3

まず第一に、これはこれとは別の問題であると言いたい:似ているが同じではない

私のコードは次のようになります:

struct addrinfo hints, *res;
struct sockaddr* serveraddr;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

int res2 = getaddrinfo(ip, port, &hints, &res);
printf("getaddrinfo() res: %d, %d\n", res2, errno);

serveraddr = res->ai_addr;

//create new socket

int soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("socket() res: %d, %d\n", socket, errno);

//set nonblocking mode
unsigned long on = 1;
res2 = ioctl(soc, FIONBIO, &on);
printf("ioctl() res: %d\n, %d", res2, errno);

res2 = connect(soc, serveraddr, sizeof(struct sockaddr));
printf("connect() res: %d, %d\n", res2, errno);

//check if socket is ready
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(soc, &wfds);

struct timeval t;
t.tv_sec=15;
t.tv_usec=0;

res2 = select(soc + 1, 0, &wfds, 0, &t);
printf("select() res: %d, %d\n", res2, errno);`

存在するマシンに接続しています(IPアドレスは存在しますが、接続しようとしているポートでリッスンしているサーバーがありません)。

Selectは常に1を返します。なぜですか?人によると、タイムアウトして0を返す必要があります。この後、ソケットに何かを書き込もうとすると、-1/ECONNREFUSEDが返されます。

これは予想される動作ですか?はいの場合、select()が接続されているかどうかを確認するにはどうすればよいですか?

4

2 に答える 2

8

タイムアウトする必要があると表示されているマニュアルページの場所がわかりません。

パケットをドロップするファイアウォールがない場合、接続は非常に高速に拒否されます (ホストからの 1 つのパケット、1 つのパケットの応答)。したがって、リセットが受信されるとすぐに、接続ソケットの「イベント」が発生します。これselectにより、(少なくとも) 1 つのアクティブなソケットが起動されます。

そのソケットからの読み取りまたは書き込みを最初に試みると、根本的な接続エラーが返されます。

于 2011-12-07T15:37:30.543 に答える
2

これは正しい動作です。保留中のエラーにより、ソケットが読み取りと書き込みの両方が可能になるためです。他のシステム コールと同様に、エラー状態を明示的にチェックする必要があります。ソケットを例外 fdset (select() の 4 番目の引数) に含めて、通知を直接取得するか、後でさまざまな方法でエラーをチェックすることができます。

SIGPIPE が発生する可能性があるため、ソケットへの書き込みには注意してください。一般に、SIGPIPE ハンドラーを設定し、EPIPE と同期してエラーを処理する必要があります。

于 2012-12-27T16:12:26.827 に答える