我有这个主要是原型的 TCP 套接字服务器,它接受一个连接,然后运行一个用户指定的程序来与另一端对话。神秘的是 write() 被调用并返回,但没有输出到达客户端。
strace 输出(作为执行程序运行“cat”)如下所示:
[pid 8142] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 32768) = 292
[pid 8142] write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 292) = 292
[pid 8142] read(0, "", 32768) = 0
[pid 8142] close(0) = 0
[pid 8142] close(1) = 0
[pid 8142] close(2) = 0
而在客户端则什么都没有发生:
shell$ seq 100 | nc localhost 4445
shell$
我已经准备好相信 execve'd 程序应该像使用 send/recv/shutdown 而不是 read/write/close 一样对待套接字,但我到目前为止看到的文档似乎建议 close() 应该按设计工作,并且仅在半关闭连接时才需要关闭。Unix Sockets FAQ提到未发送的数据应该在关闭时刷新而不设置任何 SO_LINGER 选项,Linux 手册页 socket(7) 声称“当套接字作为 exit(2) 的一部分关闭时,它总是在后台徘徊. " 给它足够的输出会导致第一部分到达客户端。
为了完整起见,这里是程序...
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/net.h>
#include <netinet/in.h>
static int sock_fd_listen;
static struct sockaddr_in my_addr = {PF_INET, 0x5d11, 0x0100007f};
static struct
static int one=1;
static int sockargs[]={0, 0, 0};
extern char **environ;
void step1()
{
int retval;
sock_fd_listen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
retval=bind(sock_fd_listen, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr_in));
if (retval==-1) {
perror("bind");
exit(1);
}
setsockopt(sock_fd_listen, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
listen(sock_fd_listen, 5);
}
void main(int argc, char *argv[])
{
static char buf[4096];
int nconn=0;
step1();
while (1) {
int conn_sock;
pid_t pid;
sockargs[0]=sock_fd_listen;
conn_sock=accept(sock_fd_listen,NULL,NULL);
pid=fork();
if (pid==0) {
dup2(conn_sock,0);
dup2(conn_sock,1);
close(conn_sock);
execve(argv[1],argv+1,environ);
fprintf(stderr, "execve failed: %s\n",strerror(errno));
exit(-1);
} else {
close(conn_sock);
}
}
}