文章目录
- 一、socket套接字
-
- 1.socket套接字类型
- 2.socket使用
-
- 2.1 服务端
- 2.2客户端
- 3.通信循环
- 4.链接循环
- 5.半连接池
- 6.补充
- 二、黏包
-
- 1.黏包的产生
- 2.黏包解决
一、socket套接字 1.socket套接字类型
- 基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
- 基于网络类型的套接字家族
套接字家族的名字:AF_INET
(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)
文章图片
2.1 服务端
import socketserver = socket.socket()# 建立服务器
"""
括号内不写参数默认就是基于网络的遵循TCP协议的套接字
"""
server.bind(('127.0.0.1', 8080))# 设置ip和端口
"""
服务端应该具备的特征
固定的地址
...
127.0.0.1是计算机的本地回环地址 只有当前计算机本身可以访问
"""
server.listen(5)# 开机
"""
半连接池(暂且忽略 先直接写 后面讲)
"""
sock, addr = server.accept()# 等待并接听电话没有人来就原地等待(程序阻塞)
"""
listen和accept对应TCP三次握手服务端的两个状态
"""
print(addr)# 客户端的地址
data = https://www.it610.com/article/sock.recv(1024)# 接收客户端消息
print(data.decode('utf8'))
sock.send('你好啊'.encode('utf8'))# 发送消息给客户端
"""
recv和send接收和发送的都是bytes类型的数据
"""
sock.close()# 关闭连接
server.close()# 关闭服务器
2.2客户端
import socketclient = socket.socket()# 产生一个socket对象
client.connect(('127.0.0.1', 8080))# 根据服务端的地址链接
while True:
sc = input("需要发给服务器的消息:").strip()
client.send(sc.encode("utf8"))# 给服务端发送消息
data = https://www.it610.com/article/client.recv(1024)# 接收服务端回复的消息
print(data.decode('utf8'))client.close()# 关闭客户端
3.通信循环 由于服务器和客户端之间需要不断通信,所以需要对消息的接收和发送循环起来
# 下方为服务器端循环通信,由于是先recv所以会先等待客户端发消息
while True:
data = https://www.it610.com/article/sock.recv(1024)# 接收客户端消息
print("客户端:" + data.decode('utf8'))
sc = input("输入需要发给客户端的消息:").strip()
sock.send(sc.encode('utf8'))# 发送消息给客户端# 下方为客户端循环通信,由于是先send所以需要先发消息,然后等待服务器消息
while True:
sc = input("需要发给服务器的消息:").strip()
client.send(b'hello sweet heart!!!')# 给服务端发送消息
data = https://www.it610.com/article/client.recv(1024)# 接收服务端回复的消息
print(data.decode('utf8'))
4.链接循环 当客户端断开后需要让服务器进入accept等待下一个客户端,此时需要使用到异常处理
如果是windows 客户端异常退出之后服务端会直接报错,使用以下方式重新等待连接:
处理方式
异常处理
如果是mac或linux 服务端会接收到一个空消息,使用一下方法重新等待连接:
处理方式
len判断
循环链接的要点在于客户端断开后服务端需要重新等待客户端连接
while True:
try:
data = https://www.it610.com/article/sock.recv(1024)# 接收客户端消息
print("客户端:" + data.decode('utf8'))
sc = input("输入需要发给客户端的消息:").strip()
sock.send(sc.encode('utf8'))# 发送消息给客户端
except Exception:
sock, addr = server.accept()
print(addr)
5.半连接池 半连接池:限制的是同一时刻的请求数,而非连接数,第一次握手成功时客户端会连上半连接池
设置的最大等待人数 >>>: 节省资源 提高效率
py文件默认同一时间只能运行一次 如果想单独分开运行多次
listen(5)
6.补充 反复重启服务端可能会报错>>>:address in use
这个错在苹果电脑报的频繁 windows频率较少
from socket import SOL_SOCKET,SO_REUSEADDR
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 在bind前加
二、黏包 1.黏包的产生 会发生黏包的两种情况:
- 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
- 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
【网络编程|网络编程——socket套接字、黏包】代码如下(示例):
# struct模块
import structdata1 = 'hello world!'
print(len(data1))# 12
res1 = struct.pack('i', len(data1))# 第一个参数是格式 写i就可以了
print(len(res1))# 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,)
推荐阅读
- django框架|django——版本问题、启动问题、安装、基础使用、应用app、django主要文件介绍
- python——用Turtle画画写名字
- 软件测试|【码住收藏】软件测试报告模板范文来了——优秀测试报告模板流程
- 软件测试|十分钟带你看懂——Python测试框架之pytest最全讲
- 技术交流|Python图像处理丨图像缩放、旋转、翻转与图像平移
- Python数据分析基础-2Python标量类型
- python——rsa和aes加解密
- Python数据分析基础-1二元操作符(又全又清晰!)
- 一行代码简化 Python 异常信息(错误清晰可见,排版简洁明了)