学习了计算机网络的相关知识,下面我们来从网络编程的角度验证一下网络实际交互的数据是什么。下面的程序用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分析,得到下面的结果:

image-20210812164710169

如果我们直接看tcpdump的控制台日志,也是一样的:

image-20210812173026827

啰嗦几句:

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》中有这么一段话:

image-20210812174500375

(完)