socket与struct模块
一、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)

浙公网安备 33010602011771号