0

winsock を使用して単純なクライアント/サーバー アプリケーションを作成しました。サーバーとクライアントは、localhost の TCP ポート 76567 (私が選んだランダムな番号) を介して接続し、通信します。私は 3 台のデスクトップでテストしました。2 台は XP を実行し、もう 1 台は Win7 を実行しています。また、4 台のラップトップでテストしました。3 台は Win7 を実行し、1 台は XP を実行しています。アプリケーションはすべてのデスクトップ マシンと XP ラップトップで正常に動作しますが、クライアントがサーバーに接続しようとすると、3 台の Win7 ラップトップすべてでエラー 10061 が発生します。

ファイアウォールをオフにしましたが、問題は解決しません。また、このエラーの原因を調べてみたところ、クライアントがリッスンしていないサーバーに接続しようとしているようです。ただし、listen() へのサーバー呼び出しは正常に返されます。問題が Win7 ラップトップでのみ発生するように見えるのは非常に奇妙ですが、アイデアはありますか?

これが私のソケット初期化コードです:

// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
    printf("WSAStartup failed: %d\n", iResult);
}

// Create a server socket
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if(iResult != 0)
{
    printf("getaddrinfo failed: %d\n", iResult);
    WSACleanup();
}

// Create a socket to listen for clients
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
    printf("Error at socket(): %d\n", WSAGetLastError());

    freeaddrinfo(result);
    WSACleanup();
}

// Bind socket to ip address and port
iResult = bind(listenSocket, result->ai_addr, (int) result->ai_addrlen);
if(iResult == SOCKET_ERROR)
{
    printf("bind failed with error: %d\n", WSAGetLastError());

    freeaddrinfo(result);
    closesocket(listenSocket);
    WSACleanup();
}
freeaddrinfo(result);

// Listen for connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
    printf("Listen failed with error: %d\n", WSAGetLastError());

    closesocket(listenSocket);
    WSACleanup();
}

どうもありがとう :)

4

2 に答える 2

2

IP ポートは 16 ビット整数であるため、許可される最大ポート番号は 0xFFFF (65535) です。ここで起こるのは一種の整数オーバーフローです。目的のポート番号 (76567) は 16 ビットに収まらないため、番号が切り捨てられ、最下位の 16 ビットのみが使用されます。これでポート番号 11031addr.sin_port = htons(76567);が得られhtons()ますuint16_t

于 2012-07-13T21:39:25.087 に答える
0

getaddrinfo()指定された条件で使用可能なすべてのアドレスのリンクされたリストを返しますhints。マシンにネットワーク アダプターが 1 つしかない場合でも、localhost であっても、複数の IP アドレスが割り当てられている可能性があります。見つかった最初の IP/ポートのペアにサーバー ソケットをバインドしているgetaddrinfo()ため、クライアントが実際にはサーバーでリッスンしていない別の IP/ポートに接続しようとしている可能性があります。あなたのLAN /インターネットIPが、代わりにクライアントが接続してい127.0.0.1ます。127.0.0.1サーバーが にバインドされていない限り、クライアントは に接続できません127.0.0.1

マルチホーム/マルチ IP 環境では、 を呼び出すときに、 の代わりにワイルドカード0.0.0.0IP (別名) を使用する必要があります。これにより、インストールされているすべてのネットワーク アダプターの使用可能なすべての IP にソケットがバインドされます。そうすれば、クライアントは、サーバーがバインドされている任意の IP に接続できます。実際、あなたが示したコードを考えると、まったく使用する必要さえありません:INADDR_ANYbind()result->ai_addr127.0.0.1getaddrinfo()

// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
    printf("WSAStartup failed: %d\n", iResult);
}

// Create an IPv4 server socket to listen for IPv4 clients
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == INVALID_SOCKET)
{
    printf("Error at socket(): %d\n", WSAGetLastError());
    WSACleanup();
}

// Bind socket to IPv4 address and port
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(76567);
addr.sin_addr.s_addr = INADDR_ANY;

iResult = bind(listenSocket, (sockaddr*)&addr, sizeof(addr));
if(iResult == SOCKET_ERROR)
{
    printf("bind failed with error: %d\n", WSAGetLastError());
    closesocket(listenSocket);
    WSACleanup();
}

// Listen for IPv4 connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
    printf("Listen failed with error: %d\n", WSAGetLastError());
    closesocket(listenSocket);
    WSACleanup();
}
于 2012-04-28T00:41:33.880 に答える