阻塞模式下当完成数据的发送后,关闭套节字不能用closesocket一关了之,这样会造成数据的丢失。
正确的做法是调用shutdown,发送SD_SEND参数进行"半关闭", 这样做TCP会在数据发送完成后发送FIN通知对方,然后循环用recv接收直到对方关闭套接字发送过来FIN。参考代码如下:
void CloseSocket(SOCKET hSocket)


{
if(hSocket == INVALID_SOCKET)
return;

// 半关闭
if(shutdown(hSocket, SD_SEND) != SOCKET_ERROR)

{
char buf[1024];
int nRecv = 0;
do

{
nRecv = recv(m_hSocket, buf, 1024, 0);
} while (!(nRecv == 0 || nRecv == SOCKET_ERROR));
}
// 关闭
closesocket(hSocket);
}
对于WINDOWS,可以配合WSAAsyncSelect选择FD_CLOSE事件,参考代码:
void CloseSocket(SOCKET hSocket)


{
if(hSocket == INVALID_SOCKET)
return;
WSAEVENT hEvent = WSA_INVALID_EVENT;
for(;;)

{
hEvent = WSACreateEvent();
if(hEvent == WSA_INVALID_EVENT)
break;

if(WSAEventSelect(hSocket, hEvent, FD_CLOSE) != 0)
break;

if(shutdown(hSocket, SD_SEND) != 0)
break;

if(WaitForSingleObject(hEvent, 200) != WAIT_OBJECT_0)
break;

char buf[1024];
int nRecv = 0;
do

{
nRecv = recv(hSocket, buf, 1024, 0);
} while (!(nRecv == 0 || nRecv == SOCKET_ERROR));

break;
}

if (hEvent != WSA_INVALID_EVENT)

{
WSACloseEvent(hEvent);
hEvent = WSA_INVALID_EVENT;
}
closesocket(hSocket);
}
关于半关闭的描述请参考《TCP/IP详解 卷1:协议》
参考链接
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/shutdown_2.asp
http://tangentsoft.net/wskfaq/examples/basics/ws-util.cpp
http://www.flipcode.com/articles/network_part02.shtml
http://www.codeguru.com/forum/archive/index.php/t-288238.html
posted on 2005-06-25 13:48 王骏的BLOG 阅读(2170)
评论(8) 编辑 收藏