TCP数据交换

从连接到断开整个过程中,数据交换是我觉得最复杂的一个模块。在这里我简单描述一下在局域网中成块数据块流收发的过程。

首先,发送方从缓存里面读取数据。并不是一收到数据就马上发送,而是根据恰当的时间对数据进行发送(长度优先和时间优先)。开始发送数据时,因为在连接的过程中就知道接收方的窗口大小,所以发送方会一次发送一个或多个数据包,但是发送的数据不会超过窗口的大小(发送方可以自行计算)。接收方一接收到数据后,也不是马上发送确认包,而是会等待一段时间,如果有数据,那么数据包和确认包将一起发送过去。否则只发送确认包。收到确认包后,接收方的窗口右边往右移动。数据收发中,不断重复这个过程,直到数据收发结束。从整个收发的过程中看出,增大接收方的窗口大小一定程度上能够提高TCP的吞吐量,从而提高整个数据收发的效率。

数据收发窗口变化图

TCP/IP断开

在TCP/IP数据收发的过程中,这个过程是双向的,如果先完成数据发送的一方主动断开TCP/IP连接,例如A和B通讯,A先发送完数据,那么A先主动断开,这时A会发送一个FIN给B,A进入FIN_WAIT1。B接收到A发送过来的数据包后,进入了CLOSE_WAIT(被动关闭)。如果此时B还在收发数据,那么B会发送一个ACK确认报给A,A收到确认报后进入FIN_WAIT2,这也就是所谓的TCP的半关闭。直到B完成数据的收发,B发送一个FIN给A,此时B进入LAST_ACK状态,等待A发送ACK。A收到数据包之后,向B发送一个ACK,同时A进入TIME_WAIT状态,也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL。为什么这个时间是2MSL呢,其实这个时间设置成2MSL,主要是确认ACK是否丢失。因为B如果在一定的时间内没有收到A发送的确认数据包的话,会重新发送fin。B收到A发送的确认数据包之后,B进入的初始状态。由于A在内存中记录了IP、端口号的使用情况。在A处于TIME_WAIT状态时,直到TIME_WAIT结束时候,端口才能重新被使用。

在断开阶段也有可能会遇到同时断开的情况。A和B同时主动断开。A和B都发送FIN给对方。双方接收到对方发送的FIN数据包后,都向对方发送ack数据包。由于双方都是主动断开因此双方都进入TIME_WAIT状态,直到状态结束IP、端口才能重新被使用。

TCP/IP连接

在TCP连接的过程中,实际上是一个交换控制信息的过程。首先,客户端发送连接请求到服务器。客户端发送请求的数据包

SYN=1 表示这是一个连接请求,

seq=cx,cx表示一个随机数,这样做的目标是考虑到安全性,防止被攻击。

win=cy,cy表示窗口的大小,用于后期数据收发,不需要发送方发送一个数据包就进入等待状态。

mss=cz,cz表示数据最大的接受的长度(可以通过MTU和头部计算得出)


服务器端接受客户端发送的连接请求后,服务器的连接被动打开。此时,服务器发送一个确认数据包。

ack=cx+1,该标识位表示已经收到刚才客户端发送过来的数据包,

syn=1,表示服务器向客户端发送连接请求。

seq=sx,sx也是一个随机数,作用跟客户端是一样的

win=sy,表示服务器端窗口的大小

mass=sz,sz表示数据最大的接受的长度(可以通过MTU和头部计算得出)


客户端接收到服务器端的连接请求后,也发送一个确认包

ack=sx+1,该标识位表示已经收到刚才服务器发送过来的数据包

seq=cx+1

win=cy,此时窗口的大小

到此,整个连接阶段就已经完成。其实在连接的过程中主要是对控制信息的交换

mysql中char和varchar

在MySQL中,char和varchar是两种非常常见且非常重要的字符串类型,MySQL不同存储引擎对其在磁盘和内存的处理方式不一样。

varchar

varchar类型是属于可变长类型,相对来说比char类型更节省空间,因为varchar只使用必要的空间(Row_FORMAT=FIXED是个特殊情况)。但是varchar需要额外的字节记录字符长度。如果列的最大长度小于或等于255个字节,需要一个字节来记录长度,超过255个字节需要额外2个字节。

以下情况适合使用varchar

字符串列的最大长度比平均长度达很多

列更新很少(碎片很少)


char

char是定长类型,MySQL总是根据定义字符串长度分配足够的空间。

以下情况适合使用char

char值适合存储很短的字符串,或者接近值长度的字符串。

对于经常变更的数据,char比varchar好,因为char类型不容易产生碎片。

对于非常短的列,char比varchar在存储空间上也更有效率。


内存上的比较

MySQL通常会分配固定大小的内存来保存内部值。


总结

varchar(1)和varchar(100)存储’y’在存储空间是一样的。但是varchar(100)会占用更大的内存,在这种情况下,如果数据量非常大,varchar(1)性能会比varchar(100)好很多。如果这时候对临时表进行排序时会更加明显,如果是机械磁盘的话,需要响应的时间会更久。

以上比较是基于innodb

HTTP从请求到响应

    用户通过浏览器提交请求后,首先浏览器会先解析URL,通过URL获取到相关的信息后,如目资源文件以及目标服务器,生成对应的HTTP请求消息。由于浏览器不具备发送数据包的功能,所以浏览器只能通过操作系统来实现。因此在委托服务器发送数据包之前,还需要知道服务器的IP地址。于是整个过程进入了域名解析阶段。

    在域名解析阶段中,因为浏览器已获取域名,于是委托操作系统对域名进行解析,操作系统发送UDP请求对域名进行解析,最后将域名解析成IP。到此为止,域名解析过程结束,整个过程进入数据收发环节。

tcpip连接到断开

    在数据收发的整个环节里,浏览器委托操作系统的协议栈对数据进行收发。首先是连接阶段,也就是三次握手,首先客户端向服务器端发送连接请求,服务器端发送一个确认包,客户端收到服务器的确认包后,发送一个确认包到服务器,在这个过程中,客户端和服务器端进行了端口、ip、窗口等信息的交换。至此,连接阶段就已经结束了,整个过程进入数据收发阶段。

tcpip连接到断开

    在数据收发阶段,并不是协议栈收到数据就马上发送出去的,而是数据被发送到缓冲区等待应用层的下一段数据。协议栈会考虑到多方面的因素来进行收发操作(长度优先或者时间优先)。对于较大的数据,会先把数据拆分出来,放进单独的数据包中。收发数据时,一般采用滑动窗口方式,由于在连接阶段已经知道对方的窗口大小,发送方会根据窗口大小发送数据,接收方会根据恰当的时间发送确认包,这个过程持续到数据收发完成,最终数据收发阶段结束,进入连接断开阶段。

tcpip数据收发和断开

    在连接断开阶段,发送一个断开请求的数据包,客户端发送一个确认断开数据包,然后客户端接受完数据后也发送一个断开请求的数据包,服务器发送一个确认断开数据包,然后断开连接,到此整个通讯的过程就结束了。