服务器主动关闭socket后, 客户端send函数拥塞并且socket状态为CLOSE_WAIT

服务器主动关闭socket后, 客户端send函数阻塞并且socket状态为CLOSE_WAIT
当服务器端关闭socket连接时, 若客户端接着发数据, 
根据TCP协议的规定,客户端会收到一个RST响应, 此时send调用应该会失败
在linux下测试确实如此, 但是在windows xp/7上send调用不会失败, 而是会阻塞...
这导致了客户端程序无法正常退出, 求大神解释啊...

服务器主动关闭socket后, 客户端send函数拥塞并且socket状态为CLOSE_WAIT
服务器主动关闭socket后, 客户端send函数阻塞并且socket状态为CLOSE_WAIT

测试环境: 
  服务器: win7 64
  客户端: windows xp/7(注意, 如果服务器与客户端在同一台电脑上, 则send会失败而不是阻塞)

测试代码如下: 

服务器端程序

#include "stdafx.h"
#include <Winsock2.h>  
#pragma comment(lib, "Ws2_32.lib")

BOOL ServerTest(USHORT usPort)
{
BOOL rv = FALSE;
struct sockaddr_in server_addr = {0x0};
struct sockaddr_in client_addr = {0x0};

__try{
// 创建Socket
SOCKET soc_listen = socket(AF_INET, SOCK_STREAM, 0);
if(INVALID_SOCKET == soc_listen){
wprintf(L"TCP listen socket create failed(err=0x%08x)", WSAGetLastError());
__leave;
}

// 绑定
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(usPort);
server_addr.sin_addr.S_un.S_addr = INADDR_ANY;
if(::bind(soc_listen, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){
wprintf(L"Socket bind Failed(err=0x%08x)", WSAGetLastError());
__leave;


// 监听
if(SOCKET_ERROR == ::listen(soc_listen, 5)){
wprintf(L"Socket listen Failed(err=0x%08x)", WSAGetLastError());
__leave;
}

// 服务器主循环
// 接收到客户端连接后马上关闭连接
for(;;)
{
int len = sizeof(client_addr);
SOCKET soc_client = ::accept(soc_listen, (struct sockaddr *)&client_addr, &len);
if(soc_client == INVALID_SOCKET){
wprintf(L"accept Failed(err=0x%08x)", WSAGetLastError());
continue;
}

wprintf(L"client connected! SOCKET=%d\r\n", soc_client);

closesocket(soc_client);
}
// 设置成功标志
rv = TRUE;
}
__finally{
}
return rv;
}

int _tmain(int argc, _TCHAR* argv[])
{
// 初始化
WSADATA  ws;
if(WSAStartup(MAKEWORD(2,2), &ws) != 0){
    printf("Init Windows Socket Failed %d", GetLastError());
    return -1;
}

// 服务器测试函数
ServerTest(2222);

// 清理
WSACleanup();
return 0;
}


客户端程序

#include "stdafx.h"
#include <Winsock2.h>  
#pragma comment(lib, "Ws2_32.lib")

BOOL ClientTest(const char *server_ip, USHORT port)
{
BOOL rv = FALSE;
SOCKET soc = INVALID_SOCKET;
ULONG ipaddr = inet_addr(server_ip);
struct sockaddr_in server_addr;
int ret = 0;
#define BUFFER_SIZE 32
char buf[BUFFER_SIZE] = {0,};

// 创建Socket
soc = socket(AF_INET, SOCK_STREAM, 0);
if(soc == INVALID_SOCKET){
wprintf(L"socket failed(err=%d).", WSAGetLastError());
goto ERR;
}

// 设置连接信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.S_un.S_addr = ipaddr;

// 连接服务器
ret = connect(soc, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(ret == SOCKET_ERROR){
wprintf(L"connect failed(err=%d).", WSAGetLastError());
goto ERR;
}

// 向服务器发送数据
while(1)
{
// 当服务器端关闭socket连接时, 若客户端接着发数据, 
// 根据TCP协议的规定,客户端会收到一个RST响应, 此时send调用会失败
// 在linux下测试确实如此, 但是在windows xp/7上send调用不会失败, 而是会阻塞...
ret = send(soc, (const char*)buf, sizeof(buf), 0);
if(ret == SOCKET_ERROR){
wprintf(L"send failed(err=%d).", WSAGetLastError());
goto ERR;
}

static int count = 0;
printf("[%d] send success ret=%d\r\n", ++count, ret);
}

// 设置成功标志
rv = TRUE;

ERR:
// 关闭socket
if(soc != INVALID_SOCKET){
closesocket(soc);
}
return rv;
}

int main(int argc, char* argv[])
{
if(argc != 2){
printf("client.exe server_ipaddr\r\n");
return 1;
}

// 初始化
WSADATA  ws;
if(WSAStartup(MAKEWORD(2,2), &ws) != 0){
printf("Init Windows Socket Failed %d", GetLastError());
return -1;
}

// 客户端测试函数
ClientTest(argv[1], 2222);

// 清理
WSACleanup();
return 0;
}

------解决思路----------------------
设置socket非阻塞模式呢
------解决思路----------------------
抓包看下服务器关闭的时候客户端收到FIN包了吗?
------解决思路----------------------
设置合适的超时时间
------解决思路----------------------
引用:
设置合适的超时时间