简易版客户端服务端交互
常识
AF_UNIX 是基于文件类型的套接字家族
AF_INET是 基础网络类型的套接字家族
socket 模块属性很多,可以直接使用from module import *语句 ,这样socket所有的数据都被带劲命名空间里了. 减少代码量(少用)
服务端
#1导入
import socket
# 2.获取套接字
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3绑定
s.bind(('127.0.0.1',8070))
#4开机,监听
s.listen(1)
#5创建一个通道和地址,等待接受电话
conn,addr=s.accept()
#6接受这个值
data=conn.recv(1024)
#7释放数据
print(data)
#8用通道发送数据
conn.send('帅逼'.encode('gbk'))
#9关闭通道
conn.close()
#10关闭服务端
s.close()
客户端
#导入
import socket
#创建对象
s=socket.socket()
#连接服务端地址
s.connect(('127.0.0.1',8070))
s.send(b'adas')
#接受字节数据
data=s.recv(1024)
#打印展现出来
print(data.decode('gbk'))
#关闭
s.close()
基础知识混淆点
把b格式转成字符串
ss=str(b'hello',encoding='utf8')
等于这个
ss=b'hello'.decode('utf8')
把字符串转成b格式
by=bytes('hello',encoding='utf8')
by='hello'.encode('utf8')
解决客户端突然断开连接
客户端需要发信息一直发信息 所以有while循环 ,但是我们的服务端也需要一直接受信息,否则发信息就没有意义了
-
但是 如果说客户端突然断开连接这个时候就会出现一下错误
这个时候就需要加上try 以及 except EXCEPTION 如果出现了错误 ,那么咱们需要怎么做。。
总结:
服务端server
#1导入
import socket
# 2.创建对象
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3绑定
s.bind(('127.0.0.1',8070))
#开机,监听
s.listen(1)
#创建一个通道和地址,等待接受电话
conn,addr=s.accept()
#接受这个值
while True:
try:
#等待接受 最大收1024字节
data=conn.recv(1024)
#释放数据
print(data.decode('utf8'))
except Exception:
conn.close()
break
client 客户端
导入 创建 连接 发送信息 转换格式
import socket
#创建新对象
s=socket.socket()
#连接直接用
s.connect('127.0.0.1',8070)
#发送信息
while True:
msg=input('输入')
#发送输入数据
s.send(msg.encode('utf8'))
套接字加上连接循环通讯循环
服务端要一直稳定的运行,不能客户端断了 咱们的服务端等着连接的代码需要重写一遍,所以应该让服务端循环等着客户端的连接(但是接受,打印客户数据信息,需要在连接之后写)所以需要加上一个循环嵌套,循环嵌套是 内层嵌套运行break掉才会继续运行外层循环的信息(称之为结算运行)。
需求精简:服务端要能够一直的循环等待客户端连接,蛋不需要发一次信息就连接一次。
实现精简:嵌套循环 等待客户端连接代码写在大循环,接受客户数据信息,与打印信息放在内层循环里面。
……
#接受这个值
while True:
print('等待客户端的连接')
conn,addr=s.accept()
while True:
try:
#等待接受 最大收1024字节
data=conn.recv(1024)
#释放数据
print(data.decode('utf8'))
except Exception:
conn.close()
break
conn.close()
addr是客户端的地址
解决粘包问题
基础概念
TCP粘包就是指发送方发送的若干个包数据 --->接收方接受时粘成一个包,两个数据包是有数据头尾的,后一个包可能会紧接着前一个包的尾
可能是发送方造成的,也可能是有接收方造成的,发送方因其粘包是有TCP协议本身造成的,如果连续几次发送数据很少,那么TCP会根据优化算法把这些数据合成一个包后一次发送出去,这样接收方就收到了粘包数据。
解决方案
长度不变,就不会粘包,因为粘包,发送方或者接收方可能会少数据多数据,固定他的字节的长度就不会产生粘包
struct模块
为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从换从中取出定长的报头,然后打开包裹取真实数据,
主要是把一个类型转成固定长度的bytes。核心
步骤
导包-->打包Pack('模式',数据)--解包
# 导报#
import struct
#打包创建对象里面有模式(以字符串表示),跟这个数据对象
obj=struct.pack('i',1234532111)
print(obj)
print(len(obj)) #固定4个字节的长度
#打开包裹,反解出来
l=struct.unpack('i',obj)[0]#是一个小元祖 取索引第0个
print(l)