0

ソケットを作成し、接続を受け入れようとしています。すべて正常に動作します。しかし、出力は、次のコードがどのように機能するかについて私を混乱させています。

      // this a server program
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/un.h>
    #include <arpa/inet.h>
    #include <errno.h>
    #include <wait.h>

    #define LISTENQ (1024)

    int main(void) {

       int lstn_sock, conn_sock;
       struct sockaddr_in my_serv;
       short int pnum = 4080;

       // create listening socket
       if( (lstn_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("Error (socket): %s\n",strerror(errno));
        exit(1);
       }

       // initialize socket address
       memset( &my_serv, 0, sizeof(my_serv) );
       my_serv.sin_family = AF_INET;
       my_serv.sin_addr.s_addr = INADDR_ANY;
       my_serv.sin_port = htons(pnum);

       // associate address with socket. 
       if( bind(lstn_sock, (struct sockaddr *) &my_serv, sizeof(my_serv)) < 0){
        printf("Error (bind): %s\n",strerror(errno));
        exit(1);
       }
        //printf("lstn_sock: %d\n",lstn_sock);
       // start listening to socket
       if( listen(lstn_sock, LISTENQ) < 0){
        printf("Error (listen): %s\n",strerror(errno));
        exit(1);
       }

       // make it a daemon
       while(1){
        // retrieve connect request and connect
        if( (conn_sock = accept(lstn_sock, NULL, NULL)) < 0){
           printf("Error (accept): %s\n",strerror(errno));
           exit(1);
        }

        printf("The server says hi!\n");

        // close connected socket
        if( close(conn_sock) < 0){
           printf("Error (close): %s\n",strerror(errno));
           exit(1);
        }
       }

    return 0;

    }

@ubuntu:$ ./my_code & @ubuntu:$ telnet localhost 4080

以下は、上記のコードからの 2 つの異なる出力です。
Output1
Trying ::1...
Trying 127.0.0.1..
localhost に接続されています。
エスケープ文字は「^]」です。
サーバーがこんにちは!
接続は外部ホストによって閉じられました。

Output2
Trying ::1...
Trying 127.0.0.1..
サーバーからこんにちは!
ローカルホストに接続しました。
エスケープ文字は「^]」です。
接続は外部ホストによって閉じられました。

「サーバーがこんにちは!」という動きの理由を誰か説明してください。
出力で。

4

2 に答える 2

2

サーバーをバックグラウンドで起動し、同じ端末で telnet を使用してテストしていると思います。

サーバーはその挨拶を標準出力に出力し、telnet も標準出力に書き込みます。これらは、独立して (おそらく同時に) スケジュールされる 2 つの独立したプロセスです。出力が端末に表示される正確な順序を予測することはできません。

于 2012-04-21T15:14:31.060 に答える
1

より長い回答を書きましたが、カーネルパニックが発生しました!!!! 私のMOBOがとても嫌いです。しかし、ここに短い要約があります。

あなたの問題は解決されましたが、明確にするためにのみ:

あなたは読むことができました-そしてサブ。

端末を使用しています。端末には通常、次の 3 つのストリームがあります。

  • 標準入力
  • 標準出力
  • 標準エラー

サーバープログラムを開始すると、その端末でプロセスが開始されます。

プロセスは、環境変数、制限などの端末プロセスからさまざまな「もの」を継承します。サーバーもシェルの子プロセスになります。シェル自体は通常、上位プロセスの子などです。

アンパサンドを使用すると、プロセスはバックグラウンドに置かれますが、同じ端末の子のままです。

いずれかのストリームへの書き込みは、プロセスを開始したシェルと同じストリームに書き込まれます。

stdout通常のサーバー/クライアントのシナリオでは、メッセージを送信するために に書き込むことはありません。サーバーのstdoutは、サーバー環境 (/proc/[pid]/fd/…) にバインドされます。クライアントは、通常は別のシステム上にあり、(通常) サーバー上の何にもアクセスできません。したがって、ソケットの概念全体 - 独立したシステム間の通信。そのため、代わりに接続に書き込みます。


さまざまな Linux ツールを使用してケースを簡単に見てみましょう。

発行pstreeすると、これを簡単に視覚化できます。のようなもの (たくさん削除):

$ ./server 4082 &
[1] 2795 <-- PID OF SERVER
$ pstree -p
init(1)─┬─ ...
        :
        ├─gnome-terminal(2369)─┬─bash(2374)───mplayer(2459)───mplayer(2460)
        │                      ├─bash(2586)───pstree(2779)
        │                      ├─bash(2646)
        │                      ├─bash(2705)───server(2795) <-- YOUR SERVER
        │                      ├─gnome-pty-helpe(2373)
        │                      ├─{gnome-terminal}(2371)
        │                      ├─{gnome-terminal}(2372)
        │                      └─{gnome-terminal}(2375)
        :
$ telnet localhost 4082  <--- IN SAME TERMINAL
$ pstree -p
init(1)─┬─ ...
        :
        ├─gnome-terminal(2369)─┬─bash(2374)───mplayer(2459)───mplayer(2460)
        │                      ├─bash(2586)───pstree(2779)
        │                      ├─bash(2646)
        │                      ├─bash(2705)─┬─server(2795) <-- YOUR SERVER
        │                      │            └─telnet(2797) <-- TELNET SAME SHELL
        │                      ├─gnome-pty-helpe(2373)
        │                      ├─{gnome-terminal}(2371)
        │                      ├─{gnome-terminal}(2372)
        │                      └─{gnome-terminal}(2375)
        :

今。サーバーとシェルは同じ bash を共有し、結果として同じエンド ユーザー出力を共有します- stdout…</p>

プロセスのさまざまなストリームをさまざまな方法でスパイできます。簡単な方法の 1 つは、次を使用することstraceです。

$ sudo strace -ewrite -p 12345

ここ12345で、プロセスの PID です。すなわち;

$ sudo strace -e write=0,1,3,4 -p 2797
Process 2797 attached - interrupt to quit
select(4, [0 3], [], [3], NULL)         = 1 (in [0])
read(0, "frack!\n", 8129)               = 7
select(4, [0 3], [3], [3], {0, 0})      = 1 (out [3], left {0, 0})
send(3, "frack!\r\n", 8, 0)             = 8
 | 00000  66 72 61 63 6b 21 0d 0a                           frack!..          |
于 2012-04-21T19:10:17.097 に答える