我已经创建了一个套接字,并且正在尝试接受连接。一切正常。但是,输出让我对以下代码的工作原理感到困惑。
// 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..
服务员打招呼!
连接到本地主机。
转义字符是“^]”。
外部主机关闭连接。
有人可以解释一下“服务器打招呼!”移动的原因吗
在输出中。
我猜您在后台启动了服务器,并在同一终端中使用 telnet 来测试它。
您的服务器将该问候语打印到标准输出,telnet 也会写入标准输出。它们是两个独立的进程,将独立调度(可能同时)。您无法预测输出在终端上出现的确切顺序。
我写了一个更长的答案,但随后出现了内核恐慌!!!!非常讨厌我的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!.. |