Python中的网络编程
B/S与C/S
- S :Server 服务器端
- C :Client 客户端
- B :Browser 浏览器
互联网协议
-
TCP
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠 的、基于字节流的传输层通信协议。(注:摘自百度百科)
-
三次握手
-
四次挥手
客户端主动向服务端发送断开请求,服务器发送消息代表已不再接收客户端消息。
服务端等待传输任务结束后向客户端发送断开请求,客户端响应消息同时服务端我们断开连接,这个时候客户端会进入一个计时等待时间,假如这个时候服务端又发送了一条断开的消息,这个时候就说明之前发送的消息服务器没有收到,客户端就会再次发送断开响应。直到客户端在计时等待的时候没有收到服务端的消息了,那么客户端就可以关闭连接了。
-
-
UDP
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种 无连接 的传输层协议,提供面向事务的简单 不可靠 信息传送服务。(注:摘自百度百科)
Python基于TCP与UDP的网络编程
-
TCP
-
客户端
import socket soc=socket.socket() soc.connect(('127.0.0.1',8080)) soc.send('hello hello'.encode()) data=soc.recv(1024) print('我收到服务端回的',data.decode()) soc.close()
-
服务端
import socket soc=socket.socket() soc.bind(('127.0.0.1',8080)) soc.listen(5) conn,addr=soc.accept() data=conn.recv(1024) print('我收到客户端发的',data.decode()) conn.send(data.decode().upper().encode()) conn.close() soc.close()
-
-
UDP
-
客户端
import socket s = socket.socket(type=socket.SOCK_DGRAM) s.sendto('hello world!'.encode(),('127.0.0.1',8080)) print('收到服务端消息',s.recvfrom(1024)[0].decode()) s.close()
-
服务端
import socket s = socket.socket(type=socket.SOCK_DGRAM) s.bind(('127.0.0.1',8080)) data = s.recvfrom(1024) print('收到客户端消息', data[0].decode()) s.sendto(data[0].decode().upper().encode(), data[1]) s.close()
-
TCP的粘包问题
只有TCP有粘包现象,UDP永远不会粘包,因为TCP是基于 数据流 的协议,而UDP是基于 数据报 的协议
为什么会发生粘包问题
因为接收方不知道消息与消息之间的界限,不知道一次性接收多少字节的数据所造成的。
如何解决粘包问题
模拟UDP的数据报形式
-
服务端
import socket import struct import json soc = socket.socket() soc.bind(('127.0.0.1', 8080)) soc.listen(5) conn, addr = soc.accept() s_bytes = 'Hello Client!'.encode() # 创建头字典,将数据长度保存到字典中 dic = {'size': len(s_bytes)} # 将字典转成bytes格式 dic_bytes = (json.dumps(dic)).encode() # head_count是4个字节的长度 head_count = struct.pack('i', len(dic_bytes)) # 发送同步信息长度 conn.send(head_count) # 发送头部内容 conn.send(dic_bytes) # 发了内容 conn.send(s_bytes) conn.close() soc.close()
-
客户端
import socket import struct import json s = socket.socket() s.connect(('127.0.0.1', 8080)) # 头部字典长度固定4字节 dic_bytes = s.recv(4) # 解出头部字典的长度 dic_len = struct.unpack('i', dic_bytes)[0] # 接收头部字典 str_dic = s.recv(dic_len) # 将字符串转成字典 dic = json.loads(str_dic) # 获取数据长度 data_len = dic['size'] # 接收数据部分 while data_len > 0: if data_len > 1024: print(s.recv(1024)) else: print(s.recv(data_len)) data_len -= 1024 s.close()
多线程
-
服务端
import socket import struct import json import socketserver def read_data(con: socket.socket) -> str: pack = con.recv(4) head_size = struct.unpack('i', pack)[0] head_dic = json.loads(con.recv(head_size).decode()) # type:dict data_size = head_dic.get('data_size') data = b'' while data_size > 0: if data_size > 1024: data += con.recv(1024) else: data += con.recv(data_size) data_size -= 1024 return data.decode() def write_data(con: socket.socket, data: str): data_size = len(data.encode()) data_hred = {'data_size': data_size} data_hred = json.dumps(data_hred).encode() con.send(struct.pack('i', len(data_hred))) con.send(data_hred) con.send(data.encode()) class myTcp(socketserver.BaseRequestHandler): def handle(self): while True: data = read_data(self.request) print('收到客户端消息', data) write_data(self.request, data.upper()) if __name__ == '__main__': s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), myTcp) s.serve_forever()
-
客户端
import socket import struct import json def read_data(con: socket.socket) -> str: pack = con.recv(4) head_size = struct.unpack('i', pack)[0] head_dic = json.loads(con.recv(head_size).decode()) # type:dict data_size = head_dic.get('data_size') data = b'' while data_size > 0: if data_size > 1024: data += con.recv(1024) else: data += con.recv(data_size) data_size -= 1024 return data.decode() def write_data(con: socket.socket, data: str): data_size = len(data.encode()) data_hred = {'data_size': data_size} data_hred = json.dumps(data_hred).encode() con.send(struct.pack('i', len(data_hred))) con.send(data_hred) con.send(data.encode()) if __name__ == '__main__': s = socket.socket() s.connect(('127.0.0.1', 8080)) while True: write_data(s, 'hello world!') print(read_data(s))