0

TCP プロトコルを使用してツールを作成しています。このツールは 1000 の TCP クライアントをシミュレートします.ソケット fd が約 500 に追加されると, ソケットを作成するフォローアップはデータを送信できません.送信関数は 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());
}
4

1 に答える 1

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。これらは実際にはエラーではなく、通常の予想される状態であるためです。

于 2012-12-03T08:28:59.947 に答える