学习了计算机网络的相关知识,下面我们来从网络编程的角度验证一下网络实际交互的数据是什么。下面的程序用C语言在Linux环境下编写而成。
先准备一个服务器端程序,任何连上它的客户端,它都给返回服务器当前时间,然后立刻主动关闭连接。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 | #include "unp.h"
#include <time.h>
int main(int argc, char** argv) {
	int listenfd, connfd;
	struct sockaddr_in servaddr;
	char buff[MAXLINE];
	time_t ticks;
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(10241);
	Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
	Listen(listenfd, LISTENQ);
	for (;;) {
		connfd = Accept(listenfd, (SA*)NULL, NULL);
		ticks = time(NULL);
		snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
		Write(connfd, buff, strlen(buff));
		Close(connfd);
	}
}
 | 
 
客户端程序,连接服务器并打印获取的内容:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 | #include "unp.h"
int main(int argc, char** argv) {
	int sockfd, n;
	char recvline[MAXLINE + 1];
	struct sockaddr_in servaddr;
	if (argc != 2)
		err_quit("usage: a.out <IPaddress>");
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(10241); // daytime server
	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);
	if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");
	while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
		recvline[n] = 0;// null terminate
		if (fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
	}
	if (n < 0)
		err_sys("read error");
	exit(0);
}
 | 
 
我们在Linux系统中编译得到两个可执行文件。开三个窗口,分别执行:
| 1
2
3
4
5
6
7
8
 | # 第一:启动Server
./UnpServer.out
# 第二:启动tcpdump监听,并将结果写入临时文件:
tcpdump -i lo -w time.tcpdump
# 第三:Client访问Server
./UnpClient.out 127.0.0.1
 | 
 
接下来将tcpdump监听的包日志文件 time.tcpdump下载到windows系统中。用包分析神器Wireshark分析,得到下面的结果:
     
如果我们直接看tcpdump的控制台日志,也是一样的:
     
啰嗦几句:
| 1
2
3
4
5
6
 | Flags表示包的状态标志
S=SYN:发起连接标志
P=PUSH:传送数据标志
F=FIN:关闭连接标志
.=ACK:表示确认或None
R=RST(RESET):重置连接
 | 
 
为什么主动关闭同时FIN+ACK
上面结果第6行,服务器端主动关闭连接。为什么发送的同时有FIN+ACK标志呢?
原因如下:TCP除了主动发起连接的第一个SYN包,ACK=0,其它所有TCP包都设置ACK= 1 标志位。《TCP/IP详解 卷1》中有这么一段话:
     
(完)