Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2002.10.28;
Скачать: [xml.tar.bz2];

Вниз

Сервис грузит процессор   Найти похожие ветки 

 
Borys   (2002-08-26 11:59) [0]

Написал сервис который висит ожидает коннекта (listen) soket делал API функциями, но проблема когда запускаю любую другую сетевую приблуду даже IE она начинает кушать процессрное время загрузка до 40%-60%. Когда сервис один даже с поключенными клиентскими частями ничего не грузит.
Что м.б. помогите?


 
AlexAn   (2002-08-26 12:52) [1]

Ты бы хоть написал на каком сокете (блокирующем или нет) построен твой сервис и алгоритм подключения клиента, тогда можно что-нибудь сказать


 
Borys   (2002-08-26 16:28) [2]

вот таким образом

Saddr.sin_family:=AF_INET;
Saddr.sin_port:=htons(Sport);
Saddr.sin_addr.S_addr:=INADDR_ANY;
SSocket:=socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
...
bind(SSocket,Saddr,sizeof(TSockAddr))

listen(SSocket,MaxConect)=0


 
Digitman   (2002-08-26 16:47) [3]


> listen(SSocket,MaxConect)=0


а это чего такое ?
а где цикл ?


 
Borys   (2002-08-26 17:45) [4]

это просто опечатка, а команда listen ждет коннекта до посинения

While not(terminated) do
if listen(SSocket,MaxConect)=0 then begin
//принимаю клиента
end;


 
Digitman   (2002-08-26 18:27) [5]

>Borys


> ждет коннекта до посинения


Ну так а что ж ты хочешь , раз "до посинения" ?
Блокирующий вызов, осн.код.поток (скорее всего) - вот тебе и "грузит" твоя "приблуда" все на свете)

Или применяй асинхронный неблокирующий режим или выноси работу с гнездом в доп.код.поток. Да и в доп.потоке весьма желательно использовать неблок.режим, иначе не будет он реагировать ни на что, пока тот же упомянутый тобой listen() не вернет управление.


 
Polevi   (2002-08-26 18:29) [6]

listen ничего не ждет - ждет accept


 
Polevi   (2002-08-26 18:33) [7]

procedure TAcceptThread.Execute;
begin
...

if bind(FListenSocket, FAddr, SizeOf(FAddr))=SOCKET_ERROR then Terminate;
listen(FListenSocket, SOMAXCONN);

try
while not Terminated do
begin
Len:=sizeof(FAddr);
ClientSocket:=accept(FListenSocket, @FAddr, @Len);

...


 
Borys   (2002-08-26 18:36) [8]

да верно listen ничего не ждет, ждет accept а ожидает соединения у меня другой поток


 
Polevi   (2002-08-26 18:41) [9]

что значит ожидает соединения ? если у тебя поток ожидает соединения - в нем и надо делать listen а затем в цикле accept, как в выше приведенном коде.
какой смысл разводить listen и accept по разным потокам, непонятно..


 
Digitman   (2002-08-27 08:29) [10]

>Borys
>Polevi

Приношу извинения, "заклинило" что-то, действительно - "ждет" Accept(), а не Listen()

Borys, listen() и accept/WSAAccept() должны вызываться в одном и том же потоке. И все же настоятельно рекомендую не использовать блокирующий режим "слушающего" гнезда. Равно как и не использовать блок.режим для гнезд, возвращаемых Accept()/WSAAccept() при акцепте запроса на соединение


 
Polevi   (2002-08-27 09:33) [11]

2Digitman ©
По вашему получается что блокирующий режим вообще не надо использовать - вы не могли бы объяснить свою точку зрения ?


 
AlexAn   (2002-08-27 10:25) [12]

во-первых действительно, для прослушивания в цикле используется accept, listen в цикл включать не надо

во-вторых интересно, как работает серверный-клиентский сокет возвращаемый accept, потому, что accept всегда будет ждать соединения, а вот для серверного-клиентского сокета в блокирующем режиме неправильно написанный алгоритм может "скушать" все ресурсы процессора !

Вот примерчик эхо-сервера:

// Module Name: Server.c
//
// Description:
// This example illustrates a simple TCP server that accepts
// incoming client connections. Once a client connection is
// established, a thread is spawned to read data from the
// client and echo it back (if the echo option is not
// disabled).
//
// Compile:
// cl -o Server Server.c ws2_32.lib
//
// Command line options:
// server [-p:x] [-i:IP] [-o]
// -p:x Port number to listen on
// -i:str Interface to listen on
// -o Receive only, don"t echo the data back
//
#include <winsock2.h>

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 5150
#define DEFAULT_BUFFER 4096

int iPort = DEFAULT_PORT; // Port to listen for clients on
BOOL bInterface = FALSE, // Listen on the specified interface
bRecvOnly = FALSE; // Receive data only; don"t echo back
char szAddress[128]; // Interface to listen for clients on

//
// Function: usage
//
// Description:
// Print usage information and exit
//
void usage()
{
printf("usage: server [-p:x] [-i:IP] [-o]\n\n");
printf(" -p:x Port number to listen on\n");
printf(" -i:str Interface to listen on\n");
printf(" -o Don"t echo the data back\n\n");
ExitProcess(1);
}




 
AlexAn   (2002-08-27 10:26) [13]


//
// Function: ValidateArgs
//
// Description:
// Parse the command line arguments, and set some global flags
// to indicate what actions to perform
//
void ValidateArgs(int argc, char **argv)
{
int i;

for(i = 1; i < argc; i++)
{
if ((argv[i][0] == "-") || (argv[i][0] == "/"))
{
switch (tolower(argv[i][1]))
{
case "p":
iPort = atoi(&argv[i][3]);
break;
case "i":
bInterface = TRUE;
if (strlen(argv[i]) > 3)
strcpy(szAddress, &argv[i][3]);
break;
case "o":
bRecvOnly = TRUE;
break;
default:
usage();
break;
}
}
}
}

//
// Function: ClientThread
//
// Description:
// This function is called as a thread, and it handles a given
// client connection. The parameter passed in is the socket
// handle returned from an accept() call. This function reads
// data from the client and writes it back.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock=(SOCKET)lpParam;
char szBuff[DEFAULT_BUFFER];
int ret,
nLeft,
idx;

while(1)
{
// Perform a blocking recv() call
//
ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);
if (ret == 0) // Graceful close
break;
else if (ret == SOCKET_ERROR)
{
printf("recv() failed: %d\n", WSAGetLastError());
break;
}
szBuff[ret] = "\0";
printf("RECV: "%s"\n", szBuff);
//
// If we selected to echo the data back, do it
//
if (!bRecvOnly)
{
nLeft = ret;
idx = 0;
//
// Make sure we write all the data
//
while(nLeft > 0)
{
ret = send(sock, &szBuff[idx], nLeft, 0);
if (ret == 0)
break;
else if (ret == SOCKET_ERROR)
{
printf("send() failed: %d\n",
WSAGetLastError());
break;
}
nLeft -= ret;
idx += ret;
}
}
}
return 0;
}

//
// Function: main
//
// Description:
// Main thread of execution. Initialize Winsock, parse the
// command line arguments, create the listening socket, bind
// to the local address, and wait for client connections.
//
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET sListen,
sClient;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local,
client;

ValidateArgs(argc, argv);
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
//
if (bInterface)
{
local.sin_addr.s_addr = inet_addr(szAddress);
if (local.sin_addr.s_addr == INADDR_NONE)
usage();
}
else
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);

if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8);
//
// In a continous loop, wait for incoming clients. Once one
// is detected, create a thread and pass the handle off to it.
//
while (1)
{
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client,
&iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
break;
}
printf("Accepted client: %s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));

hThread = CreateThread(NULL, 0, ClientThread,
(LPVOID)sClient, 0, &dwThreadId);
if (hThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
break;
}
CloseHandle(hThread);
}
closesocket(sListen);

WSACleanup();
return 0;
}


 
Digitman   (2002-08-27 10:30) [14]

>Polevi

Ну почему же нельзя ? Можно.

Но вот представь себе такую ситуацию :

- гнездо создано в доп.код.потоке и инициировано для работы в блок.режиме;

- реализована логика, при которой доступ к сессии и созданному в ней гнезду допускается лишь в контексте только одного код.потока - создавшего сессию/гнездо и управляющего транспортом "своего" гнезда; работа код.потока контролируется через механизм сообщений, адресованных ему со стороны внешнего код.потока (некоего контролирующего потока - диспетчера транспортных кодовых потоков, ассоциированных с соотв.кл.соединениями/запросами)

- вызвана одна из блокирующих ф-ций гнезда, например, recv(); возврат из ф-ции - либо по отказу трансп.канала либо по готовности принятых от клиента данных;

- клиент "молчит" бесконечно долго - вызванная ф-ция recv() "висит", не возвращая управление;

- контролирующий код.поток принимает решение "отключить" клиента по таймауту ожидания кл.запроса/ответа и посылает соответствующему трансп.код.потоку сообщение типа TM_DISCONNECT_AND_TERMINATE и ждет извещения о результате исполнения данного командного сообщения (которое д.б. интерпретировано как, скажем, последовательность действий : "разорвать соединение", "уничтожить гнездо", "завершить сессию" и "завершиться самому")

- трансп.код.поток, которому адресовано это сообщение, будучи исполняющим в дан.момент ф-цию recv() ("висящую" неопределенно долго), не может ни выбрать из очереди ни обработать сообщение

- в результате такой ситуации контролирующий код.поток будет либо ждать исполнения команды управляемым им трансп.код.потоком неопределенно долго либо вынужден будет терминировать "зависший" код.поток принудительно, что крайне нежелательно допускать : это чревато минимум утечкой ресурсов, максимум - крахом процесса сервера


 
Polevi   (2002-08-27 11:05) [15]

2Digitman ©
это все правильно, но я работаю с сокетом с помощью ReadFile и WriteFile асинхронно и для получения уведомления о завершении операции использую POverlapped.hEvent или CompletionPorts..
в случае с Overlapped.hEvent событие завершения "ловится" ф-ией WaitForMultipleObjects, которая также может ожидать некого Eventa с ручным сбросом, специально предназначенного для завершения работы потоков, к примеру.. Просто интересно есть ли какие нибудь недостатки использования Read-WriteFile при работе с сокетами по сравнению с recv, send ?


 
Polevi   (2002-08-27 11:06) [16]

PS
преимущества налицо, IMHO :-)


 
Digitman   (2002-08-27 11:28) [17]

>Polevi

Overlapped-операции сами по себе подразумевают неблокирующий режим вызовов различных API-ф-ций. В т.ч. и WinsockAPI. И коль скоро ты упомянул POverlapped.hEvent , уже очевидно, что гнездо д.б. инициализировано для работы в асинхронном неблокирующем режиме (т.е. где-то по тексту вызывается WSACreateEvent с последующим WSAEventSelect). Поэтому и ф-ции ожидания типа WaitFor, MsgWaitFor, WSAWaitFor использовать должно и нужно - и это правильно и вполне логично. Overlapped-режим в случае с readfile/writefile для файлового потока, ассоциированного с хэндлом гнезда, и решает (как один из способов) как раз ту проблему синхронного блокирующего режима, что изложена мной выше.

В принципе, imho, использование непосредственных вызовов гнездовых трансп.ф-ций send/recv гораздо более гибко, нежели файловые ф-ции redfile/writefile, хотя и сложнее для программной реализации, ибо любые штатные и нештатные ситуации транспорта приходится предусматривать и обрабатывать "ручками". Не говоря уже о проблемах (при файловом вводе/выводе) в установках опций гнезда, отличающихся от используемых по-умолчанию при его создании.


 
Borys   (2002-08-27 12:14) [18]

Вообще помогло когда я вынес listen за цикл.
А вообще я перед recv анализирую есть ли данные и поэтому блокировки не происходит ни когда.
while (ioctlsocket(Socket,FIONREAD,j)=0) and (i<repeat1) do begin
if j<>0 then break;
sleep(10);
inc(i);
end;
if (i>=repeat1) and (j=0) then begin
//завершаю клиентское соединение по таймауту
end;


Ну а по accept он уходит в ожидание до бесконечности (или можно сделать чтобы он не ждал бесконечность).

Осталась одна проблема когда запускаю клиентскую часть на соседнем компе никто ничего не грузит.
А когда на том же где сервер (127.0.0.1), то сервер начинает грузить.


 
Polevi   (2002-08-27 12:34) [19]

гм
я не использую WSACreateEvent и WSAEventSelect и у меня все работает :-)

type
TClient=class
private
FSocket:TSocket;
FEvent:THandle;
ov:POVERLAPPED;
...

constructor TClient.Create;
begin
...
FEvent:=CreateEvent(nil,true,false,nil);
ov.hEvent:=FEvent;
...

procedure TAcceptThread.Execute;
begin
...
try
while not Terminated do
begin
ClientSocket:=accept(FListenSocket, @FAddr, @Len);
Client.FSocket:=ClientSocket
...


procedure TClientThread.Execute;
begin
...
while not Terminated do
begin
Rst:=WaitForMultipleObjects(2,@FEventArray,false,INFINITE);
if (Rst=WAIT_TIMEOUT) or (Rst=WAIT_FAILED) then Terminate
else
begin
FClient:=FClientArray[Rst-WAIT_OBJECT_0];
if FClient.ov.InternalHigh=0 then Terminate else FClient.Read(FClient.ov.InternalHigh);
end;
end;

вот так..

и что подрузамевается под
>любые штатные и нештатные ситуации транспорта приходится
>предусматривать и обрабатывать "ручками".

???






 
Digitman   (2002-08-27 12:40) [20]

а теперь у тебя ioctlsocket() в цикле "грузит" - это же безусловный блокирующий вызов ! Он же у тебя крутится в осн.потоек, как я понял ?

И sleep(10) практически не спасает - слишком мала задержка. А больше ее делать нельзя - или риск "проморгать" момент доступности данных или задержка реакции на кл.запрос


 
Borys   (2002-08-27 12:46) [21]

А почему тогда с соседнего компа (т.е. клиенты на других машинах) не грузит а грузит только по 127.0.0.1.
Он у меня крутиться в процессе обслуживающего клиента.


 
Digitman   (2002-08-27 13:03) [22]

Что вообще значит "грузит" ? Поясни.


 
Borys   (2002-08-27 13:14) [23]

Когда кл. коннектится с соседнего компа загрузка на сервере 1% когда с кл коннектится с того же где и стоит сервер то загрузка 17-20%


 
Digitman   (2002-08-27 13:22) [24]

Речь-то о серверном процессе до сих пор шла !
Чего у тебя там в кл.процессе творится - это иной вопрос, надо смотреть отдельно.
С чего ты взял, что те самые 17-20% - это "нагрузка" только серверного процесса в случае, когда и клиентский и серверный процессы стартуют на одной машине ? Почему же ты выкинул из рассмотрения клиентскийц процесс в плане нагрузки ?


 
Polevi   (2002-08-27 13:23) [25]

клиентской части тоже нужны ресурсы


 
Borys   (2002-08-27 13:36) [26]

Ну Win показывает что сервер грузит (в списке процессов). Или это ничего не знгачит. А клиентская часть сама по себе свои проценты кушает.


 
Digitman   (2002-08-27 13:58) [27]

>Borys

Убирай все блокирующие вызовы. Работай в асинхронном неблокирующем режиме - и никаких проблем не будет



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2002.10.28;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.008 c
3-92366
sie_vedenie
2002-10-04 19:36
2002.10.28
Работа на sql с dbase3


3-92337
ruslan_as
2002-10-04 16:27
2002.10.28
Как заставить InterBase в SQL не чувствовать регистр букв


1-92501
Sova
2002-10-15 11:19
2002.10.28
Разрешения экрана и размер фонтов.


14-92661
vopros
2002-10-07 11:00
2002.10.28
Зацените сайт.


7-92751
CkuB
2002-08-19 00:07
2002.10.28
разрешение принтера





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский