网络通信-TCP

TCP协议简介
  • TCP协议,传输控制协议,是一种面向连接的、可靠的、基于字节流的传输通信协议,是IETE的RFC793定义
  • TCP传输数据的主要三步骤为:创建连接、数据传送、终止连接;
TCP传输的主要特点
  •  面向连接
    • TCP通信的过程一定要遵守:创建、收发、断开连接的过程,双方一定要先建立了连接且分配了必要的系统内核资源才能实现通信;
    • 通信的方式的一对一传播(单播)
    • 通信的双方在通信时都占用了系统能的一定资源保持连接,所以不再使用时一定要关掉
  • TCP传输的可靠性
    • 每次发送数据(报文段)会有应答,发送方得到应答才算发送成功
    • 每次发送数据(报文段)都会定时收应答,如果超时就重传
    • 每次发送数据(报文段)都有一个特定编号, 对方在收到后按照编号顺序重组数据即可,不会存在发送数据的顺序错乱
    • 每次发送数据(报文段)中都有一个校验和, 如果在传输过程中损坏了可以校验出来就重传
    • TCP有一套控制网络拥塞的机制不断调整找到一个尽可能高效的速度,避免主机发送的过快而使接收方来不及完全收下数据
TCP通信模型
使用TCP套接字     TCP-传输控制协议(客户端)
  • 创建/销毁TCP套接字
    • 创建流程
      • import socket
      • tcp_socket = socket.socket(socket.AF_INIT, socket.SOCK_STREAM)
      • tcp_socket.close( )
        • AF_INET 表示 IPv4协议
        • SOCK_DGRAM 表示传输控制协议
    • 注意点:
      • TCP的客户端和服务端创建socket的意义不一样,客户端创建的socket用于连接服务器端-通信-关闭,在服务器端创建的socket主要用于接收客户端的连接请求; 
      • 当socket关闭后会给服务器端发送一个字节长度为0的字节码,可以用来让服务器判断客户端关闭了连接,同时服务器也做响应的关闭操作
  • 连接服务器端 connect(具体建立连接的细节清参考下面三次握手规则)
    • sock.connect(address)
      • address是远程套接字地址(地址,端口)构成的元组
      • 成功之后便可以通信
  • TCP发送/接收数据
    • socket.send(data)
      • data为bytes类型
      • 返回值为已发送的字节数
      • 在send进行发送数据的时候,由于网卡的缓存一般为10M左右,所以当发送的数据太大的时候,网卡一次缓存的数据可能还没有文件本身的大,所有网卡发送一次数据后没有将所有的数据内容都进行发送,所以需要用循环来发送大型一点的数据,防止数据一次没有发送完成
    • socket.recv(bufsize)    ----->data
      • recv会默认阻塞等待,直到收到数据
      • bufsize 表示可以接收到的数据最大字节长度,建议设置为2的整数次方大小
      • data 返回值,表示接收到的数据  <bytes类型>
使用TCP套接字     TCP-传输控制协议(服务器端)
  • 创建/销毁TCP套接字并将套接字和(IP,端口)进行绑定
    • 创建流程
      • import socket
      • tcp_socket = socket.socket(socket.AF_INIT, socket.SOCK_STREAM)
      • socket_obj.bind(address)
    • 注意点:
    • 有时候会出现端口被占用导致TCP-SOCKETbind失败问题
      • 主要原因:
        • server主动关闭进程(同时关闭TCP连接),导致TCP变为CLOSE_WAIT状态2MSL X分钟内不能再使用该socket相关PORT
      • 解决方案:
        • 需要在listen调用之前设置
        • tcp_socket_obj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    避免因为2MSL的问题导致不能在2MSL时间内不能使用同一个端口
  • 将TCP套接字设置为监听状态--listen
    • 作用:
      • 将socket变为被动监听模式使套接字可以accept接收客户端的connet请求,在服务器端如果不listen直接进行下一步会报错。
    • 设置过程
      • socket_ob.listen(backlog)
        • backlog参数在不同OS上含义不同,经验值128
  • 接收一个客户端用户--accept  (具体建立连接的细节清参考下面三次握手规则)
    • 作用:从已经完成三次握手的套接字列队中取出一个客户,如果暂时没有客户,会阻塞等待
      • tcp_socket, address = socket_obj.accept()
        • 返回值: (tcpsocket,(IP,端口))
        • tcpsocket为返回的创建的一个用于和该客户端通信的clien_socket,每个客户端连接都会创建一个对应的tcpsocket
        • tcpsocket被销毁(引用计数为0),则表示对客户端服务已经完成
  • TCP发送/接收数据
    • tcpsocket.send(bytes)
      • bytes 为发送的数据,数据类型为bytes类型
      • 返回值为已发送的字节数
    • tcpsocket.recv(bufsize)    ----->data
      • bufsize 表示可以接收到的数据最大长度,建议设置为2的整数次方大小
      • data 返回值是接收的数据,数据类型为  <bytes类型>
备注:TCP socket的注意点
  • 在使用多进程时,若将socket传递个体子进行进行处理,socket在子进程中会复制一份实例,所以在关闭socket的时候需要注意,要同时关闭子进程和主进程中的socket才能将socket彻底释放
TCP 建立连接和断开连接的规则(三次握手/四次挥手)
  • TCP的建立连接 (三次握手)
    • 握手前(服务器端为listen状态):服务器端首先客户端和服务端要创建socket,并且服务端绑定端口变为listen状态
    • 第一次握手(客户端SYN_SEND状态):客户端发起SYN包到服务器,进入SYN_SEND状态,进入服务器端连接等候列队,等待服务器的确认;
    •  第二次握手(服务器端SYN_RCVD状态):如果服务器端已经建立连接列队有空余,服务端会像客户端发起第二次握手,服务器会先确认客户端发过来的SYN包,并 同时也返回一个SYN包并回复一个ACK,服务器端变为SYN_RCVD状态;
    • 第三次握手(ESTABLISHEDED状态):客户端接收到服务端返回的两个包后,向服务器发送确认包,待服务器手到ACK包后,双方建立了TCP连接,双方切换到ESTABLISHED状态
  • TCP断开连接 (四次挥手)
    • 第一次挥手(主动端为FIN_WAIT_1状态):主动端关闭socket发起关闭连接消息,并且发送FIN数据段给被动端,进入FIN_WAIT_1状态;
    • 第二次挥手(被动端为CLOSE_WAIT状态;主动端FIN_WAIIT_2状态):被动端收到FIN段后,会返回主动端一个确认ACK包,证明收到了主动端的关闭通知,并关闭读通道,进入CLOSE_WAIT状态,既还可以进行写数据; 主动端接收到ACK确保包后,会关闭写通道,进入FIN_WAIT_2状态;
    • 第三次挥手(被动端LAST_ACK状态):被动端发送完数据之后,会发送一个FIN数据段,表示写入完成,并进入LAST_ACK状态;
    • 第四次挥手(主动端TIME_WAIT状态):主动端收到消息后会再返回给被动端一条ACK确认段,并关闭读通道,进入TIME_WAIT状态;  被动端接收到ACK确认段后会关闭写通道;
    • **备注:
UDP及TCP的区别
  • UDP
    • 是面向无连接的通讯协议,数据包括目的端口号和源端口号信息。
    • 优点:UDP速度快、操作简单、需要系统资源较少,由于通讯不需要连接,可以实现广播发送。
    • 缺点:UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,也不用重发,不可靠。
  • TCP
    • 是面向连接的通信协议,通过三次握手建立连接,通讯完成时四次挥手。
    • 优点:TCP在数据传递时,有确认、编号、重传、拥塞控制等机制,能保证数据正确性,较可靠。
    • 缺点:TCP相对于UDP速度慢一点、要求系统资源较多。













刘小恺(Kyle) wechat
如有疑问可联系博主