前言

虽然网络编程的socket大家很多都会操作,但是很多还是不熟悉socket编程中,底层TCP/IP协议的交互过程,本文会一个简单的客户端程序和服务端程序的交互过程,使用tcpdump抓包,实例讲解客户端和服务端的TCP/IP交互细节。

TCP/IP协议

IP头和TCP头格式如下:

Internet Header Format0                   1                   2                   3           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Version|  IHL  |Type of Service|          Total Length         |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|         Identification        |Flags|      Fragment Offset    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|  Time to Live |    Protocol   |         Header Checksum       |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                       Source Address                          |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Destination Address                        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Options                    |    Padding    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+TCP Header Format0                   1                   2                   3   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|          Source Port          |       Destination Port        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                        Sequence Number                        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Acknowledgment Number                      |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|  Data |           |U|A|P|R|S|F|                               || Offset| Reserved  |R|C|S|S|Y|I|            Window             ||       |           |G|K|H|T|N|N|                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|           Checksum            |         Urgent Pointer        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Options                    |    Padding    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                             data                              |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
struct tcphdr {__be16    source;__be16   dest;__be32 seq;__be32  ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)__u16  res1:4,doff:4,fin:1,syn:1,rst:1,psh:1,ack:1,urg:1,ece:1,cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)__u16   doff:4,res1:4,cwr:1,ece:1,urg:1,ack:1,psh:1,rst:1,syn:1,fin:1;
#else
#error  "Adjust your <asm/byteorder.h> defines"
#endif  __be16  window;__sum16  check;__be16    urg_ptr;
};
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)__u8   ihl:4,version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)__u8   version:4,ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif__u8  tos;__be16  tot_len;__be16  id;__be16   frag_off;__u8   ttl;__u8    protocol;__sum16    check;__be32    saddr;__be32    daddr;/*The options start here. */
};

source 发送 TCP 数据的源端口  
dest 接受 TCP 数据的目的端口  
seq 标识该 TCP 所包含的数据字节的开始序列号,正常情况下,每次的 seq 为上次的 seq 加上上次发送的数据字节数(数据字节数 =IP 包总长 -IP 头长 -TCP 头长)。
ack_seq 确认序列号 , 表示接受方下一次接受的数据序列号。以最后接收的 seq+ 接收的数据字节数。
doff 数据首部长度 . 和 IP 协议一样 , 以 4 字节为单位 . 一般的时候为 5 
urg 如果设置紧急数据指针 , 则该位为 1 
ack 如果确认号正确 , 那么为 1 
psh 如果设置为 1, 那么接收方收到数据后 , 立即交给上一层程序  
rst 为 1 的时候 , 表示请求重新连接  
syn 为 1 的时候 , 表示请求建立连接  
fin 为 1 的时候 , 表示亲戚关闭连接  
window 窗口 , 告诉接收者可以接收的大小(字节数)  
check 对 TCP 数据进行较核  
urg_ptr 如果 urg=1, 那么指出紧急数据对于历史数据开始的序列号的偏移值

单单看这些头会比较枯燥,后面会根据一个简单的客户端和服务端的TCP/IP报文交互实例讲解这些报文头的格式和含义

位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

Sequence number(顺序号码) Acknowledge number(确认号码)

• 目的端口:16位,分配给目的计算机上的应用程序的端口号。
    • 序号:32位,指出该数据帧在发送端数据流中的次序,这个字段在 TCP/IP三次握手方式期间也用于同步序列号。
    • 确认号:32位,该字段给发送主机指出目的主机希望接收的下一个帧的顺序号。TCP采用捎带技术,在发送数据的数据流中捎带对对方数据的确认,这样可以大大节省所传送的报文数。
    • 数据偏移量:4位,指出以32位为单位的报头的长度。使用数据偏移量,可以确定在TCP报文中数据的启始位置。
    • 保留:6位,留作将来使用的字段域。该字段域必须全部置为0。
    • 码位域:6位,用来指出数据的作用与内容。这6位作用分别为:
     第1位URG(紧急控制位):如果这位为1 ,“紧急指示码”字段将被阅读,并根据其内容进行相应的处理。
     第2位ACK(确认控制位):如果这位为1,则“确认号”字段的值减1后所代表的分组被确认。
     第3位PSH(重新启动控制位):如果这位为1,即告诉TCP软件,将迄今为止发送的所有数据通过管道推送到接收端的应用程序。
     第4位RST(重新启动控制位):如果这位为1,则TCP包请求连接重新启动。
     第5位SYN(同步控制位):如果这位为1,则指出该数据报中的顺序号应进行同步。
     第6位FIN(结束控制位):如果这位为1,则表示主机数据发送完毕,要求关闭连接。
    • 窗口:16位,用来通告接收端接收缓冲区的大小。即,该字段指定发送主机一次最多可以传输的报文的个数,亦即传送窗口的大小。
    • 校验和:16位,用来检验数据的正确性,通过校验和可以保证TCP报头和负载在传输中不被破坏。
    • 紧急指示码:16位,用于标明任何紧急信息的开始。
    • 任选项:可变长度,用来设定一小组选项设置中的一个。
    • 填充:可变长度,保证IP报头以32位为边界对齐。
    • 数据:可变长度,IP数据报有效负载(但不能超过最大传输单位)。
简单的客户端和服务端

客户端和服务端是我们写的一个简单客户端程序,运行在Linux上。

客户端和服务端的功能如下:
客户端从标准输入读入一行,发送到服务端
服务端从网络读取一行,然后输出到客户端
客户端收到服务端的响应,输出这一行到标准输出

服务端代码如下:

#include  <unistd.h>
#include  <sys/types.h>       /* basic system data types */
#include  <sys/socket.h>      /* basic socket definitions */
#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
#include  <arpa/inet.h>       /* inet(3) functions */#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>#define MAXLINE 1024
//typedef struct sockaddr  SA;
void handle(int connfd);int  main(int argc, char **argv)
{int     listenfd, connfd;int  serverPort = 6888;int listenq = 1024;pid_t   childpid;char buf[MAXLINE];socklen_t socklen;struct sockaddr_in cliaddr, servaddr;socklen = sizeof(cliaddr);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(serverPort);listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0) {perror("socket error");return -1;}if (bind(listenfd, (struct sockaddr *) &servaddr, socklen) < 0) {perror("bind error");return -1;}if (listen(listenfd, listenq) < 0) {perror("listen error");    return -1;}printf("echo server startup,listen on port:%d\n", serverPort);for ( ; ; )  {connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &socklen);if (connfd < 0) {perror("accept error");continue;}sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);printf(buf,"");childpid = fork();if (childpid == 0) { /* child process */close(listenfd);    /* close listening socket */handle(connfd);   /* process the request */exit (0);} else if (childpid > 0)  {close(connfd);          /* parent closes connected socket */} else {perror("fork error");}}
}void handle(int connfd)
{size_t n;char    buf[MAXLINE];for(;;) {n = read(connfd, buf, MAXLINE);if (n < 0) {if(errno != EINTR) {perror("read error");break;}}if (n == 0) {//connfd is closed by client
            close(connfd);printf("client exit\n");break;}//client exit
        if (strncmp("exit", buf, 4) == 0) {close(connfd);printf("client exit\n");break;}write(connfd, buf, n); //write maybe fail,here don't process failed error
    }
} 

客户端代码如下:

#include  <unistd.h>
#include  <sys/types.h>       /* basic system data types */
#include  <sys/socket.h>      /* basic socket definitions */
#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
#include  <arpa/inet.h>       /* inet(3) functions */
#include <netdb.h> /*gethostbyname function */#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>#define MAXLINE 1024void handle(int connfd);int main(int argc, char **argv)
{char * servInetAddr = "127.0.0.1";int servPort = 6888;char buf[MAXLINE];int connfd;struct sockaddr_in servaddr;if (argc == 2) {servInetAddr = argv[1];}if (argc == 3) {servInetAddr = argv[1];servPort = atoi(argv[2]);}if (argc > 3) {printf("usage: echoclient <IPaddress> <Port>\n");return -1;}connfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(servPort);inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr);if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {perror("connect error");return -1;}printf("welcome to echoclient\n");handle(connfd);     /* do it all */close(connfd);printf("exit\n");exit(0);
}void handle(int sockfd)
{char sendline[MAXLINE], recvline[MAXLINE];int n;for (;;) {if (fgets(sendline, MAXLINE, stdin) == NULL) {break;//read eof
        }/*//也可以不用标准库的缓冲流,直接使用系统函数无缓存操作if (read(STDIN_FILENO, sendline, MAXLINE) == 0) {break;//read eof}*/n = write(sockfd, sendline, strlen(sendline));n = read(sockfd, recvline, MAXLINE);if (n == 0) {printf("echoclient: server terminated prematurely\n");break;}write(STDOUT_FILENO, recvline, n);//如果用标准库的缓存流输出有时会出现问题//fputs(recvline, stdout);
    }
}

下载地址

编译服务器:

gcc echoserver.c -o echoserver

编译客户端

gcc echoclient.c -o echoclient

TCP/IP连接建立,交互,关闭

首先我们要启用tcpdump监控客户端和服务端的报文:

tcpdump -S -nn -vvv -i lo port 6888

-S 打印TCP 数据包的顺序号时, 使用绝对的顺序号, 而不是相对的顺序号

-nn 表示不进行端口到名称的转换

-vvv 表示产生尽可能详细的协议输出

-i lo表示只监控网卡lo设备,默认是监控第一个网络设备。

port 6888表示只监控端口6888的相关监控数据,包括从6888端口接收和从6888端口发送的报文。

tcpdump详情可以参考本博客的"Linux tcpdump命令详解"的tcpdump的简单选项介绍。

接着我们要启动服务端:

./echoserver

再启动客户端:

./echoclient 

建立连接

客户端程序一启动,就会connect服务端,tcpdump对应的输出如下:

13:27:45.927137 IP (tos 0x0, ttl  64, id 304, offset 0, flags [DF], proto: TCP (6), length: 60) 127.0.0.1.60534 > 127.0.0.1.6888: S, cksum 0x5f32 (correct), 2584692379:2584692379(0) win 32792 <mss 16396,sackOK,timestamp 10962859 0,nop,wscale 6>
13:27:45.927254 IP (tos 0x0, ttl  64, id 0, offset 0, flags [DF], proto: TCP (6), length: 60) 127.0.0.1.6888 > 127.0.0.1.60534: S, cksum 0x3648 (correct), 2589673026:2589673026(0) ack 2584692380 win 32768 <mss 16396,sackOK,timestamp 10962860 10962859,nop,wscale 6>
13:27:45.927265 IP (tos 0x0, ttl  64, id 305, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.60534 > 127.0.0.1.6888: ., cksum 0x1d6a (correct), 2584692380:2584692380(0) ack 2589673027 win 513 <nop,nop,timestamp 10962860 10962860>

这里是TCP连接的三握手的报文交互,其中协议各个字段的含义如下:

tos表示服务类型,4bit的tos分别表示最小时延,最大吞吐量,最高可靠性,最小费用。这里都是0,表示一般服务,其余4bit废用,置0.

TTL(time - to - live)生存时间字段设置了数据报可以经过的最多路由器数。它指定了数据报的生存时间。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机。
id 对应IP报文头的Identification,用于IP分片重组。

offset 也用于IP分片重组,表示相对于原始未分片的报文的位置。

flags MF表示有更多分片,DF表示不分片,这里是DF,未使用分片,所以id和offset的值都可以忽略。

proto 表示协议,可以是TCP,UDP等,这里是TCP。

length 总长度字段,是指整个I P数据报的长度(至于首部长度这里没有给出,首部长度给出首部中32 bit字的数目。需要这个值是因为任选字段的长度是可变的。这个字段占4 bit,因此TCP最多有60字节的首部。然而没有任选字段,正常的长度是20字节)。

127.0.0.1.60534 > 127.0.0.1.6888表示数据是从IP为127.0.0.1端口为60534发送到IP为127.0.0.1端口为6888。分别对应的IP报文头的源地址和目的地址,以及TCP报文头的源端口和目的端口。

S 当建立一个新的连接时,SYN标志变1。序号字段包含由这个主机选择的该连接的初始序号ISN(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个ISN加1,因为SYN标志消耗了一个序号,这里客户端的ISN是2584692379,服务端的ISN是2589673026。

chksum 16位检验和,这里有IP首部检验和和TCP报文段(包括TCP首部和数据)检验和,具体是哪个检验和不详。

2584692379:2584692379(0)表示,第一个2584692379表示TCP报文段的序列号,(0)表示数据长度是0,即没有数据,第二个2584692379是第一个2584692379+数据长度  计算出来的。TCP是可靠连接,三握手的最大目的是为了初始化双方的ISN。假设客户端连接服务端,发送数据,刚好网络比较慢,在传输过程中,客户端和服务端已经都重启了,重新建立连接发送数据,发送过程中,服务端收到已经之前客户端的数据,发现ISN非法,就会抛弃这个包,不会对现有的服务造成影响。这个只是ISN的一方面的作用。

win TCP窗口大小,通知对方,发送方最多还可以接收的数据量,用于TCP的拥塞控制。第一个报文表示客户端通知服务端,客户端可以接受的数据的缓存区最大是32792个字节。服务端通知客户端,服务端最多可以接受的缓存区最大是32768,这个窗口大小在一方接受数据,却没有read的时候,窗口会逐渐减小,直至为0,最后对方不可以发送任何数据(如果要做该测试,需要发送的数据量大概接近65535,因为窗口的缓存区也会在剩余容量减小时,自动增加总共容量,直到总共容量接近65535,接下来就会看到win越来越小,直至0)。

ack TCP是可靠连接,所以收到发送方的数据,接受方就会发送ack确认,告诉发送方,接受方已经接收到数据,否则,发送方认为数据没有发送成功,重复发送数据。第二个包有ack 2584692380,其中2584692380是第一个报文包的2584692379:2584692379(0)的第二个2584692379+1的值。

<mss 16396,sackOK,timestamp 10962859 0,nop,wscale 6>这里表示IP报文头的可选字段,mss是最小最大分段大小,这里是16396,表示一个TCP报文段发送的数据最大可以是16396个字节,可能是lo设备的关系,这个mss很大,一般都是MTU 1500 个字节 - IP数据报文头20个字节- TCP报文头20个字节 = 1460个字节。wscale是TCP窗口扩大选项的窗口扩大因子,用于扩大TCP通告窗口,使TCP的窗口定义从16bit增加为32bit。这里的wscale是6,那么实际窗口是513左移6位,既513 X 64 = 32832,这个选项只在一个SYN报文中有意义。其他选项不详,具体参考RFC。

交互

建立连接之后,我们通过客户端分别发送a和123到服务端,客户端后台显示如下:

[root@localhost simpletcpip]# ./echoclient
welcome to echoclient
a
a
123
123

tcpdump对应的输出是:

13:27:48.248592 IP (tos 0x0, ttl  64, id 306, offset 0, flags [DF], proto: TCP (6), length: 54) 127.0.0.1.60534 > 127.0.0.1.6888: P, cksum 0xfe2a (incorrect (-> 0xb344), 2584692380:2584692382(2) ack 2589673027 win 513 <nop,nop,timestamp 10965181 10962860>
13:27:48.248739 IP (tos 0x0, ttl  64, id 495, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.6888 > 127.0.0.1.60534: ., cksum 0x0b47 (correct), 2589673027:2589673027(0) ack 2584692382 win 512 <nop,nop,timestamp 10965181 10965181>
13:27:48.249061 IP (tos 0x0, ttl  64, id 496, offset 0, flags [DF], proto: TCP (6), length: 54) 127.0.0.1.6888 > 127.0.0.1.60534: P, cksum 0xfe2a (incorrect (-> 0xaa32), 2589673027:2589673029(2) ack 2584692382 win 512 <nop,nop,timestamp 10965181 10965181>
13:27:48.249085 IP (tos 0x0, ttl  64, id 307, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.60534 > 127.0.0.1.6888: ., cksum 0x0b43 (correct), 2584692382:2584692382(0) ack 2589673029 win 513 <nop,nop,timestamp 10965182 10965181>
13:27:49.544830 IP (tos 0x0, ttl  64, id 308, offset 0, flags [DF], proto: TCP (6), length: 56) 127.0.0.1.60534 > 127.0.0.1.6888: P, cksum 0xfe2c (incorrect (-> 0xa1eb), 2584692382:2584692386(4) ack 2589673029 win 513 <nop,nop,timestamp 10966477 10965181>
13:27:49.544987 IP (tos 0x0, ttl  64, id 497, offset 0, flags [DF], proto: TCP (6), length: 56) 127.0.0.1.6888 > 127.0.0.1.60534: P, cksum 0xfe2c (incorrect (-> 0x9cd8), 2589673029:2589673033(4) ack 2584692386 win 512 <nop,nop,timestamp 10966477 10966477>
13:27:49.545010 IP (tos 0x0, ttl  64, id 309, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.60534 > 127.0.0.1.6888: ., cksum 0x011c (correct), 2584692386:2584692386(0) ack 2589673033 win 513 <nop,nop,timestamp 10966477 10966477>

第一个报文是客户端给服务端发送了一个a数据,P表示push标志,发送方使用该标志通知接收方将所收到的数据全部提交给接收进程。这里的数据包括与PUSH一起传送的数据以及接收方TCP已经为接收进程收到的其他数据。长度为54是因为a数据后面还有一个\n(输入a然后回车导致的),所以是2个字节,比正常情况下没有数据的52个字节多了2个字节。

第二个报文是服务端接受了a数据后,发送给客户端的ack确认。

第三个报文和第四个报文分别是服务端发给客户端的回显a,以及客户端的ack确认。

第五个报文是客户端给服务端发送了123数据。

第六个报文,是服务端给客户端发送回显123,同时合并了对客户端的ack确认。

第七个报文是客户端对服务端的回显123数据的ack确认。

关闭连接

直接在客户端的控制终端执行Ctrl+C结束客户端程序,就可以关闭TCP连接,tcpdump输出如下:

13:38:10.081895 IP (tos 0x0, ttl  64, id 310, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.60534 > 127.0.0.1.6888: F, cksum 0x897d (correct), 2584692386:2584692386(0) ack 2589673033 win 513 <nop,nop,timestamp 11586913 10966477>
13:38:10.081987 IP (tos 0x0, ttl  64, id 498, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.6888 > 127.0.0.1.60534: F, cksum 0x11e0 (correct), 2589673033:2589673033(0) ack 2584692387 win 512 <nop,nop,timestamp 11586913 11586913>
13:38:10.081993 IP (tos 0x0, ttl  64, id 311, offset 0, flags [DF], proto: TCP (6), length: 52) 127.0.0.1.60534 > 127.0.0.1.6888: ., cksum 0x11df (correct), 2584692387:2584692387(0) ack 2589673034 win 513 <nop,nop,timestamp 11586913 11586913>

关闭的请求由客户端发出,第一个报文是客户端发给服务端,F表示Fin,发送关闭连接请求。这个关闭连接请求是由于客户端退出,操作系统回收客户端资源,自动发出的。当然,如果我们在客户端输入Ctrl+D,最后执行close(connfd),关闭连接请求的报文就会发送。

第二个报文是服务端发给客户端的关闭连接请求,当客户端关闭连接是,服务端处理客户端请求的handle函数中

if (n == 0) {//connfd is closed by client
            close(connfd);printf("client exit\n");break;
}

执行close(connfd),对应的第二个报文就会发送。

第三个报文只是客户端对服务端的关闭连接请求报文的确认。

总结

本文基于tcpdump和一个简单的客户端和服务端,实例讲解了TCP/IP协议,不止有协议的含义,而且有TCP/IP连接的建立,交互,关闭的一些细节。由于篇幅和tcpdump的输出问题,未能将IP协议和TCP协议的报文头的每个字段含义都讲解一次,如果大家希望可以进一步了解,可以参考RFC 791 - Internet Protocol和RFC 793 - Transmission Control Protocol,还有TCP/IP协议卷一的相关内容。

基于tcpdump实例讲解TCP/IP协议相关推荐

  1. 通过连接实例解读TCP/IP协议

    通过连接实例解读TCP/IP协议 最近狂补基础,猛看TCP/IP协议.不过,书上的东西太抽象了,没有什么数据实例,看了不 久就忘了.于是,搬来一个sniffer,抓了数据包来看,呵呵,结合书里面得讲解 ...

  2. TCP/IP协议——TCP/IP协议栈及框架

    TCP/IP协议同ISO/OSI模型一样,也可以安排成栈形式.但这个栈不同于ISO/OSI版本,比ISO/OSI栈少,所以又称之为短栈.另外,需要知道的是:TCP/IP协议栈只是许多支持ISO/OSI ...

  3. 程序员必知必会网络传输之TCP/IP协议族,共864页的详解文档让你原地起飞!

    我们现实网络无处不在,我们被庞大的虚拟网络包围,但我们却对它是怎样把我们的信息传递并实现通信的,我们并没有了解过,那么当我们在浏览器中出入一段地址,按下回车这背后都会发生什么? 比如说一般场景下,客户 ...

  4. 第一章 TCP/IP 协议

    作者简介:一名云计算网络运维人员.每天分享网络与运维的技术与干货.   座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.什么是TCP/IP ​编辑 二.什么是协议 1. ...

  5. linux中tcp/ip协议实现及嵌入式应用 下载,LINU中TCPIP协议实现及嵌入式应用

    好文网为大家准备了关于LINU中TCPIP协议实现及嵌入式应用范文,好文网里面收集了五十多篇关于好LINU中TCPIP协议实现及嵌入式应用好文,希望可以帮助大家.更多关于LINU中TCPIP协议实现及 ...

  6. 基于C#的TCP/IP协议应用(一)

    一.背景与概念 1.标准以太网 以太网是美国Xerox(施乐)公司的Palo Alto研究中心于1975年研制成功的,其核心技术起源于ALOHA网.目前以太网是指符合IEEE 802.3标准的局域网( ...

  7. zynq tcp如何从网口发数据_基于TCP/IP协议的电口通信

    之前有介绍过TCP/IP协议的实现是通过轻量级LWIP协议实现的,具体在FPGA中实现又可以分为多种方式,具体如下: 图8‑98 LWIP协议在FPGA中的实现方式 LWIP可以通过硬核实现或者软核实 ...

  8. 基于TCP/IP协议 区别 GET和POST

    基于TCP/IP协议讲解GET和POST的区别(转载于博客园) 在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象.但是如果路上跑的全是看起来一模一样的汽 ...

  9. 基于TCP/IP协议的网络摄像头的QT项目

    目录 项目简述: 1.服务器 步骤一:首先搭建一个基本的服务器框架. 1.初始化服务器的函数主体 2.等待连接 步骤二:数据库的使用,本次项目使用的Sqlite3数据库 1.数据库初始化 2.登录时使 ...

最新文章

  1. 玩转Parse(第一篇:新手入门)
  2. SQL数据库常见故障及解决方法
  3. ClickHouse【环境搭建 02】设置用户密码的两种方式(明文+SHA256)及新用户添加及只读模式 Cannot execute query in readonly mode 问题解决
  4. Andriod开发中正确引入jar包的方式
  5. BookSmart Self Publishing
  6. java接口自动化Excel占位符_基于maven+java+TestNG+httpclient+poi+jsonpath+ExtentReport的接口自动化测试框架...
  7. SQL Server高级数据库管理员面试问答
  8. intellij idea 忽略文件不提交
  9. jsdroid 教程_南方Cass专题,全系列教程+插件汇总打包
  10. 中国各省级行政区公共数据开放平台网址(2021.11.1更新)
  11. 如何关闭电脑弹窗(2种方法)
  12. opencv 物体尺寸测量
  13. 熟女给老实木讷男孩的恋爱建议(转帖)
  14. ONFI ZQ Calibration
  15. Windows进程小结
  16. 面试完还呗、拼多多、蚂蚁金服、趣头条、京东到家之后,我知道了这些
  17. TIM微秒级计时学习笔记
  18. DeFi之道丨两种衍生品策略教你对冲DeFi头寸风险
  19. 虚拟机 ubuntu 16 安装caffe CPU版本 安装open pose
  20. 请问机器学习算法岗中用户增长和推荐系统差别是什么呢?

热门文章

  1. matlab ascii 异或,GPS数据包的ASCII异或校验和计算方法(VC++)
  2. ORCLE分组后取出时间最近的一条
  3. python使用pillow下载网络图片到本地预览
  4. lc滤波电路电感电容值选择_电感器变压器选型与应用
  5. tplink迷你路由器中继模式_斐讯无线路由器设置无线中继(无线扩展)
  6. Java并发编程——线程带来的风险
  7. 后台MemoryStream图片流用ajax接收乱码问题
  8. SQL Server索引总结二
  9. HTML5 学习总结(二)——HTML5新增属性与表单元素
  10. wget命令3(转载)