网上某论坛有这样一个问题:当recv()函数的返回值为0时,能不能在接收端不关闭套接字,以便这条建立好的C/S通信下次可以直接使用?
我对这个问题的回答是:不能。
原因是:此时即使接收端不关闭套接字,发送端也已经关闭相应的套接字,这条连接需要从accept()/connect()两个函数这里重新建立。
测试代码如下:
#include "stdafx.h"
#include
#include
#pragma comment(lib,"ws2_32")
const int m_listen_port=9923;
#define buff_size 1024
int main(int argc, char* argv[])
{
int ret_common=0;
int ret_error=0;
WSAData wsadata;
WORD m_version;
m_version=MAKEWORD(2,2);
WSAStartup(m_version,&wsadata);
SOCKET
m_server_sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (m_server_sock==INVALID_SOCKET)
{
ret_error=WSAGetLastError();
printf("error for
socket() and caputre error code: %d\n",ret_error);
return 0;
}
SOCKADDR_IN m_sock_addr;
memset(&m_sock_addr,0,sizeof(m_sock_addr));
m_sock_addr.sin_family=AF_INET;
m_sock_addr.sin_addr.S_un.S_addr=INADDR_ANY;
m_sock_addr.sin_port=htons(m_listen_port);
ret_common=bind(m_server_sock,(SOCKADDR*)&m_sock_addr,sizeof(m_sock_addr));
if (ret_common==SOCKET_ERROR)
{
ret_error=WSAGetLastError();
printf("error for
bind() and caputre error code: %d\n",ret_error);
return 0;
}
listen(m_server_sock,SOMAXCONN);
fd_set fd_socket;
FD_ZERO(&fd_socket);
FD_SET(m_server_sock,&fd_socket);
while (1)
{
fd_set
fd_read=fd_socket;
ret_common=select(0,&fd_read,NULL,NULL,NULL);
if
(ret_common>0)
{
for
(unsigned int i=0;i
{
BOOL
m_boolen_ret=FD_ISSET(fd_socket.fd_array[i],&fd_read);
if
(m_boolen_ret)
{
if
(fd_socket.fd_array[i]==m_server_sock)
{
SOCKADDR_IN
m_client_addr;
memset(&m_client_addr,0,sizeof(m_client_addr));
int
m_client_addr_len=sizeof(m_client_addr);
SOCKET
m_client_sock=accept(m_server_sock,(SOCKADDR*)&m_client_addr,&m_client_addr_len);
printf("accpet
a connection from socket %d\n",m_client_sock);
FD_SET(m_client_sock,&fd_socket);
}
else
{
char
m_recv_buff[buff_size];
memset(m_recv_buff,0,buff_size);
ret_common=recv(fd_socket.fd_array[i],m_recv_buff,sizeof(m_recv_buff),0);
if
(ret_common>0)// 接收数据包正常,数据包中的数据大于0个字节;
{
printf("receive
data \"%s\" from socket
%d\n",m_recv_buff,fd_socket.fd_array[i]);
continue;
}
else
if
(ret_common==0)// 传输数据包操作完成,连接断开(gracefully);
{
ret_error=WSAGetLastError();
printf("there
is a connection is gracefully closed and capture error code:
%d,socket:%d\n",
ret_error,fd_socket.fd_array[i]);
closesocket(fd_socket.fd_array[i]);
FD_CLR(fd_socket.fd_array[i],&fd_socket); continue;
}
else//
传输数据包出错;
{
ret_error=WSAGetLastError();
closesocket(fd_socket.fd_array[i]);
FD_CLR(fd_socket.fd_array[i],&fd_socket);
if
(ret_error==10054)// 连接被强制断开;
{
printf("client
closed the connection by force, test ret_common:
%d,socket:%d\n",
ret_error,ret_common,fd_socket.fd_array[i]);
}
else//
输出其它错误;
{
printf("error
for recv(), capture error code: %d, test ret_common:
%d,socket:%d\n",
ret_error,ret_common,fd_socket.fd_array[i]);
} continue;
}
}
}
} }
else
{
ret_error=WSAGetLastError();
printf("error
for select() and capture error code: %d\n",ret_error);
break;
}
}
closesocket(m_server_sock);
WSACleanup();
return 0;
}
这段发送端代码不是我写的,看起来可能比较乱,请见谅:
for (int i=0;i<10;i++)
{
strncpy(m_send_buff,"data",sizeof("data"));
char a[20];
memset(a,0,20);
itoa(i+1,a,10);
strncat(m_send_buff,a,20);
ret_common=send(s,m_send_buff,sizeof(m_send_buff),0);
if
(ret_common==SOCKET_ERROR)
{
ret_error=WSAGetLastError();
printf("error
for send() and capture error code: %d\n",ret_error);
break;
}
else
{
printf("send
data: %s\n",m_send_buff);
}
Sleep(1000);
}
Sleep(6000);
// 关闭套节字
::closesocket(s);
Sleep(10000);
printf("ret\n");
return 0;
当包含这段代码的程序发送数据包到包含上一段代码的程序时,发送数据完毕,在等6秒钟后发送数据的套接字才关闭,而接收端也是等6秒钟才输出客户端关闭(gracefully)关闭的信息,再等10描述,发送数据的程序才推出。
总结一下:
(1)当接收端被强行关闭时,ret_common为-1,WSAGetLastError()返回值(即ret_error)为10054(0x2746);
(2)当数据传输执行closesocket()(closesocket()参数为发送数据的套接字)之后,接收端的返回值(即ret_common)为0。
(3)在传输过程中,如果接收端被强行关闭,那么发送端的send()函数的返回值(即ret_common)为-1,WSAGetLastError()的返回值(即ret_error)为10054(0x2746)。
需要注意一点:
WSAGetLastError()的返回值:10054,与GetLastError()的返回值:0x2746,这两个错误返回值是相等的(不同的是针对WSAGetLastError()函数和GetLastError()函数的返回值类型不同(WSAGetLastError()返回int类型操作数;GetLastError()返回DWORD类型操作数))。