Сейчас на форуме: (+5 невидимых) |
![]() |
eXeL@B —› Программирование —› Определение разрыва соединения в серверной программе. |
Посл.ответ | Сообщение |
|
Создано: 08 октября 2007 14:03 · Поправил: NetSpider · Личное сообщение · #1 Ситуация такая. Пишу многопоточный сервер. Возникла потребность отследить ненормальное завершение работы соединения. Т.е., например, клиента во время работы с сервером сняли из диспетчера задач и он не закрыл соединение. В результате на сервере висит в работе поток и на коннекте Close Wait. Какой функцией можно это отследить? getsockopt? ![]() |
|
Создано: 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) ![]() |
|
Создано: 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 вернул ошибку, что входные данные неверные. ![]() |
|
Создано: 08 октября 2007 20:02 · Поправил: s0larian · Личное сообщение · #4 NetSpider, стой, тут два варианта: а) клиент успел послать RST и тогда ты получишь на сервере ошибку при чтении. То есть, либо blocking recv() либо select() тебе вернёт ошибку. Тут просто closesocket() вызываешь и привет. б) клиент не успел послать RST. Тогда тебе надо реализовать timout для каждого соединения. Это просто таймер - типа новая команда или ответ каждые 30 секунд, или вызываешь closesocket(). Кста именно это делает keep alive. То есть, IIRC, при включённо keep alive этот случай превращается в а) Кста, отдельный поток для каждого клиента - неэкономно. Плохо будет винде при нескольких сотнях клиентов... ![]() |
|
Создано: 09 октября 2007 09:52 · Поправил: NetSpider · Личное сообщение · #5 s0larian, Спасибо. Буду пробовать все таки через KEEP ALIVE. По поводу отдельного потока для каждого клиента - думаю нестрашно. Программа должна получиться типа RAdmin. Клиент к серверу скорее всего будет подключаться один и подключений будет немного. Просто одновременно он сможет использовать допутим удаленный shell, управление файлами, работа с процессами и т.п. В плане сделать клиент в виде плагина wfx для тотал коммандера. ![]() |
![]() |
eXeL@B —› Программирование —› Определение разрыва соединения в серверной программе. |