Почему-то поток при дисконнекте сокета не закрывается, хотя должен. Подскажите в чем собака. Код (Text): ;--- process client ClientThreadProc proc ClientSock: SOCKET LOCAL buf[1024]: BYTE LOCAL BufSz: DWORD LOCAL ff: BOOL mov eax, TRUE mov ff, eax invoke setsockopt, ClientSock, SOL_SOCKET, SO_KEEPALIVE, addr ff, sizeof BOOL invoke ReceiveBuffer, ClientSock, addr buf, sizeof Password invoke lstrcmp, addr buf, addr Password .IF eax != 0 invoke DestroySocket, ClientSock ret .ENDIF invoke SendBuffer, ClientSock, addr helo, sizeof helo .WHILE (TRUE) invoke ReceiveBuffer, ClientSock, addr BufSz, -1 invoke WSAGetLastError .BREAK .IF eax != 0 mov eax, BufSz .IF (eax>0) invoke ReceiveBuffer, ClientSock, addr buf, BufSz invoke WSAGetLastError .BREAK .IF eax != 0 invoke Parse, ClientSock, addr buf, BufSz .ENDIF invoke Sleep, 60 .ENDW ret ClientThreadProc endp ;--- receives buffer from socket ReceiveBuffer proc rSock: DWORD, BufAddr: DWORD, BufSize:DWORD LOCAL Result: DWORD .IF (BufSize == -1) invoke ioctlsocket, rSock, FIONREAD, BufAddr mov Result, eax .ELSE invoke recv, rSock, BufAddr, BufSize, 0 mov Result, eax .ENDIF mov eax, Result ret ReceiveBuffer endp ;--- sends buffer to socket SendBuffer proc wSock: DWORD, BufAddr: DWORD, BufSize: DWORD invoke send, wSock, BufAddr, BufSize, 0 ret SendBuffer endp
Есть предположение. Правда, пока проверить по тех. причинам не могу. 1. Сокет со стороны отправителя закрылся. 2. invoke ReceiveBuffer, ClientSock, addr BufSz, -1 приводит к invoke ioctlsocket, rSock, FIONREAD, BufAddr Как реагирует ioctlsocket в данной ситуации? MSDN внятно про такую ситуацию ничего не говорит. Из списка ошибок самая подходящая - WSAENETDOWN. Но, имхо, ioctlsocket() никак не отслеживает такую ситуацию и просто записыват в BufSz ноль без какой-либо ошибки, что, вобщем-то, логично. 3. .IF (eax>0) не проходит, так как eax = 0. В результате имеем бесконечный .WHILE(TRUE).
Так оно и происходит. Я проверил Но дело в том что ошибки никакой нет, как вы правильно упомянули. При этом: я же делаю Код (Text): invoke setsockopt, ClientSock, SOL_SOCKET, SO_KEEPALIVE, addr ff, sizeof BOOL т.е. по MSDn при отпадении сокета при любой сокетной операции (хотя бы select) должна возвратиться ошибка. Может, я неправильно применяю setsockopt?
Наверное, надо поприменять select? А тогда, макросов FD_SET и FD_ZERO для масм ни у кого не завалялось?
Из MSDN про SO_KEEPALIVE: Однако ioctlsocket() такие ошибки не возвращает. Так что здесь SO_KEEPALIVE бесполезна. Вот тебе из linux kernel пример нужных макросов, может, поможет. Код (Text): #define __NFDBITS (8 * sizeof(unsigned long)) #define __FD_SETSIZE 1024 #define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) typedef struct { unsigned long fds_bits [__FDSET_LONGS]; } __kernel_fd_set; #define __FD_SET(fd, fdsetp) \ __asm__ __volatile__("btsl %1,%0": \ "+m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #define __FD_CLR(fd, fdsetp) \ __asm__ __volatile__("btrl %1,%0": \ "+m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #define __FD_ISSET(fd, fdsetp) (__extension__ ({ \ unsigned char __result; \ __asm__ __volatile__("btl %1,%2 ; setb %0" \ :"=q" (__result) :"r" ((int) (fd)), \ "m" (*(__kernel_fd_set *) (fdsetp))); \ __result; })) #define __FD_ZERO(fdsetp) \ do { \ int __d0, __d1; \ __asm__ __volatile__("cld ; rep ; stosl" \ :"=m" (*(__kernel_fd_set *) (fdsetp)), \ "=&c" (__d0), "=&D" (__d1) \ :"a" (0), "1" (__FDSET_LONGS), \ "2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \ } while (0)