socket套接字
- 套接字家族
文件类型的: AF_UNIX 网络类型的: AF_INET- 图示:
- 服务端启动之后,客户端才能够运行起来
使用套接字完成客户端与服务端的交互 服务端: # 1.创建一个socket对象 server = socket.socket() # 括号里什么都写默认是基于网络的TCP套接字 # 2.绑定一个固定的地址(ip\port) server.bind(('127.0.0.1',8080)) # 地址用本机的 # 3.半连接池 # 主要是为了做缓冲 避免太多无效等待 server.listen(5) # 4.连接客户端 sock, address = server.accept() # accept有两个形参返回值,用两个接收 print(sock,address) # 5.数据交互 sock.send(b'hello big') # 往客户端发送数据 data = sock.recv(1024) # 接收客户端发送的数据 1024bytes print(data) # 6.断开连接 sock.close() # 断掉与客户端的连接 server.close() # 关机 客户端: import socket # 1.产生一个socket对象 client = socket.socket() # 2.连接服务端(ip,port) client.connect(('127.0.0.1',8080)) # 3.数据交互 data = client.recv(1024) #接收服务端发送的数据 print(data) client.send(b'fack you') # 关闭 client.close() 现在我们只完成了客户端接收到了服务端发送的信息,并不能进行互动 针对以上完成优化 1.send与recv 客户端与服务端不能同时收或发 2.针对自定义的消息 使用input即可 3.循环通信(畅聊下去) 在用户交互环节添加循环 4.避免客户端断开连接,让服务可以持续运行 使用异常捕获,一旦客户端断开连接 服务端结束通信循环 调到连接处等待 5.避免输入空格(什么都不输)后程序没有响应 判断输入的东西是否为空,如果是就重新输入(主要是客户端) 6.避免程序频繁重启后端口被占用报错(mac电脑) from socket import SOL_SOCKET,SO_REUSEADDR server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 在bind前面添加 7.客户端异常退出会发送空消息(针对mac linux) 针对接收的消息加判断处理即可
- 图示:
- 黏包问题
服务端代码 sock.recv(1024) sock.recv(1024) sock.recv(1024) 客户端代码 client.send(b'jason') client.send(b'kevin') client.send(b'tony')- TCP特性
- 流式协议:所有的数据类似于水流一样,连接到一起
数据量很小,并且时间间隔很多,就会自动组织到一起- recv
需要接收的数据量是未知的,所以才会有黏包的现象,知道的话就不会产生黏包了 - 黏包实例
struct模块无论数据长度是多少,都可以帮你打包成固定长度
基于打包后的固定长度,可以反向解析出其真实长度 struct模块针对数据量特别大的数字没有办法打包 服务端: # 1.先构造数据文件的字典 # 2.将字典打包成固定长度的数据 # 3.发送固定长度的字典报头 # 4.发送真实字典数据 # 5.发送真实数据 客户端 # 1.先接收长度为4的报头数据 # 2.根据报头解包出字典的长度 # 3.直接接收字典数据 # 4.解码并反序列化出字典 # 5.从数据字典中获取真实数据的各项信息 ``` - UDP协议
- 用户数据报协议
简单的面向无连接的,不可靠的数据报的 传输层协议- 黏包问题
UDP不存在黏包问题,所以UDP多用于短消息的交互(例如我们使用的qq)- UDP实例操作
服务端不需要考虑客户端是否异常退出 服务端 import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1', 8080)) msg, address = server.recvfrom(1024) print('msg>>>:%s' % msg.decode('utf8')) print('address>>>:',address) server.sendto('我是服务端,和我一起成为魔法少女吧'.encode('utf8'), address) 客户端 import socket client = socket.socket(type=socket.SOCK_DGRAM) server_address = ('127.0.0.1', 8080) client.sendto('我是客户端,魔法少女可以拯救世界吗'.encode('utf8'), server_address) msg, address = client.recvfrom(1024) print('msg>>>:%s' % msg.decode('utf8')) print('address>>>:',address)
- TCP特性