连接请求的输出不是原子的

问题描述 投票:0回答:2

我已经创建了一个套接字,并且正在尝试接受连接。一切正常。但是,输出让我对以下代码的工作原理感到困惑。

      // 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本地主机4080

以下是上述代码的 2 个不同输出:
输出1
正在尝试::1...
正在尝试 127.0.0.1..
连接到本地主机。
转义字符是“^]”。
服务员打招呼!
外部主机关闭连接。

输出2
正在尝试::1...
正在尝试 127.0.0.1..
服务员打招呼!
连接到本地主机。
转义字符是“^]”。
外部主机关闭连接。

有人可以解释一下“服务器打招呼!”移动的原因吗
在输出中。

c sockets
2个回答
2
投票

我猜您在后台启动了服务器,并在同一终端中使用 telnet 来测试它。

您的服务器将该问候语打印到标准输出,telnet 也会写入标准输出。它们是两个独立的进程,将独立调度(可能同时)。您无法预测输出在终端上出现的确切顺序。


1
投票

我写了一个更长的答案,但随后出现了内核恐慌!!!!非常讨厌我的MOBO。但这里有一个较短的回顾。

我看到您的问题已解决,但只是澄清一下:

您可以阅读 - 并订阅。

您正在使用终端。一个终端通常有三个:

  • 标准输入
  • 标准输出
  • 标准错误

当您启动 server 程序时,该终端中会启动一个进程。

该进程从终端进程继承各种“things”,如环境变量、限制等。服务器也成为 shell 的child进程。 shell 本身通常是更高进程的子进程,等等。

当您使用&符号时,进程将被放入后台,但仍然是同一终端的子进程。

写入任一流都会写入与启动进程的 shell 相同的流

在典型的服务器/客户端场景中,您不会写入

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)
        :

现在。服务器和 shell 共享相同的 bash 以及相应的相同的最终用户 输出 -

stdout

您可以通过多种方式监视流程的不同流。一种简单的方法是使用

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!..          |
© www.soinside.com 2019 - 2024. All rights reserved.