当前位置: 技术问答>linux和unix
Shutdown和Select的困惑
来源: 互联网 发布时间:2016-07-23
本文导语: 小弟是菜鸟,最近学习《UNIX网络编程》第三版。读到IO复用那章,6.6,6.7讲shutdown用法的地方,有点困惑。 按照书上说,SHUT_RD是关闭连接读的一半,套接口中不再有数据可接收,而且套接口接受缓冲区中的现有数据...
小弟是菜鸟,最近学习《UNIX网络编程》第三版。读到IO复用那章,6.6,6.7讲shutdown用法的地方,有点困惑。
按照书上说,SHUT_RD是关闭连接读的一半,套接口中不再有数据可接收,而且套接口接受缓冲区中的现有数据都被丢弃。进程不能再对这样的套接口调用任何读函数。套接口接收的来自对端的任何数据都被确认,然后悄悄丢弃。
我为了试验SHUT_RD,就把6.7的str_cli中Shutdown(sockfd, SHUT_WR)改为了Shutdown(sockfd, SHUT_RD)。为了确认客户端退出状态,我还在return前面加了printf("normal terminationn");
客户端代码:tcpcli02.c
str_cli所在文件strcliselect02.c
服务器是一个回射操作,只要客户端从stdio输入,服务器就返回给客户端一样的内容。
运行服务器和客户端,并且在客户端输入“test”和ctrl+d,结果如下:
wanjian@ubuntu:~/net/select$ ./tcpcli02 127.0.0.1
test
test
normal termination
整个连接建立和终止的tcpdump:
root@ubuntu:/home/wanjian# tcpdump -i lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes
22:00:43.922807 IP localhost.53342 > localhost.9877: Flags [S], seq 3927771684, win 32792, options [mss 16396,sackOK,TS val 328455 ecr 0,nop,wscale 5], length 0
22:00:43.925823 IP localhost.9877 > localhost.53342: Flags [S.], seq 3925328431, ack 3927771685, win 32768, options [mss 16396,sackOK,TS val 328456 ecr 328455,nop,wscale 5], length 0
22:00:43.929054 IP localhost.53342 > localhost.9877: Flags [.], ack 1, win 1025, options [nop,nop,TS val 328457 ecr 328456], length 0
22:01:00.022906 IP localhost.53342 > localhost.9877: Flags [P.], seq 1:6, ack 1, win 1025, options [nop,nop,TS val 332480 ecr 328456], length 5
22:01:00.025050 IP localhost.9877 > localhost.53342: Flags [.], ack 6, win 1024, options [nop,nop,TS val 332481 ecr 332480], length 0
22:01:00.026434 IP localhost.9877 > localhost.53342: Flags [P.], seq 1:6, ack 6, win 1024, options [nop,nop,TS val 332481 ecr 332480], length 5
22:01:00.026918 IP localhost.53342 > localhost.9877: Flags [.], ack 6, win 1025, options [nop,nop,TS val 332481 ecr 332481], length 0
22:01:30.425750 IP localhost.53342 > localhost.9877: Flags [F.], seq 6, ack 6, win 1025, options [nop,nop,TS val 340081 ecr 332481], length 0
22:01:30.430395 IP localhost.9877 > localhost.53342: Flags [F.], seq 6, ack 7, win 1024, options [nop,nop,TS val 340082 ecr 340081], length 0
22:01:30.432291 IP localhost.53342 > localhost.9877: Flags [.], ack 7, win 1025, options [nop,nop,TS val 340082 ecr 340082], length 0
从执行结果看,tcpdump中最后3个分组分别是客户端发给服务器的FIN,服务器发给客户端的FIN(捎带了ACK),客户端发给服务器的ACK。这3个分组还好理解,因为“套接口接收的来自对端的任何数据都被确认,然后悄悄丢弃”。但是为何最后客户端“normal termination”了呢?如果“套接口中不再有数据可接收”,那么为什么Select返回了并且检测到是sockfd可读呢?如果“进程不能再对这样的套接口调用任何读函数”,那么下面的Read为何读到了EOF而返回0呢?
请教大虾帮助!!!!
按照书上说,SHUT_RD是关闭连接读的一半,套接口中不再有数据可接收,而且套接口接受缓冲区中的现有数据都被丢弃。进程不能再对这样的套接口调用任何读函数。套接口接收的来自对端的任何数据都被确认,然后悄悄丢弃。
我为了试验SHUT_RD,就把6.7的str_cli中Shutdown(sockfd, SHUT_WR)改为了Shutdown(sockfd, SHUT_RD)。为了确认客户端退出状态,我还在return前面加了printf("normal terminationn");
客户端代码:tcpcli02.c
/* Use standard echo server; baseline measurements for nonblocking version */
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: tcpcli ");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT); //7
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all */
exit(0);
}
str_cli所在文件strcliselect02.c
#include "unp.h"
void
str_cli(FILE *fp, int sockfd)
{
int maxfdp1, stdineof;
fd_set rset;
char buf[MAXLINE];
int n;
stdineof = 0;
FD_ZERO(&rset);
for ( ; ; ) {
if (stdineof == 0)
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);
if (FD_ISSET(sockfd, &rset)) { /* socket is readable */
if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
if (stdineof == 1) {
printf("normal terminationn");
return; /* normal termination */
}
else
err_quit("str_cli: server terminated prematurely");
}
Write(fileno(stdout), buf, n);
}
if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */
if ( (n = Read(fileno(fp), buf, MAXLINE)) == 0) {
stdineof = 1;
Shutdown(sockfd, SHUT_RD); /* send FIN SHUT_WR */
FD_CLR(fileno(fp), &rset);
continue;
}
Writen(sockfd, buf, n);
}
}
}
服务器是一个回射操作,只要客户端从stdio输入,服务器就返回给客户端一样的内容。
运行服务器和客户端,并且在客户端输入“test”和ctrl+d,结果如下:
wanjian@ubuntu:~/net/select$ ./tcpcli02 127.0.0.1
test
test
normal termination
整个连接建立和终止的tcpdump:
root@ubuntu:/home/wanjian# tcpdump -i lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes
22:00:43.922807 IP localhost.53342 > localhost.9877: Flags [S], seq 3927771684, win 32792, options [mss 16396,sackOK,TS val 328455 ecr 0,nop,wscale 5], length 0
22:00:43.925823 IP localhost.9877 > localhost.53342: Flags [S.], seq 3925328431, ack 3927771685, win 32768, options [mss 16396,sackOK,TS val 328456 ecr 328455,nop,wscale 5], length 0
22:00:43.929054 IP localhost.53342 > localhost.9877: Flags [.], ack 1, win 1025, options [nop,nop,TS val 328457 ecr 328456], length 0
22:01:00.022906 IP localhost.53342 > localhost.9877: Flags [P.], seq 1:6, ack 1, win 1025, options [nop,nop,TS val 332480 ecr 328456], length 5
22:01:00.025050 IP localhost.9877 > localhost.53342: Flags [.], ack 6, win 1024, options [nop,nop,TS val 332481 ecr 332480], length 0
22:01:00.026434 IP localhost.9877 > localhost.53342: Flags [P.], seq 1:6, ack 6, win 1024, options [nop,nop,TS val 332481 ecr 332480], length 5
22:01:00.026918 IP localhost.53342 > localhost.9877: Flags [.], ack 6, win 1025, options [nop,nop,TS val 332481 ecr 332481], length 0
22:01:30.425750 IP localhost.53342 > localhost.9877: Flags [F.], seq 6, ack 6, win 1025, options [nop,nop,TS val 340081 ecr 332481], length 0
22:01:30.430395 IP localhost.9877 > localhost.53342: Flags [F.], seq 6, ack 7, win 1024, options [nop,nop,TS val 340082 ecr 340081], length 0
22:01:30.432291 IP localhost.53342 > localhost.9877: Flags [.], ack 7, win 1025, options [nop,nop,TS val 340082 ecr 340082], length 0
从执行结果看,tcpdump中最后3个分组分别是客户端发给服务器的FIN,服务器发给客户端的FIN(捎带了ACK),客户端发给服务器的ACK。这3个分组还好理解,因为“套接口接收的来自对端的任何数据都被确认,然后悄悄丢弃”。但是为何最后客户端“normal termination”了呢?如果“套接口中不再有数据可接收”,那么为什么Select返回了并且检测到是sockfd可读呢?如果“进程不能再对这样的套接口调用任何读函数”,那么下面的Read为何读到了EOF而返回0呢?
请教大虾帮助!!!!
|
1.FIN包不算数据包,不会被丢弃。如果丢弃的话TCP连接就没法正常断开了
2.收到FIN包后,协议栈会设置相应sock为可读,但read会返回0表示EOF
3.shutdown只对本地socket数据的读写有影响,对正常的TCP协议流程没有影响
2.收到FIN包后,协议栈会设置相应sock为可读,但read会返回0表示EOF
3.shutdown只对本地socket数据的读写有影响,对正常的TCP协议流程没有影响
您可能感兴趣的文章:
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。