python基础day37 基于TCP、UDP协议的套接字编程和粘包现象
基于TCP协议的套接字编程(socket编程)
什么是Socket?
我们经常把Socket翻译为套接字,Socket是在应用层和传输层之间的一个抽象层,它把TCO/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信
套接字的分类:
AF_UNIX:用在局域网中
AF_INET:用在互联网中
客户端和服务端如何启动?
应该先启动服务端,服务端启动之后,等待客户端来连接,然后节后客户端发来的消息,进行通信
简易版本的套接字编程
# 服务端 import socket """ # SOCK_STREAM:使用的是TCP协议 # SOCK_DGRAM:使用的是UDP协议 """ # AF_INET:指定这个就完事了 # 买了个手机 server = socket.socket() # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 实例化得到socket对象 ###2. 服务端绑定信息 # 给手机买了个手机卡 server.bind(("127.0.0.1", 8000)) ###3.监听消息 server.listen(3) # 3代表的是半连接池:可以等待的客户端的数量 ###4. 接收消息 sock, addr = server.accept() # 代码走到这里会停住,等待接收客户端发来的消息 """ sock:代表的是当前客户端的连接对象 addr:代表的是客户端的信息(ip+port) """ ###5.真正的取到客户端发来的消息 data = sock.recv(1024) # 接收的最大数据,字节类型 print("客户端发来的消息:%s" % data) ###6. 服务端个客户端发消息 sock.send(b'hello') # 数据类型必须是字节类型 ###7. 断开与客户端之间的连接 sock.close() ###8. 关机 server.close() ##################客户端 import socket """ # SOCK_STREAM:使用的是TCP协议 # SOCK_DGRAM:使用的是UDP协议 """ # AF_INET:指定这个就完事了 # 买了个手机 client = socket.socket() # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 实例化得到socket对象 ###2.连接服务端 client.connect(("127.0.0.1", 8000)) ###3. 给服务端发送消息 client.send(b'helloworld') # 也要发送字节类型 ###4. 接收一些服务端发来的消息 data = client.recv(1024) # 一次接收的最大数据量,字节类型 print("服务端发来的消息:%s" % data) ###5. 挂断 client.close()
加上通信循环
# 服务端 import socket """ # SOCK_STREAM:使用的是TCP协议 # SOCK_DGRAM:使用的是UDP协议 """ # AF_INET:指定这个就完事了 # 买了个手机 server = socket.socket() # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 实例化得到socket对象 # server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 实例化得到socket对象 ###2. 服务端绑定信息 # 给手机买了个手机卡 server.bind(("127.0.0.1", 8000)) ###3.监听消息 server.listen(3) # 3代表的是半连接池:可以等待的客户端的数量 ###4. 接收消息 while True: sock, addr = server.accept() # 代码走到这里会停住,等待接收客户端发来的消息 """ sock:代表的是当前客户端的连接对象 addr:代表的是客户端的信息(ip+port) """ ###5.真正的取到客户端发来的消息 data = sock.recv(1024) # 接收的最大数据,字节类型 print("客户端发来的消息:%s" % data) ###6. 服务端个客户端发消息 sock.send(data.upper()) # 数据类型必须是字节类型 ###7. 断开与客户端之间的连接 sock.close() ###8. 关机 server.close()
加上连接循环
# 服务端 import socket """ # SOCK_STREAM:使用的是TCP协议 # SOCK_DGRAM:使用的是UDP协议 """ server = socket.socket() # 服务端绑定信息 server.bind(('127.0.0.1', 8001)) # 加上通信循环 # 监听信息 server.listen(2) # 3代表的是半连接池:可以等待的客户端的数量 # 接收消息 """ sock:代表的是当前客户端的连接对象 addr:代表的是客户端的信息(ip+port) """ while True: sock, addr = server.accept() # 代码走到这回停住,等待客户端发来的消息 while True: try: # 取到客户端发到的信息 data = sock.recv(1024) # 接受的最大数据量 if len(data) == 0: break print('客户端:%s' % data.decode()) sock.send(data.upper()) except ConnectionResetError as e: print(e) break # 断开连接 sock.close() # 关机 server.close() # 客户端 import socket """ # SOCK_STREAM:使用的是TCP协议 # SOCK_DGRAM:使用的是UDP协议 """ client = socket.socket() # 连接服务器 client.connect(('127.0.0.1', 8001)) while True: # 给服务器发消息 date = input('你要向服务器输入的信息:') if len(date) == 0: continue client.send(date.encode('utf8')) # 接收服务器发来的消息 data = client.recv(1024) # 一次性接受的最大数据量,字节类型 print('服务器:%s' % data.decode()) # 挂断 client.close()
基于UDP协议的套接字编程
# 服务端 import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP server.bind(('127.0.0.1', 8080)) while True: # client_addr:客户端的地址:ip+port data, client_addr = server.recvfrom(1024) # 接收客户端发来的消息,1024是字节数 print('===>', data, client_addr) server.sendto(data.upper(), client_addr) # 给客户端发消息 server.close() # 客户端: import socket client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP while True: msg = input('>>: ').strip() # msg='' client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080)) data, server_addr = client.recvfrom(1024) print(data) client.close()
粘包现象
client --------------------------------server 9999 1024 9999-1024 黏包现象:其实就是管道里面的数据没有被完全取出来 TCP的特性:流式协议 """ 1. 当客户端发送的数据量很小并且时间间隔很小的时候 它会把数据打包成一个包一次性发送
2. 客户端发送的数据量很大时,它会把数据拆分,分多次发送。 """
struct模块
import struct # 1000 ======> 4 # 1000000 =======> 4 # helloworld ========> 4 """报头:4个字节""" # res=struct.pack('i', 1000) # i:被打包的数据大小是有限制的 # res=struct.pack('q', 100000000000000000000) # # res=struct.pack('i', 200000000) # print(len(res)) # 4 # # # 解包 # res1=struct.unpack('q', res)[0] # print(res1)