Форум: "Сети";
Текущий архив: 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.007 c