4.15python笔记
作者:互联网
socket模块及粘包问题
socket套接字
Socket并不属于TCP/IP协议簇,它只是一个编程接口,即对TCP/IP的封装和应用,简单理解TCP/IP看看作一个函数,而Socket用来进行调用,Socket可在网络中对两个程序建立通信通道。
Socket可分为两个基本模块,一个服务端一个客户端,链接后进行通信。
服务端编写
import socket
server = socket.socket() # 相当于买手机
"""通过查看源码得知
括号内不写参数默认就是基于网络的遵循TCP协议的套接字"""
server.bind(('127.0.0.1', 8080)) # 相当于插电话卡
"""127.0.0.1是计算机的本地回环地址 只有当前计算机本身可以访问"""
server.listen(5) # 相当于开机,数字是等待接收的客户端数量(半连接池)
sock, addr = server.accept() # 相当于等待并接听电话,没有收到信息就原地等待(程序阻塞)
print(addr) # 客户端地址
data = sock.recv(1024) # 相当于听电话,接收信息,参数是接收的信息长度
print(data.decode('utf8')) # 打印接收的信息,接收的信息需要解码
sock.send('你好啊'.encode('utf8')) # 发送信息,同样需要编码
注意:recv和send接收和发送的都是bytes类型的数据
sock.close # 相当于挂电话
server.close # 相当于关机
客户端编写
import socket
client = socket.socket() # 产生一个socket对象
client.connect(('127.0.0.1', 8080)) # 根据服务端地址链接
client.send('你是谁'.encode('utf8')) # 发送信息至服务端
data = client.recv(1024) # 接收服务端回复的消息
print(data.decode('utf8')) # 打印接收的消息
client.close() # 关闭客户端
通信循环
1.先解决消息固定的问题
利用input获取用户输入
2.再解决通信循环问题
使用while循环语句
import socket
# 客户端
client = socket.socket()
client.connect(('127.0.0.1', 8080))
while True:
msg = input('输入需要发送的信息>>>:').strip()
client.send(msg.encode('utf8')) # 发送信息
data = client.rscv(1024) # 接收信息
print(data) # 打印获取信息
client.close
import socket
# 服务端
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
sock,addr = server.accept()
while True:
data = sock.recv(1024)
print(data.decode('utf8'))
msg = input('输入需要发送的信息>>>:').strip()
sock.send(msg.encode('utf8'))
sock.close
server.close
半连接池
即设置的最大等待人数 >>>: 节省资源,提高效率
server.listen(5) # # 除当前接收的客户端外,还允许接收5个,这5个为等待状态
黏包问题及解决方法
#TCP协议的特点:
会将数据量比较小并且时间间隔比较短的数据整合到一起发送,并且还会受制于recv括号内的数字大小(核心问题!!!)
#流式协议:
跟水流一样不间断
黏包现象只发生在tcp协议中
1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点
2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
粘包是接收长度没对上导致的
控制recv接收的字节数与之对应(你发多少字节我收多少字节)
在很多情况下并不知道数据的长度,服务端不能写死
解决粘包问题
import stuuct # 调用struct模块
data1 = 'hello world!'
print(len(data1)) # 12
res1 = struct.pack('i', len(data1)) # 打包,第一个参数是格式,写i就可以
print(len(res1)) # 4 ,打包后长度为4
ret1 = struct.unpack('i', res1) # 拆包,拆包后是一个元组
print(ret1) # (12,)
data2 = 'hello baby baby baby baby baby baby baby baby'
print(len(data2)) # 45
res2 = struct.pack('i', len(data2))
print(len(res2)) # 4
ret2 = struct.unpack('i', res2)
print(ret2) # (45,)
pack可以将任意长度的数字打包成固定长度
unpack可以将固定长度的数字解包成打包之前数据真实的长度
可以考虑使用字典封装数据然后再打包
具体解决方法
思路:
1.先将真实数据打包成固定长度的包
2.将固定长度的包先发给对方
3.对方接收到包之后再解包获取真实数据长度
4.接收真实数据长度
终极解决方案
# 服务端
1.先构造一个字典
内部存档了真实数据相关的信息
大小 名称 简介 ...
2.对字典做打包处理
3.将固定长度的数据(字典)发送给对方
4.发送真实的字典数据
5.发送真实的真正数据
# 客户端
1.先接收固定长度的字典包
2.解析出字典的真实长度
3.接收字典数据
4.从字典数据中解析出各种信息
5.接收真实的数据
data_dict = {
'file_name': 'XXX合集.zip',
'file_desc': '营养快线',
'file_size': 321312312312312312312312312
}
print(len(data_dict)) # 3
res = struct.pack('i', len(data_dict))
print(len(res)) # 4
ret = struct.unpack('i', res)
print(ret) # (3,),元组形式,3是原数据的真实长度
标签:4.15,socket,python,笔记,server,client,print,接收,data 来源: https://www.cnblogs.com/zq0408/p/16286345.html