我创建了一个套接字,我正在尝试接受连接。一切正常。但是,输出让我对以下代码的工作原理感到困惑。
// 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&amp; @ubuntu:$ telnet localhost 4080
以下是上述代码的两个不同输出:
的输出1
尝试:: 1 ...
尝试127.0.0.1 ..
连接到localhost。
逃脱角色是'^]'
服务员说嗨!
外部主机关闭连接。
输出2
尝试:: 1 ...
尝试127.0.0.1 ..
服务员说嗨!
连接到localhost。
逃脱角色是'^]'
外部主机关闭连接。
有人可以解释一下“服务员说嗨!”的动作原因 在输出中。
答案 0 :(得分:2)
我猜你在后台启动了你的服务器,并且在同一个终端中使用telnet来测试它。
您的服务器将该问候语打印到标准输出,telnet也会写入标准输出。它们是两个独立的进程,可以独立调度(可能同时进行)。您无法预测输出在终端上的确切顺序。
答案 1 :(得分:1)
我写了一个更长的答案,但后来内核恐慌!!!!非常讨厌我的MOBO。但这是一个较短的重新上限。
我看到你的问题已经解决,但只是要明确:
你可以read - 和潜艇。
您正在使用终端。终端通常有三个streams:
当您启动服务器程序时,将在该终端中启动一个进程。
该进程从终端进程继承了各种“ things ”,如环境变量,限制等。服务器也成为shell的子进程。 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!.. |