Сейчас на форуме: (+5 невидимых)

 eXeL@B —› Программирование —› Определение разрыва соединения в серверной программе.
Посл.ответ Сообщение

Ранг: 39.6 (посетитель)
Активность: 0.020
Статус: Участник

Создано: 08 октября 2007 14:03 · Поправил: NetSpider
· Личное сообщение · #1

Ситуация такая. Пишу многопоточный сервер. Возникла потребность отследить ненормальное завершение работы соединения. Т.е., например, клиента во время работы с сервером сняли из диспетчера задач и он не закрыл соединение. В результате на сервере висит в работе поток и на коннекте Close Wait. Какой функцией можно это отследить? getsockopt?



Ранг: 39.6 (посетитель)
Активность: 0.020
Статус: Участник

Создано: 08 октября 2007 15:49 · Поправил: NetSpider
· Личное сообщение · #2

Вот кусок кода сервера, чтобы понятнее было что мне нужно сделать.

int WINAPI RemoteCmd(SOCKET sock, char *buffer, int bufsize)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
HANDLE cstdin, wstdin, rstdout, cstdout;
DWORD fexit, N, total;

//Отправка сообщения о типе режима
send(sock,RemoteCmdMode,sizeof(RemoteCmdMode),0);

memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));

sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE; //allow inheritable handles

if (!CreatePipe(&cstdin, &wstdin, &sa, 0)) return 0; //create stdin pipe
if (!CreatePipe(&rstdout, &cstdout, &sa, 0)) return 0; //create stdout pipe

GetStartupInfo(&si); //set startupinfo for the spawned process

si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = cstdout;
si.hStdError = cstdout; //set the new handles for the child process
si.hStdInput = cstdin;

//spawn the child process
if (!CreateProcess(0, "cmd.exe", 0, 0, TRUE, CREATE_NEW_CONSOLE, 0,0,&si,&pi)) return -1;

while(GetExitCodeProcess(pi.hProcess,&fexit) &&
(fexit == STILL_ACTIVE)){

if (!CheckConnect(sock)) MessageBox(0, "Соединение потеряно", "INFO", 0);
//check to see if there is any data to read from stdout
if (PeekNamedPipe(rstdout, buffer, 1, &N, &total, 0) && N){
for (DWORD a = 0; a < total; a += bufsize){
ReadFile(rstdout, buffer, bufsize, &N, 0);
send(sock, buffer, N, 0);
};
}
if (!ioctlsocket(sock, FIONREAD , &N) && N){
recv(sock, buffer, 1, 0);
if (*buffer == '\x0A') WriteFile(wstdin, "\x0D", 1, &N, 0);
WriteFile(wstdin, buffer, 1, &N, 0);
}
Sleep(1);
}
CloseHandle(cstdin);
CloseHandle(wstdin);
CloseHandle(rstdout);
CloseHandle(cstdout);
return 0;
}


Надо реализовать функцию CheckConnect(sock)



Ранг: 39.6 (посетитель)
Активность: 0.020
Статус: Участник

Создано: 08 октября 2007 16:37
· Личное сообщение · #3

Нарыл в инете, что есть способ KEEP ALIVE. К сожалению не подходит. Eсть еще функция select...
Эта фун-я может вернуть информацию о состоянии сокета. Попытался сделать так.

int WINAPI CheckConnect(SOCKET sock)
{
fd_set readfds;
DWORD nbytes;

memset(&readfds, 0, sizeof(readfds));
select(1,&readfds,NULL, NULL, NULL);
if (FD_ISSET(sock,&readfds)) {
ioctlsocket(sock,FIONREAD,&nbytes);
if (!nbytes) return 0;
};
return 1;
}

Но select вернул ошибку, что входные данные неверные.




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 08 октября 2007 20:02 · Поправил: s0larian
· Личное сообщение · #4

NetSpider, стой, тут два варианта:
а) клиент успел послать RST и тогда ты получишь на сервере ошибку при чтении. То есть, либо blocking recv() либо select() тебе вернёт ошибку. Тут просто closesocket() вызываешь и привет.

б) клиент не успел послать RST. Тогда тебе надо реализовать timout для каждого соединения. Это просто таймер - типа новая команда или ответ каждые 30 секунд, или вызываешь closesocket(). Кста именно это делает keep alive. То есть, IIRC, при включённо keep alive этот случай превращается в а)

Кста, отдельный поток для каждого клиента - неэкономно. Плохо будет винде при нескольких сотнях клиентов...



Ранг: 39.6 (посетитель)
Активность: 0.020
Статус: Участник

Создано: 09 октября 2007 09:52 · Поправил: NetSpider
· Личное сообщение · #5

s0larian, Спасибо. Буду пробовать все таки через KEEP ALIVE.
По поводу отдельного потока для каждого клиента - думаю нестрашно. Программа должна получиться типа RAdmin. Клиент к серверу скорее всего будет подключаться один и подключений будет немного. Просто одновременно он сможет использовать допутим удаленный shell, управление файлами, работа с процессами и т.п. В плане сделать клиент в виде плагина wfx для тотал коммандера.


 eXeL@B —› Программирование —› Определение разрыва соединения в серверной программе.
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати