楼上用的是偷窥数据的方法,我用的是keepalive的方法,缺点是不支持win98。 下面的例子是tcp/ip阻塞的socket.能够监测到电脑reset或拔掉网线后socket中断的情况!//server /*********************************************** command format: TCPTest port, for example: TCPTest 5678 ************************************************/ // 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 calls // a socket api function to detect whether the client is online. // DWORD WINAPI ClientThread(LPVOID lpParam) { SOCKET sock = (SOCKET)lpParam; char szBuff[DEFAULT_BUFFER];
while(1) { //call a socket function to detect whether the client is online. int ret = recv(sock, szBuff, DEFAULT_BUFFER, 0); //check the returned value if(WSAGetLastError() == WSAENETRESET)//The connection has been broken //due to the keep-alive activity //detecting a failure while the //operation was in progress { printf("client WSAENETRESET!, sock = %d\n", sock); shutdown(sock, SD_BOTH); closesocket(sock); break; } if(WSAGetLastError() == WSAENOTCONN)//The socket is not connected. { printf("client WSAENOTCONN!, sock = %d\n", sock); shutdown(sock, SD_BOTH); closesocket(sock); break; } if(WSAGetLastError() == WSAECONNRESET)//The virtual circuit was reset by the //remote side executing a hard or abortive //close. The application should close the //socket as it is no longer usable. On a //UPD-datagram socket this error would //indicate that a previous send operation //resulted in an ICMP "Port Unreachable" //message. { printf("client WSAECONNRESET!, sock = %d\n", sock); shutdown(sock, SD_BOTH); closesocket(sock); break; } else if(ret == SOCKET_ERROR) { continue; } //Sleep(10); } return 0; }int main(int argc, char* argv[]) { ///////////////////////////////////////////// int nPort; if(argc == 1) nPort = DEFAULT_PORT; else nPort = atoi(argv[1]); ///////////////////////////////////////// WSADATA wsd; SOCKET sListen, sClient; int iAddrSize; HANDLE hThread; DWORD dwThreadId; struct sockaddr_in local, client; if(WSAStartup(MAKEWORD(2,2), &wsd) != 0) { printf("Failed to load Winsock!\n"); return 1; } // Create a listen socket sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sListen == SOCKET_ERROR) { printf("socket() failed: %d\n", WSAGetLastError()); WSACleanup(); return 1; } // Select the local interface and bind to it local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_family = AF_INET; local.sin_port = htons(nPort); if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR) { printf("bind() failed: %d\n", WSAGetLastError()); closesocket(sListen);
在当IsConnectionLost返回True时,说明当前的SOCKET连接已经失效了。
m_hSocket是当前SOCKET连接的句柄BOOL CCrobSocket::IsConnectionLost()
{
BOOL bConnLost = FALSE;
int nRet = 0;
BOOL bOK = TRUE;
if (m_hSocket == INVALID_SOCKET)
return TRUE; struct timeval timeout = { 0, 0 };
fd_set rset;
FD_ZERO(&rset);
FD_SET(m_hSocket, &rset);
nRet = ::select(0, &rset, NULL, NULL, &timeout);
bOK = (nRet > 0);
if(bOK)
{
bOK = FD_ISSET(m_hSocket, &rset);
}
if(bOK)
{
char szBuffer[1] = "";
nRet = ::recv(m_hSocket, szBuffer, 1, MSG_PEEK);
bOK = (nRet > 0);
if(!bOK)
{
int err = ::WSAGetLastError();
bConnLost = (( err == WSAENETRESET) || (err == WSAECONNABORTED) || (err == WSAECONNRESET) || (err == WSAEINVAL) || (nRet == 0));
}
}
return(bConnLost);
}
下面的例子是tcp/ip阻塞的socket.能够监测到电脑reset或拔掉网线后socket中断的情况!//server
/***********************************************
command format: TCPTest port,
for example:
TCPTest 5678
************************************************/
// 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 calls
// a socket api function to detect whether the client is online.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock = (SOCKET)lpParam;
char szBuff[DEFAULT_BUFFER];
while(1)
{
//call a socket function to detect whether the client is online.
int ret = recv(sock, szBuff, DEFAULT_BUFFER, 0); //check the returned value
if(WSAGetLastError() == WSAENETRESET)//The connection has been broken
//due to the keep-alive activity
//detecting a failure while the
//operation was in progress
{
printf("client WSAENETRESET!, sock = %d\n", sock);
shutdown(sock, SD_BOTH);
closesocket(sock);
break;
}
if(WSAGetLastError() == WSAENOTCONN)//The socket is not connected.
{
printf("client WSAENOTCONN!, sock = %d\n", sock);
shutdown(sock, SD_BOTH);
closesocket(sock);
break;
}
if(WSAGetLastError() == WSAECONNRESET)//The virtual circuit was reset by the
//remote side executing a hard or abortive
//close. The application should close the
//socket as it is no longer usable. On a
//UPD-datagram socket this error would
//indicate that a previous send operation
//resulted in an ICMP "Port Unreachable"
//message.
{
printf("client WSAECONNRESET!, sock = %d\n", sock);
shutdown(sock, SD_BOTH);
closesocket(sock);
break;
}
else if(ret == SOCKET_ERROR)
{
continue;
}
//Sleep(10);
}
return 0;
}int main(int argc, char* argv[])
{
///////////////////////////////////////////// int nPort;
if(argc == 1)
nPort = DEFAULT_PORT;
else
nPort = atoi(argv[1]); ///////////////////////////////////////// WSADATA wsd;
SOCKET sListen,
sClient;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local,
client; if(WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
// Create a listen socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
WSACleanup();
return 1;
} // Select the local interface and bind to it
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(nPort); if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
closesocket(sListen);
WSACleanup();
return 1;
} //set KeepAlive
struct tcp_keepalive kp;
kp.onoff = 1;
kp.keepalivetime = 100;
kp.keepaliveinterval = 100; DWORD cbRet;
if( 0 != WSAIoctl(
sListen,
SIO_KEEPALIVE_VALS,
&kp,
sizeof(kp),
NULL,
0,
&cbRet,
NULL,
NULL
))
{
closesocket(sListen);
WSACleanup();
return 1;
} listen(sListen, 8);
printf("listening...\n");
// In a continous loop, wait for incoming clients. Once one
// is detected, create a thread and pass the handle off to it.
iAddrSize = sizeof(client);
while(1)
{
sClient = accept(sListen, (struct sockaddr *)&client,
&iAddrSize); if (sClient == INVALID_SOCKET)
{
//printf("accept() failed: %d\n", WSAGetLastError());
continue;
}
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());
closesocket(sClient);
continue;
}
CloseHandle(hThread);
} closesocket(sListen);
WSACleanup();
return 0;
}