Linux用のepollを使用してtcpクライアントの非同期接続と切断が必要です。内線があります。ConnectEx、DisconnectEx、AcceptExなどのWindowsの機能... tcpサーバーでは標準のaccept機能が機能していますが、tcpクライアントでは接続と切断が機能していません...すべてのソケットがブロックされていません。
これどうやってするの?
ありがとう!
Linux用のepollを使用してtcpクライアントの非同期接続と切断が必要です。内線があります。ConnectEx、DisconnectEx、AcceptExなどのWindowsの機能... tcpサーバーでは標準のaccept機能が機能していますが、tcpクライアントでは接続と切断が機能していません...すべてのソケットがブロックされていません。
これどうやってするの?
ありがとう!
ノンブロッキングの 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 がすぐに成功するのを見てきました。
経験上、ノンブロッキング接続を検出する場合、epoll は select や poll とは少し異なります。
epollで:
connect() 呼び出しが行われた後、戻りコードを確認します。
接続がすぐに完了できない場合は、epoll に EPOLLOUT イベントを登録します。
epoll_wait() を呼び出します。
接続に失敗した場合、イベントは EPOLLERR または EPOLLHUP で満たされ、それ以外の場合は EPOLLOUT がトリガーされます。
他の誰かがこれを探している場合に備えて、ここに「完全な」回答があります。
#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)
{
...
}
}
Sonny のソリューションを試しましたが、epoll_ctl は無効な引数を返します。したがって、これを行う正しい方法は次のとおりだと思います。
1.socketfd と epollfd を作成する
2. epoll_ctl を使用して、socketfd と epollfd を epoll イベントに関連付けます。
3.接続を行います(socketfd、...)
4.戻り値またはerrnoを確認する
5. errno == EINPROGRESS の場合、epoll_wait を実行します