我正在编写一个使用TCP协议的工具。该工具模拟1000个TCP客户端。当套接字fd添加到大约500时,创建套接字的后续操作无法发送数据,并且send函数返回EAGAIN。为什么呢?
我的所有TCP套接字都是非阻塞的。
例如:
我的测试日志:
12 2012-12-03 23:21:56:41005 tang_dts_serv_task.cpp:55 [3] [17294] dts zero channel acc.[confid:41075200][userid:860194970]
13 2012-12-03 23:21:56:41509 send_task_mgr.cpp:49 [3] [17348] send task mgr.[cmdcode:4354][fd:1026]
14 2012-12-03 23:21:56:41529 data_send_task.cpp:51 [2] [17348] dts send task.[cmdcode:4354][fd:1026][port:25789]
15 2012-12-03 23:21:56:41543 os_sock.cpp:15 [0] [17348] send error.[fd:1026][errno:11]
套接字1026刚刚创建,但第一个软件包无法发送。
我的永远:
Ubuntu 8.04.4 LTS
Linux VM-Ubuntu203001 2.6.24-24-server #1 SMP Fri Sep 18 17:24:10 UTC 2009 i686 GNU/Linux
发送部分:
void DataSendTask::ProcessMsg(message *msg)
{
tcm_message *tm;
DtsContext *ctx;
ClientEntity *cli;
size_t transfer_bytes;
char *d_buf;
int buf_len;
int retval;
EventHandler *handler;
Reactor *reactor;
tm = (tcm_message*)msg->content;
ctx = (DtsContext*)tm->ctx;
handler = ctx->event_handler();
reactor = handler->reactor();
SendBuffer &s_buf = ctx->send_buf();
SockStream &stream = ctx->sock_stream();
cli = ctx->client_entity();
int sock_state = ctx->GetSockState();
if (sock_state != DtsContext::CS_CONNECTED){
LOG_ERROR("data send task socket state exception! [fd:%d][sockstate:%d]" ,stream.sock_fd() , sock_state);
delete tm;
tm = NULL;
return;
}
struct sockaddr_in localaddr;
socklen_t addr_len;
addr_len = sizeof(localaddr);
OsSock::GetSockName(stream.sock_fd() , (struct sockaddr*)&localaddr , &addr_len);
int port = localaddr.sin_port;
LOG_INFO("dts send task.[cmdcode:%d][fd:%d][port:%d]",msg->msg_code , stream.sock_fd() , port);
//1. Wei need to see wheter the half_package have unsend bytes.
buf_len = s_buf.GetHalfPackageLength();
if (buf_len > 0){
transfer_bytes = 0;
d_buf = s_buf.GetHalfPackagePointer();
retval = stream.Send(d_buf , buf_len , MSG_NOSIGNAL , &transfer_bytes);
if (retval <= 0){
LOG_ERROR("dts half send error.[fd:%d][send_bytes:%d][transfered_bytes:%d]" ,stream.sock_fd(),buf_len,transfer_bytes);
if (retval == OS_SOCK_EAGAIN){
//register event handler
reactor->RegisterHandler(handler , EventHandler::EM_WRITE);
}else if (retval == OS_SOCK_PEER_CNN_CLOSED){
//connect again?
ClientMgr::Instance()->ClientOffline(cli);
}else{
//error,print log info,continue;
}
s_buf.SaveLeftData(d_buf-transfer_bytes , buf_len - transfer_bytes);
delete tm;
tm = NULL;
return;
}
s_buf.SetHalfPackageLength(0);
LOG_DEBUG("dts half send success.[bytes:%d][fd:%d]",retval , stream.sock_fd());
}
PriorityQueue<DtsRtpPackage> &squeue = ctx->send_queue();
while(1){
//1. Get message from priority queue.
DtsRtpPackage *data = squeue.Dequeue();
if (data == NULL)
break;
d_buf = (char *)data;
buf_len = data->m_size + 4;
transfer_bytes = 0;
retval = stream.Send(d_buf , buf_len , MSG_NOSIGNAL , &transfer_bytes);
if (retval <= 0){
LOG_ERROR("dts send error.[fd:%d][send_bytes:%d][transfered_bytes:%d]" ,stream.sock_fd(),buf_len,transfer_bytes);
if (retval == OS_SOCK_EAGAIN){
//register event handler
reactor->RegisterHandler(handler , EventHandler::EM_WRITE);
}else if (retval == OS_SOCK_PEER_CNN_CLOSED){
//connect again?
ClientMgr::Instance()->ClientOffline(cli);
}else{
//error,print log info,continue;
}
s_buf.SaveLeftData(d_buf-transfer_bytes , buf_len - transfer_bytes);
tang_mfree(data);
break;
}
LOG_DEBUG("dts send success.[bytes:%d][fd:%d]",retval , stream.sock_fd());
tang_mfree(data);
}
delete tm;
tm = NULL;
LOG_DEBUG("dts send over.[fd:%d]", stream.sock_fd());
}
答案 0 :(得分:0)
当您使用非阻塞套接字时,您必须期望有时会在必须阻止时尝试操作。这只是非阻塞套接字的本质。当他们否则会阻止时,他们会返回错误。
您的代码如下:
retval = stream.Send(d_buf , buf_len , MSG_NOSIGNAL , &transfer_bytes);
if (retval <= 0){
LOG_ERROR("dts half send error.[fd:%d][send_bytes:%d][transfered_bytes:%d]" ,stream.sock_fd(),buf_len,transfer_bytes);
if (retval == OS_SOCK_EAGAIN){ // <- HERE
//register event handler
reactor->RegisterHandler(handler , EventHandler::EM_WRITE);
}else if (retval == OS_SOCK_PEER_CNN_CLOSED){
//connect again?
ClientMgr::Instance()->ClientOffline(cli);
}else{
//error,print log info,continue;
}
因此它已经正确处理了这种情况,当有缓冲空间可用时重试写入。我只是将代码更改为不记录OS_SOCK_EAGAIN
或OS_SOCK_PEER_CNN_CLOSED
,因为这些实际上不是错误,而是正常的预期条件。