vc socket中,有什么办法让recv返回0

一个阻塞的tcp/ip文件传输程序,当我发送端read()为0时退出发送函数模块,send()函数也正常返回0了,但是接收端一定要等到发送端的closesocket()函数运行完之后recv()函数才返回0,否则就一直卡在recv()那里。求用什么办法可以在不关闭接收端socket的情况下recv正常返回0好让我的程序正常退出?
我做一个多文件的网络传输,用阻塞式的TCP/IP套接字,请问怎么用select()函数判断每次发完一个文件再发另外一个?现在的问题很令人痛苦,接收端每次都不能正常返回,要不然就是recv()卡住,要不然就是send那边把其他文件的字节也传到recv端第一个文件里面。。
最新回答
独白

2024-11-05 18:05:59

你可以用异步的IO模式,比如select模式,overlappped模式,事件模式,甚至IOCP。这样就不会存在recv被卡住的问题了,性能也极大的提高。
同步的recv返回0,表示连接正常关闭, 你想让recv返回0却保持连接这是很难的。
危險人物

2024-11-05 17:41:01

首先可以将RECV函数设置为非阻塞模式。这个就不多说了。

对于另一个问题,发送端每次发送的字节数要和接收端每次接收的内容大小一致。比如接收端每次收4K,发送端也必须是每次发4K,如果发送的内容实际小于4K,就用空字符补。
失意的片刻

2024-11-05 17:26:42

CLIENT和SERVER都先定义包头,先发包头,包头包含了传输的文件大小和每次发送的拆解文件大小,然后发送拆解包,每个个拆解包都校验一次大小,最后再重新校验一次,使用另一个职守线程关闭该SOCKET,如果是多线程还要判断先进和后进的问题。
多文件的网络传输最好别用阻塞模式,太笨重了,IOCP多好啊。
沉鱼落雁

2024-11-05 00:14:07

用select测试.
select功能很强, 但用起来有点复杂, 很多人说它不好用, 其实是不会用, 希望你别说它不好用.
======================================================
不论是不是Blocking模式, select都可以用来检测:
1)连接是否成功;
2)是不是可以发送;
3)是不是可以接收;
4)对方是否断开连接

=====================================================
"send那边把其他文件的字节也传到recv端第一个文件里"
你的程序设计的问题, 和socket怎么用无关.
青衫

2024-11-05 11:00:09

//连接超时
//--------------------------------------------------------------------------
//设置为非阻塞方式连接
unsigned long ul = 1;
int ret = ioctlsocket(m_sSocket, FIONBIO, (unsigned long*)&ul);
if(ret == SOCKET_ERROR)
{
err = WSAGetLastError();
closesocket(m_sSocket);
m_sSocket = NULL;
return FALSE;
}

struct timeval timeout ; // 超时结构
fd_set r;

FD_ZERO(&r);
FD_SET(m_sSocket, &r);
timeout.tv_sec = iTimeout; // 连接超时设置
timeout.tv_usec =0;

connect(m_sSocket,(LPSOCKADDR)&server,sizeof(SOCKADDR));
ret = select(0, 0, &r, 0, &timeout);
if ( ret <= 0 )
{
err = WSAGetLastError();
closesocket(m_sSocket);
m_sSocket = NULL;
return FALSE;
}

//设回阻塞模式
ul = 0 ;
ret = ioctlsocket(m_sSocket, FIONBIO, (unsigned long*)&ul);
//--------------------------------------------------------------------------

//接收超时
//-------------------------------------------
//接收超时设置
struct timeval outtime ; // 超时结构

FD_SET fdr = {1, m_sSocket};
outtime.tv_sec = timeout;
outtime.tv_usec =0;
int nSelectRet;
//------------------------------------------------------------
//网络只认单字节串,而EVC里多字节;发送的UNICODE串转换成单字节串
UINT nLen = len * 2;
char *pByte = new char[nLen+1];
memset(pByte, 0, nLen+1);
WideCharToMultiByte(CP_ACP, NULL, buf, wcslen(buf),pByte, nLen, NULL, NULL);
int nRet;

nSelectRet=::select(0, &fdr, NULL, NULL, &outtime); //检查可读状态
if(SOCKET_ERROR==nSelectRet)
{
err = WSAGetLastError();
closesocket(m_sSocket);
m_sSocket = NULL;
return -1;
}
if(nSelectRet==0) //超时发生,无可读数据
{
AfxMessageBox(L"接收超时");
err = WSAGetLastError();
closesocket(m_sSocket);
m_sSocket = NULL;
return -1;
}
else
{
//接收数据
nRet = recv(m_sSocket, pByte, nLen, 0);
if(nRet == SOCKET_ERROR)
{
err = WSAGetLastError();
}
}

//-------------------------------------------

MultiByteToWideChar(CP_ACP, NULL, pByte, nLen, buf, len);
delete [] pByte;
pByte = NULL;

//---------------------------------------------------------------------

超时,也是 返回: SOCKET_ERROR
用WSAGetLastError() 获取 id 再分析,程序如下:

memset(buff,0x0,buff_size);
if (recv(sock,buff,sizeof(buff),0) == SOCKET_ERROR){
id = WSAGetLastError();
switch (id)
{
case WSANOTINITIALISED: printf("not initialized\n"); break;
case WSASYSNOTREADY: printf("sub sys not ready\n"); break;
case WSAHOST_NOT_FOUND: printf("name server not found\n"); break;
case WSATRY_AGAIN: printf("server fail\n"); break;
case WSANO_RECOVERY: printf("no recovery\n"); break;
case WSAEINPROGRESS: printf("socket blocked by other prog\n"); break;
case WSANO_DATA: printf("no data record\n"); break;
case WSAEINTR: printf("blocking call canciled\n"); break;
case WSAEPROCLIM: printf("limit exceeded\n");
case WSAEFAULT: printf("lpWSAData in startup not valid\n");
default: printf("unknown error id = %d\n",id); break;
};
printf("receive error.\n");
};