1.简介
1》 socket俗称“套接字”。用于网络编程客户端与服务器端的通信,计算机之间进行通信的一种约定或一种方式。基于TCP传输协议。
2》 利用三元组【ip地址,协议,端口】可以进行网络间通信,socket相当于网络通信过程的中间件工具。
3》 socket通信的数据传输方式:1. SOCK_STREAM,(面向连接,保证数据的正确性)2.SOCK_DGRAM(无连接,不作数据校验,但速度快)
2.TCP/IP协议
1.TCP(传输控制协议)和IP(网际协议),点对点链接机制,将OSI七层参考模型抽象为四层结构(联网淑用):
应用层:http,ftp,smtp,tftp…
传输层:tcp,udp
网络层:ip,icmp,igmp…
数据链路层:slip,ppp…
2.TCP数据包结构:
a.Seq序号,32位,标识传输中的数据包序号,客服都可发送。
b.Ack确认号,32位,标识确认信息,Ack=Seq+1.客户端服务器都可发送。
c.标志位:1位(bit),标识状态,分为6个:SYN(建立一个新连接)、FIN(断开一个链接)、ACK(确认号有效)、URG(紧急指针有效)、RST(重置链接)、PSH(接收方尽快将这个报文给应用层)
3.TCP建立连接三次握手
简述为:
C:服务器哥哥,我想建立连接!
S:收到客户端请求连接后)好的,我准备好了
C:谢谢大哥,我马上连接!
(1)当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置标志位SYN,同时生成一个随机序号“1000”标识该数据包。然后,向服务器发送数据包,客户端进入SYN-SEND状态。
(2)服务器收到数据包,检测到标志位SYN,知道这是建立连接的“请求包”,服务器也组建一个数据包,并设置SYN(标识用来建立连接)和ACK(确认收到客户端数据包),服务器随机生成数据包序号Seq(2000),并将客户端数据包序号(1000)+1,生成Ack“确认号”,发出数据包,进入SYN-RECV状态。
(3)客户端收到数据包,检测到SYN和ACK标志位,知道这是服务器发来的“确认包”,查看Ack序号是否为1000+1=1001,是说明建立连接成功。接下里,客户端组建数据包,设置ACK标志位,表示已收到服务器数据包的”确认包“,并件Ack确认号设置为2000+1=2001,发送给服务器,进入ESTABLISED状态。表明链接已经建立成功。
(4)服务器收到数据包,检测到ACK标志位,知道其为客户端发来的确认包,查看Ack字段是否为2000+1=2001,是表明建立连接成功。进入ESTABLISED状态。
至此,客户端和服务器都进入了ESTABLISED状态,连接建立成功,接下来就可以收发数据了。
4.断开连接四次握手
C:服务器哥哥,我想断开连接
S:好的,我准备一下
。。。。。
S:我准备好了,可以断开了。
C:谢谢大哥。
(1)客户端调用 close() 函数后,客户端组建数据包,并生成Seq5000,设置标志位FIN,发送给服务器,进入FIN-WAIT-1状态。
(2)服务器收到数据包,检测到FIN标志位,知道是断开连接数据包,服务器端设置ACK标志位,Ack字段5000+1=5001,Seq7000,发送给客户端”确认包“。进入CLOSE-WAIT状态。
注意:服务器收到请求后并不是立即断开连接,而是先向客户端发送“确认包”,告诉它我知道了,我需要准备一下才能断开连接
(3)客户端收到”确认包后“,直接进入FIN-WAIT-2状态,等待服务器准备完成后再次发送数据包。
(4)服务器端准备完毕后,组建数据包,设置标志位FIN,字段Seq7001,Ack5001,发送给客户端。表示可以断开连接了。进入LAST-ACK状态。
(5)客户端收到FIN包后,知道服务器已准备好,随机生成字段Seq5001,设置Ack7001+1=7002,设置标志位ACK,组件数据包后发送给服务器端,表明你断开吧。进入TIME-WAIT状态。
(6)服务器收到”ACK确认包“,断开连接,关闭套接字,进入CLOSED状态。
(7)数据包在网络中是有生存时间的,超过这个时间还未到达目标主机就会被丢弃,并通知源主机。这称为报文最大生存时间(MSL,Maximum Segment Lifetime)。TIME_WAIT 要等待 2MSL 才会进入 CLOSED 状态。ACK 包到达服务器需要 MSL 时间,服务器重传 FIN 包也需要 MSL 时间,2MSL 是数据包往返的最大时间,如果 2MSL 后还未收到服务器重传的 FIN 包,就说明服务器已经收到了 ACK 包。
5.断开连接
close()/closesocket() 会立即向网络中发送FIN包,不管输出缓冲区中是否还有数据,而shutdown() 会等输出缓冲区中的数据传输完毕再发送FIN包。也就意味着,调用 close()/closesocket() 将丢失输出缓冲区中的数据,而调用 shutdown() 不会。