【发布时间】:2021-01-11 01:38:39
【问题描述】:
我有简单的“echo”客户端-服务器代码,并用tcpdump 观看tcp 流,客户端总是在发送274 后发送RST。总是。但我不知道如何追查这个问题。客户:
//FILE to read from (stdin), sockfd from connect()
void str_cli(FILE *fp, int sockfd)
{
int maxfd;
fd_set rset;
//BSIZE == 4096
char recvline[BSIZE], sendline[BSIZE];
int streamfd = fileno(fp);
//clear the read set
FD_ZERO(&rset);
while (1)
{
FD_SET(streamfd, &rset);
FD_SET(sockfd, &rset);
maxfd = max(streamfd, sockfd) + 1;
//select blocks until one of the fds are readable
if (select(maxfd, &rset, NULL, NULL, NULL) < 0)
{
die("select");
}
if (FD_ISSET(sockfd, &rset))
{
//socket is readable
if (Readline(sockfd, recvline, BSIZE) == 0)
{
die("str_cli: server terminated prematurely");
}
Fputs(recvline, stdout);
}
if (FD_ISSET(streamfd, &rset))
{
//got input and can read from streamfd
if (fgets(sendline, BSIZE, fp) == NULL)
{
//EOF == all done
perror("fgets in select");
return;
}
Writen(sockfd, sendline, strlen(sendline));
}
}
}
服务器:
//sockfd is socket returned from accept()
void str_echo(int sockfd)
{
ssize_t len;
//BSIZE == 4096
char buf[BSIZE];
again:
while ((len = read(sockfd, buf, BSIZE)) > 0)
{
Writen(sockfd, buf, len);
}
if (len < 0 && errno == EINTR)
{
goto again;
}
else if (len < 0)
{
perror("str_echo::read");
}
}
我将 BSIZE 设置为 256,我认为内核由于缓冲区溢出而正在杀死客户端,所以我将其更改为 4096。但问题仍然存在,客户端发送 274 字节后,它发送 @ 987654326@ 我不知道为什么。最后的转储
127.0.0.1:9877 -> 服务器 127.0.0.1:46790 -> 客户端
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [S], seq 1941257529, win 65495, options [mss 65495,sackOK,TS val 2375820429 ecr 0,nop,wscale 7], length 0
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [S.], seq 4099864764, ack 1941257530, win 65483, options [mss 65495,sackOK,TS val 2375820429 ecr 2375820429,nop,wscale 7], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [.], ack 1, win 512, options [nop,nop,TS val 2375820429 ecr 2375820429], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 1:37, ack 1, win 512, options [nop,nop,TS val 2375820430 ecr 2375820429], length 36
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 37, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 37:81, ack 1, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 44
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 81, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 81:82, ack 1, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 1
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 82, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 82:92, ack 1, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 10
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 92, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [P.], seq 1:82, ack 92, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 81
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 194, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 194:210, ack 82, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 16
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 210:226, ack 82, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 16
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [P.], seq 226:236, ack 82, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 10
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [.], ack 266, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
IP 127.0.0.1.9877 > 127.0.0.1.46790: Flags [P.], seq 82:274, ack 274, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 192
IP 127.0.0.1.46790 > 127.0.0.1.9877: Flags [R.], seq 274, ack 274, win 512, options [nop,nop,TS val 2375820430 ecr 2375820430], length 0
19 packets captured
56 packets received by filter
16 packets dropped by kernel
有谁知道,为什么内核会强制终止客户端? (通过发送 RST)?
编辑:
如果我使用 netcat 而不是客户端 nc 127.0.0.1 9877 < somefile,服务器会正确地回显它,所以我怀疑客户端在某处有问题。但是内核还是强行让客户端发送RST,为什么呢?
【问题讨论】:
-
只是一个想法......我熟悉
write,但不熟悉Writen[但是,我假设它们相似]。您没有检查Writen返回值。Writen可能会做一个“短”写,你必须循环(例如)while ((rlen = read(sockfd, buf, BSIZE)) > 0) { for (off = 0; rlen > 0; rlen -= slen, off += slen) { slen = Writen(sockfd, &buf[off], rlen); if (slen < 0) { perror("Writen"); break; } } } -
我猜客户端在某种程度上崩溃了,而 RST 是这次崩溃的结果。只是,您没有提供实际重现问题所需的信息,即没有完整的代码,没有来自客户端的输出,没有客户端崩溃的信息......。不要过分关注 RST,它可能只是客户端崩溃的结果。首先关注客户端崩溃的原因。