为什么我的select和recv这么慢!!

wybin 2007-04-04 03:02:25
编写了一下程序,需要不断地将数据从一台计算机发送到另一台计算机,发现select和recv每次都会消耗150毫秒左右,不知道效率怎么这么低下,怎么解决呀!

软件设计是这样的,socket连接上后,双方都select对端是否有数据发送过来,
数据分为消息头和消息体,消息头是固定格式,消息体变长,因此,如果select有数据发送过来,则先recv消息头,然后直接recv消息体。

假定A机器向B机器发送了一个消息,先发送消息头,然后发消息体(分两个send函数发送),
B机器的select函数会收到数据接收请求,先收消息头(recvX),然后收消息体(recvY),消息收完后,会发送一个确认包(确认包同时携带B要发送给A的数据),确认包也是分为消息头和消息体发送。

通过这种方式,测试发现,在双方都在不断发送接收数据的过程中,

select函数耗时150毫秒左右,第一个recv(recvX)基本不耗时,第二个recv(recvY)耗时150毫秒左右,导致每收一个消息大概需要300毫秒。两个send函数基本不耗时。

也就是说,A机器与B机器之间一个完整的数据轮回大概要300毫秒,绝大多数时间都消耗在了select和recvY上了。

请问各位大虾,这到底是怎么回事,怎么能够让整个过程时间缩短呢?理想的情况最好是1-3毫秒。

网络状态是很好的,局域网100M的测试环境,数据包也很小,都不到1K。

FD_ZERO(&readfds);
FD_SET(this->socketFd,&readfds);

iResult = select(0,&readfds,NULL,NULL,&timeout);

if ( iResult == SOCKET_ERROR )
{
//Log_Manager::WriteError( "Error read on socket.");
return;
}

if ( ! iResult )
{
Log_Manager::WriteInfo( "等待对方250ms,未读取到对方发送的消息。" );

ret = DealTimeout();
Log_Manager::WriteInfo( "超时处理处理完毕。" );
continue;
}

if ( FD_ISSET(socketFd,&readfds) )
{
Log_Manager::WriteInfo( "有数据。" );

//有数据过来
ret = RecvBufferData( &dataHead, rcvDataBuf);
if ( ret < 0 ) //SOCKET_ERROR
{
Log_Manager::WriteError( "接收数据失败,需要关闭连接。");
return;
}

Log_Manager::WriteInfo( "数据接收完毕。" );

ret = SendMsgData();

Log_Manager::WriteInfo( "数据发送完毕。" );




int CNodeCommAdapter::RecvBufferData(msg_head_for_mom_mom* lpDataHead,
char* lpData)
{
Log_Manager::WriteInfo("开始读Head From Socket");

int bytesRecvHead = recv( socketFd, (char*)lpDataHead, sizeof(msg_head_for_mom_mom), 0 );
if ( bytesRecvHead == SOCKET_ERROR || bytesRecvHead != sizeof(msg_head_for_mom_mom) )
return SOCKET_ERROR;

Log_Manager::WriteInfo("读Head From Socket 完毕");

if ( ! lpDataHead->dataLen )
return lpDataHead->dataLen;

int tmpLen = lpDataHead->dataLen;
int bytesRecvData, totalRecvData = 0;

Log_Manager::WriteInfo("开始读Data From Socket");

while ( tmpLen > 0 )
{
printf("%d\n",tmpLen);

bytesRecvData = recv( socketFd, lpData + totalRecvData , tmpLen, 0 );

Log_Manager::WriteInfo("读Data From Socket完毕");

if ( bytesRecvData == SOCKET_ERROR || ! bytesRecvData)
return SOCKET_ERROR;
else
{
tmpLen -= bytesRecvData;
totalRecvData += bytesRecvData;
}
}

return lpDataHead->dataLen;
}

...全文
584 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
wybin 2007-04-05
  • 打赏
  • 举报
回复
Windows中的Winsock2,select的第一个参数忽略,

MSDN:

nfds
[in] Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.
orc1984 2007-04-05
  • 打赏
  • 举报
回复
select 里面的参数设置有问题
zhousqy 2007-04-04
  • 打赏
  • 举报
回复
select是最大的socket號+1吧
zhousqy 2007-04-04
  • 打赏
  • 举报
回复
iResult = select(0,&readfds,NULL,NULL,&timeout);
//////////////////////////////////////////////
第一個參數是0??
bargio_susie 2007-04-04
  • 打赏
  • 举报
回复
先顶再看。
wybin 2007-04-04
  • 打赏
  • 举报
回复
这是SendMsgData中的部分代码:发送基本不消耗时间

int bytesSentHead = send( socketFd, (const char*)lpDataHead, sizeof(msg_head_for_mom_mom), 0 );
if ( bytesSentHead == SOCKET_ERROR || bytesSentHead != sizeof(msg_head_for_mom_mom) )
return SOCKET_ERROR;

if ( lpDataHead->dataLen )
{
int bytesSentData = send( socketFd, lpData, lpDataHead->dataLen, 0 );
if ( bytesSentData == SOCKET_ERROR || bytesSentData != lpDataHead->dataLen )
return SOCKET_ERROR;
else
return bytesSentData;
}
else
return lpDataHead->dataLen;
wybin 2007-04-04
  • 打赏
  • 举报
回复
这是Client向Server发起连接的一段代码:

//开始连接destServerIP/destServerPort
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if ( iResult != NO_ERROR )
Log_Manager::WriteError("Error at WSAStartup()");

// Create a socket.
socketFd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( socketFd == INVALID_SOCKET ) {
Log_Manager::WriteError( "Error at socket" );//(): %ld\n", WSAGetLastError()

WSACleanup();
return;
}

// Connect to a server.
sockaddr_in clientService;

clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( destServerIP );
clientService.sin_port = htons( destServerPort );

if ( connect( socketFd, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {
Log_Manager::WriteError( "Failed to connect." );
iResult = WSAGetLastError();

closesocket(socketFd);

WSACleanup();
return;
}

//Connect OK

Log_Manager::WriteInfo("与上级节点连接成功!");

70,024

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧