转载: http://blog.csdn.net/highfly591/article/details/45365355
网络编程:要以多线程异步的方式来考虑问题。
比如我用tcp发送数据包的时候:一般定义包头,和包体的方式
包头中一般包括:
包头的特殊字段(magic):用来指明包头的开始(定义好之后,包头一定要是固定长度,又用取到完整长度的包头)。主要是防止粘包。
比如在接受方读取数据的时候,一个半的数据包己经到达,一个通过特殊字段可以判断我数据开始就是包头,第二个是我可以得到后边的半包的开始。如果我包头和包体封装到一块,数据长度就不确定,我要是全部取出来,岂不是认为我这一个半的数据包就是一个数据包。解析就是有问题的
sequence字段:这个用于标识发送的数据包的序列号
比如我异步多线程方式发送数据,每一个数据包有一个sequence,在我发送过去到服务器之后,由于一般我的每个包的功能不一样,解析不同,执行的功能不同,所以我反馈给前端的信息的时间先后不一样,这样我怎么知道我这个反馈信息是我那个请求的反馈。就是通过sequence
在比如我同一个命令控制字段,发送了多个(3个)请求数据包,由于服务器反馈回你的信息的系列不确定,假如服务器解析两个正确一个不正确,反馈回去之后,光有命令控制字段,也不能判断是那个正确,那个错误. (觉得这里可以类似: TCP 三次握手中序列号的使用方法; 它的底层通信序列号的使用办法. 发送端和接收端各维护自己的一个序列号, 用于主动发送数据包; 同时给对端应答回复时, 使用接收到的对端数据包序列号.)
命令控制字:用来标识这段数据的功能用途。
包体的信息长度:用于指明包体的长度。
一般情况下是包体和包头一块发送,接收的时候(先读包头,正确,再读包体),是先读取完整的包头(因为的固定的长度,所以可以取到完整的包头)。解析包头里边的包体长度,和crc校验值。然后通过包体长度。在读取包体,crc校验值的比较,判断包体是否正确,如果不正确,就直接丢弃。如果正确,再按照获得的包体长度读取完整的包体信息。
包体信息的crc校验值字段:主要是为了保证我传输过来的数据是正确的。传输过来的数据在本地做一个crc校验,然后和这个校验值比较,如果一样,说明数据是正确的。
自己认为重要的包体的信息:自己定义
二.TCP底层通信协议序列号的使用方法
建立连接后,两台主机就可以相互传输数据了。如下图所示:
![](http://c.biancheng.net/cpp/uploads/allimg/151105/1-15110510394G48.jpg)
图1:TCP 套接字的数据交换过程
上图给出了主机A分2次(分2个数据包)向主机B传递200字节的过程。首先,主机A通过1个数据包发送100个字节的数据,数据包的 Seq 号设置为 1200。主机B为了确认这一点,向主机A发送 ACK 包,并将 Ack 号设置为 1301。
为了保证数据准确到达,目标机器在收到数据包(包括SYN包、FIN包、普通数据包等)包后必须立即回传ACK包,这样发送方才能确认数据传输成功。
此时 Ack 号为 1301 而不是 1201,原因在于 Ack 号的增量为传输的数据字节数。假设每次 Ack 号不加传输的字节数,这样虽然可以确认数据包的传输,但无法明确100字节全部正确传递还是丢失了一部分,比如只传递了80字节。因此按如下的公式确认 Ack 号:
Ack号 = Seq号 + 传递的字节数 + 1
与三次握手协议相同,最后加 1 是为了告诉对方要传递的 Seq 号。
下面分析传输过程中数据包丢失的情况,如下图所示:
![](http://c.biancheng.net/cpp/uploads/allimg/151106/1-151106134A4196.jpg)
图2:TCP套接字数据传输过程中发生错误
上图表示通过 Seq 1301 数据包向主机B传递100字节的数据,但中间发生了错误,主机B未收到。经过一段时间后,主机A仍未收到对于 Seq 1301 的ACK确认,因此尝试重传数据