12

私はバークレー ソケット (インターネット ドメインと Unix ドメインの両方) を使用していますが、サーバーが要求の読み取りとクライアントへの応答の書き込みに同じソケットを使用できるかどうか疑問に思っていました。または、クライアントはリプレイを待機する別のソケットを作成し、サーバーは受信したメッセージの処理後にそれに接続する必要があります。

ところで、接続指向のソケット (ストリーム ソケット、TCP など) について話しています。

これは簡略化されたサーバー コードです (簡略化のために、ここではシステム コールのエラー チェックを省略しています)。

int main() {

    int server_socket, connected_socket;
    struct sockaddr_in server_addr;
    char buf[1024];
    char aux[256];
    int bytes_read;

    server_socket = socket(AF_INET, SOCK_STREAM, 0);    

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(1234);
    bind(server_socket, &server_addr, sizeof(server_addr))

    listen(server_socket, 5)

    connected_sodket = accept(server_socket, 0, 0);
    do {
        bzero(buf, sizeof(buf));
        bytes_read = read(connected_socket, buf, sizeof(buf));        
    } while (bytes_read > 0);          

    /* Here I want to use connected_socket to write the reply, can I? */

    close(connected_socket);       

    close(server_socket);

    return (EXIT_SUCCESS);
}

そして、これは単純化されたクライアント コードです (単純化するために、ここではシステム コールのエラー チェックを省略しています)。

int main() {

    int client_socket;
    struct sockaddr_in server_addr;

    client_socket = socket(AF_INET, SOCK_STREAM, 0);

    hp = gethostbyname("myhost");
    server_addr.sin_family = AF_INET;
    memcpy(&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
    server_addr.sin_port = htons(1234);

    connect(client_socket, &server_addr, sizeof(server_addr));

    write(client_socket, MSG, sizeof(MSG));

    /* Here I want to wait for a response from the server using client_socket, can I? */

    close(client_socket);

    return (EXIT_SUCCESS);
}

connected_socketサーバーとクライアントで使用してclient_socket、応答メッセージを返すことはできますか? または、「受け入れる」ときにサーバーで取得したクライアントアドレスを使用して、クライアントのソケットに接続する必要がありますか?

コメントが表示されているクライアント/サーバーで読み取り/書き込みを使用してみましたが、両方のプログラムがブロックされたままになり、デッドロックのようです。

よろしくお願いします!よろしく。

4

9 に答える 9

10

同じソケットを使用する必要があります。

アプリケーション プロトコルは、クライアントとサーバーがいつデータを待機するか、メッセージを相互に送信するかを明確に定義します。クライアントからの要求が 1 つだけで、サーバーからの応答が 1 つだけのプロトコルを想定すると、次のようになります。


  • クライアントはサーバーとの接続を確立します。
  • クライアントがリクエストを送信します (send() を使用)。
  • クライアントは、プロトコルによって、サーバーが応答することを知っています。したがって、同じソケット (recv()) でデータを待ちます。
  • 応答を検証した後、クライアントはソケットを閉じることができます。

  • サーバーはクライアントからの接続を受け入れます。
  • サーバーは、最初のステップがクライアント次第であることを認識しているため、データを待ちます (recv());
  • サーバーはリクエストを検証します。
  • サーバーは、クライアントがデータを待っていることをプロトコルから認識します。したがって、send(); で応答を送信します。
  • サーバーは、プロトコルから、これ以上の手順がないことを認識しています。したがって、ソケットを閉じることができます。
于 2009-01-21T23:07:16.137 に答える
8

同じソケットを使用できますが、プログラムは、応答を試みる前にクライアントが送信するすべてをサーバーに読み取らせるように設定されています。したがって、クライアントがソケットの書き込み側を閉じるまでサーバーのループは完了しないため、サーバーは EOF (0 バイトの読み取り) を取得するため、サーバーは応答を返しません。

これに対処するには、いくつかの方法があります。

  1. EOF まで読み取るのではなく、リクエスト全体が表示された後にサーバーのループを中断できます。これには、クライアントから送信されたデータが自己区切りである必要があるため、サーバーはいつすべてを読み取ったかを知ることができます。
  2. 返信には 2 番目の接続を使用できます。おそらく最高ではありません。
  3. ソケットの非対称シャットダウンを使用できます。クライアントshutdown(client_socket, SHUT_WR)にソケットを半分閉じてもらいます。その後、サーバーは EOF を認識します (そしてループは終了します) が、ソケットの他の方向はまだ応答のために開かれています。
于 2009-01-21T23:29:38.993 に答える
3

はい、可能です。単純なサーバー (および単純なクライアント) の例については、このページを参照してください。サーバーは通常、「受け入れられた」ファイル記述子を新しいプロセスに渡すことに注意してください。これにより、より多くの着信接続をリッスンし続けることができます。

于 2009-01-21T23:04:04.333 に答える
2

同じソケットを使用する必要があるだけでなく (Federico が言うように)、ファイアウォールを介して戻りパケットを取得するには、実際に同じソケットを使用する必要があります。

ファイアウォールは TCP 接続を認識しており、ファイアウォール内のマシンが接続を開始した場合は、戻りデータの通過を自動的に許可します。代わりに、ファイアウォールの外側から新しい TCP ソケットを作成しようとすると、そのトラフィックが特に許可されていない限り、ブロックされます。

于 2009-01-21T23:31:13.467 に答える
1

現在の設定では、サーバーはクライアントがソケットを閉じるまで読み取りを試みますが、クライアントはサーバーが応答するまでソケットを閉じません。したがって、一種の「デッドロック」があります。サーバーは、さらにデータが到着することを期待して読み取りを停止していません。クライアントは、サーバーに読み取りが完了したことを伝える方法がありません。

接続がまだ開いている間に、サーバーがリクエストが完了したことを認識する何らかの方法が必要です。たとえば、リクエストを改行で終了すると、サーバーは完全な行を受信したかどうかを確認し、読み取りを停止して回答を送信できます。

于 2009-01-21T23:26:42.103 に答える
1

はい、SOCK_STREAM ソケットは双方向です。接続の両側で同じソケットに対して読み書きできる必要があります。のマニュアルページにsocket(2)は、これに関する詳細が記載されています。

于 2009-01-21T23:01:12.747 に答える
1

はい、できます。TCP ソケットは双方向です。同じ read() および write() 関数を使用するだけです。また、ネットワーク上で何が起こるかを制御できないため、connect()、read()、write() などのすべての呼び出しでエラー状態を確認してください。

于 2009-01-21T23:01:31.903 に答える
1

ごめん; 言わなかったけどこんな風にしてみた

コメントがあるサーバーのこのコード:

write(connected_socket, "Ok, I got it", sizeof("Ok, I got it"));

コメントがあるクライアントのこのコード:

read(client_socket, buf, sizeof(buf));

両方のプログラムがブロックされたままになり、クライアントを強制終了すると、サーバーは受信したメッセージを表示します (サーバーがread を呼び出した直後に printf があります)。

read と write の代わりに send と recv (両方とも 0 フラグ) で試してみましたが、変わりませんでした。

于 2009-01-21T23:14:52.733 に答える
0

試してみましたか?示された場所に実際にコードを入れるとうまくいくようです

于 2009-01-21T23:00:42.297 に答える