一、基于TCP协议的网络编程:
1、TCP协议:是一种面向连接的、可靠的、基于字节流的传输层通信协议
功能:
当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。之后TCP把数据包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。 TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。 在数据正确性与合法性上,TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和;同时可以使用md5认证对数据进行加密。 在保证可靠性上,采用超时重传和捎带确认机制。 在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。 在拥塞控制上,采用广受好评的TCP拥塞控制算法(也称AIMD算法)。该算法主要包括四个主要部分: (1)慢启动 每当建立一个TCP连接时或一个TCP连接发生超时重传后,该连接便进入慢启动阶段。进入慢启动后,TCP实体将拥塞窗口的大小初始化为一个报文段,即:cwnd=1。此后,每收到一个报文段的确认(ACK),cwnd值加1,即拥塞窗口按指数增加。当cwnd值超过慢启动阐值(sshterhs)或发生报文段丢失重传时, 慢启动阶段结束。前者进入拥塞避免阶段,后者重新进入慢启动阶段。 (2)拥塞避免 在慢启阶段,当cwnd值超过慢启动阐值(ssthresh)后,慢启动过程结束,TCP连接进入拥塞避免阶段。在拥塞避免阶段,每一次发送的cwnd个报文段被完全确认后,才将cwnd值加1。在此阶段,cwnd值线性增加。 (3)快速重传 快速重传是对超时重传的改进。当源端收到对同一个报文的三个重复确认时,就确定一个报文段已经丢失,因此立刻重传丢失的报文段,而不必等到重传定时器(RTO)超时。以此减少不必要的等待时间。 (4)快速恢复 快速恢复是对丢失恢复机制的改进。在快速重传之后,不经过慢启动过程而直接进入拥塞避免阶段。每当快速重传后,置sshtesrh=cwnd/2、ewnd=ssthresh+3。此后,每收到一个重复确认,将cwnd值加1,直至收到对丢失报文段和其后若干报文段的累积确认后,置cwnd=ssthesrh,进入拥塞避免阶段。TCP协议的功能
特点:
TCP是一种面向广域网的通信协议,目的是在跨越多个网络通信时,为两个通信端点之间提供一条具有下列特点的通信方式: (1)基于流的方式; (2)面向连接; (3)可靠通信方式; (4)在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销; (5)通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点。 为满足TCP协议的这些特点,TCP协议做了如下的规定 ①数据分片:在发送端对用户数据进行分片,在接收端进行重组,由TCP确定分片的大小并控制分片和重组; ②到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认; ③超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片; ④滑动窗口:TCP连接每一方的接收缓冲空间大小都固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出; ⑤失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层; ⑥重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据; ⑦数据校验:TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验和有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发TCP协议的特点
服务端:
import socket import struct sk=socket.socket() sk.bind(('127.0.0.1',8000)) sk.listen(5) conn, adder = sk.accept() # 等待客户端连接 while True: #sk.bind(('127.0.0.1', 8000)) # sk.listen(5) # conn,adder=sk.accept()#等待客户端连接 data=conn.recv(100) data=data.decode('utf8') print(data) server_data=input('>>>') l=len(server_data) res=struct.pack('i',l) # print(struct.unpack('i',res)[0]) conn.send(res) conn.send(server_data.encode('utf8'))server
客户端:
import socket import struct sk=socket.socket() sk.connect(('127.0.0.1',8000)) while True: client_len=b'' len1=0 client_data=input('>>>').encode('utf8') sk.send(client_data) # ret=sk.recv(2048).decode('utf8') k = sk.recv(4) k=struct.unpack('i',k) print(k) while len1<k: ret = sk.recv(100) len1+=len(ret) client_len+=ret print(ret.decode('utf8'))client
二、基于UDP协议:
UDP :为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法。
功能:
为了在给定的主机上能识别多个目的地址,同时允许多个应用程序在同一台主机上工作并能独立地进行数据包的发送和接收,设计用户数据报协议UDP。UDP使用底层的互联网协议来传送报文,同IP一样提供不可靠的无连接数据包传输服务。它不提供报文到达确认、排序、及流量控制等功能。 UDP Helper可以实现对指定UDP端口广播报文的中继转发,即将指定UDP端口的广播报文转换为单播报文发送给指定的服务器,起到中继的作用。 服务端:
import socket server=socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1',8080)) #server.listen(20) #ipp=('127.0.0.1',8000) while True: # n=input('>>>').encode('utf-8') #conn,adder=server.accept() date,adder=server.recvfrom(1024) date=date.decode('utf-8') print(date) #date=conn.recv(1024) if '你好' in date: server.sendto('好个鬼!!!'.encode('utf-8'),adder) else: n = input('>>>').encode('utf-8') # if date=='q': # break #else: # print(date.decode('utf-8')) #print(conn) #print(conn) #conn.send(n) server.sendto(n, adder) conn.close()sever端
客户端:
import socket client=socket.socket(type=socket.SOCK_DGRAM) id=(('127.0.0.1',8080)) while True: n=('2号:'+input('>>>')).encode('utf-8') client.sendto(n,id) date,adder=client.recvfrom(1024) date=date.decode('utf-8') if date=='结束': print('服务器终止了你的访问!') break else: print(date) client.close()client端