一、socket模块
socket简介
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
socket简易代码 (以C/S架构为例)
服务端
import socket server = socket.socket() server.bind(('127.0.0.1', 8090)) server.listen(5) sock, addr = server.accept() print(addr) data = sock.recv(1024) print(data) sock.send(b'hahaha') sock.close() server.close()
客户端
import socket client = socket.socket() client.connect(('127.0.0.1', 8090)) client.send(b'xixixi') data = client.recv(1024) print(data) client.close()
优化版本
1.客户端校验消息不能为空
2.服务端添加兼容性代码(mac linux)
在服务端添加 if recv ==0 :continue
3.服务端重启频繁报端口占用错误
from socket import SOL_SOCKET, SO_REUSEADDR
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 在bind前加
4.客户端异常关闭服务端报错的问题
使用异常捕获
服务端
import socket import struct import json server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: sock, addr = server.accept() while True:
data = sock.recv(1024) print(data) sock.send(b'hahaha') sock.close() server.close()
客户端
import socket client = socket.socket() client.connect(('127.0.0.1', 8090)) client.send(b'xixixi') data = client.recv(1024) print(data) client.close()
二、struct模块
struct模块可以解决文件传输时的黏包现象
什么是黏包?
在数据传输时,数据没有完全传输完,还留在管道内。
例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束
此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。
解决黏包情况(以上面的数据传输代码为例)
服务端
import socket import struct import json server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: sock, addr = server.accept() while True: head_data = sock.recv(4) # 解析报头 dict_length = struct.unpack('i', head_data)[0] # 接收字典 dict_data = sock.recv(dict_length) # 反序列化字典并解码 dict_real = json.loads(dict_data) # 取出字典的中的文件大小 file_size = dict_real.get('size') file_name = dict_real.get('filename') # 上传文件 recv_size = 0 with open('filename', 'wb') as f: while recv_size < file_size: data = sock.recv(1024) recv_size += len(data) f.write(data)
客户端
import os import socket import json import struct client = socket.socket() client.connect(('127.0.0.1', 8080)) while True: data_path = r'D:\BaiduNetdiskDownload\视频' movie_list = os.listdir(data_path) for i, j in enumerate(movie_list, 1): print(i, j) choice = input('请输入编号>>>: ') if choice == 0: continue if choice.isdigit(): choice = int(choice) if choice in range(1, len(movie_list) + 1): movie_name = movie_list[choice - 1] movie_path = os.path.join(data_path, movie_name) data_dict = { 'size': os.path.getsize(movie_path), 'filename': movie_name } data_josn = json.dumps(data_dict) data_head = struct.pack('i', len(data_josn)) client.send(data_head) client.send(data_josn.encode('utf8')) with open(movie_path, 'rb') as f: for line in f: client.send(line)