8

Linux用のepollを使用してtcpクライアントの非同期接続と切断が必要です。内線があります。ConnectEx、DisconnectEx、AcceptExなどのWindowsの機能... tcpサーバーでは標準のaccept機能が機能していますが、tcpクライアントでは接続と切断が機能していません...すべてのソケットがブロックされていません。

これどうやってするの?

ありがとう!

4

4 に答える 4

37

ノンブロッキングの connect() を実行するには、ソケットがすでにノンブロッキングになっていると仮定します。

int res = connect(fd, ...);
if (res < 0 && errno != EINPROGRESS) {
    // error, fail somehow, close socket
    return;
}

if (res == 0) {
    // connection has succeeded immediately
} else {
    // connection attempt is in progress
}

connect() が EINPROGRESS で失敗した 2 番目のケース (この場合のみ) では、ソケットが書き込み可能になるまで待機する必要があります。たとえば、epoll では、このソケットで EPOLLOUT を待機していることを指定します。書き込み可能であるという通知を受け取ったら (epoll を使用すると、EPOLLERR または EPOLLHUP イベントも受け取ることが期待されます)、接続試行の結果を確認します。

int result;
socklen_t result_len = sizeof(result);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) {
    // error, fail somehow, close socket
    return;
}

if (result != 0) {
    // connection failed; error code is in 'result'
    return;
}

// socket is ready for read()/write()

私の経験では、Linux では connect() がすぐに成功することはなく、書き込み可能になるまで常に待機する必要があります。ただし、たとえば FreeBSD では、ノンブロッキングの connect() to localhost がすぐに成功するのを見てきました。

于 2012-04-17T16:07:10.243 に答える
3

経験上、ノンブロッキング接続を検出する場合、epoll は select や poll とは少し異なります。

epollで:

connect() 呼び出しが行われた後、戻りコードを確認します。

接続がすぐに完了できない場合は、epoll に EPOLLOUT イベントを登録します。

epoll_wait() を呼び出します。

接続に失敗した場合、イベントは EPOLLERR または EPOLLHUP で満たされ、それ以外の場合は EPOLLOUT がトリガーされます。

于 2013-08-15T09:14:20.127 に答える
1

他の誰かがこれを探している場合に備えて、ここに「完全な」回答があります。

#include <sys/epoll.h>
#include <errno.h>
....
....
int retVal = -1;
socklen_t retValLen = sizeof (retVal);

int status = connect(socketFD, ...);
if (status == 0)
 {
   // OK -- socket is ready for IO
 }
else if (errno == EINPROGRESS)
 {
    struct epoll_event newPeerConnectionEvent;
    int epollFD = -1;
    struct epoll_event processableEvents;
    unsigned int numEvents = -1;

    if ((epollFD = epoll_create (1)) == -1)
    {
       printf ("Could not create the epoll FD list. Aborting!");
       exit (2);
    }     

    newPeerConnectionEvent.data.fd = socketFD;
    newPeerConnectionEvent.events = EPOLLOUT | EPOLLIN | EPOLLERR;

    if (epoll_ctl (epollFD, EPOLL_CTL_ADD, socketFD, &newPeerConnectionEvent) == -1)
    {
       printf ("Could not add the socket FD to the epoll FD list. Aborting!");
       exit (2);
    }

    numEvents = epoll_wait (epollFD, &processableEvents, 1, -1);

    if (numEvents < 0)
    {
       printf ("Serious error in epoll setup: epoll_wait () returned < 0 status!");
       exit (2);
    }

    if (getsockopt (socketFD, SOL_SOCKET, SO_ERROR, &retVal, &retValLen) < 0)
    {
       // ERROR, fail somehow, close socket
    }

    if (retVal != 0) 
    {
       // ERROR: connect did not "go through"
    }   
}
else
{
   // ERROR: connect did not "go through" for other non-recoverable reasons.
   switch (errno)
   {
     ...
   }
}
于 2012-06-05T21:19:02.133 に答える
1

Sonny のソリューションを試しましたが、epoll_ctl は無効な引数を返します。したがって、これを行う正しい方法は次のとおりだと思います。

1.socketfd と epollfd を作成する

2. epoll_ctl を使用して、socketfd と epollfd を epoll イベントに関連付けます。

3.接続を行います(socketfd、...)

4.戻り値またはerrnoを確認する

5. errno == EINPROGRESS の場合、epoll_wait を実行します

于 2014-05-03T07:46:22.860 に答える