8.23_python_lx_day30
一.TCP基本语法
import socket
(1)服务端
<1>创建一个socket对象
sk = socket.socket()
<2>绑定对应的ip和端口号(让其他主机在网络中可以找得到)
#127.0.0.1代表本地ip sk.bind( ("127.0.0.1",9001) )
<3>开启监听
sk.listen()
<4>建立三次握手
conn,addr = sk.accept()
<5>处理收发数据的逻辑
#recv 接收 send 发送 res = conn.recv(1024) # 代表一次最多接收1024个字节 print(res.decode('utf-8'))
<6>四次挥手
conn.close()
<7>退还端口
sk.close()
(2)客户端
<1>创建一个socket对象
sk = socket.socket()
<2>与服务器建立连接
sk.connect( ('127.0.0.1',9001) )
<3>发送数据(只能发送二进制的字节流)
sk.send('需要发送的字符串'.encode('utf-8'))
<4>关闭连接
sk.close()
二.TCP循环发送消息
(1)服务端
<1>创建一个socket对象
sk = socket.socket()
<2>绑定对应的ip和端口号(让其他主机在网络中可以找得到)
#127.0.0.1代表本地ip sk.bind( ("127.0.0.1",9001) )
<3>开启监听
sk.listen()
<5>处理收发数据的逻辑
while True: #<4>三次握手 conn,addr = sk.accept() while True: res = conn.recv(1024) print(res.decode()) strvar = input("请输入服务端要给客户端发送的内容") conn.send(strvar.encode()) if strvar.upper() == "Q": break
<6>四次挥手
conn.close()
<7>退还端口
sk.close()
(2)客户端
<1>.创建socket对象
sk = socket.socket()
<2>连接服务端
sk.connect( ("127.0.0.1" , 9000) )
<3>收发数据
while True: strvar = input("请输入您要发送的内容:") sk.send(strvar.encode()) res = sk.recv(1024) if res == b"q" or res == b"Q": break print(res.decode())
<4>关闭连接
sk.close()
三.udp基本语法
(1)服务端
<1>创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
<2>绑定地址端口号
sk.bind( ("127.0.0.1",9000) )
<3>udp服务器,在一开始只能够接受数据
msg,cli_addr = sk.recvfrom(1024) print(msg.decode()) print(cli_addr) # 服务端给客户端发送数据 msg = "发送的字符串" sk.sendto(msg.encode(),cli_addr)
<4>关闭连接
sk.close()
(2)客户端
<1>创建udp对象
sk = socket.socket(type = socket.SOCK_DGRAM)
<2>收发数据的逻辑
# 发送数据 msg = "你好,你是mm还是gg" # sendto( 消息,(ip,端口号) ) sk.sendto( msg.encode() , ("127.0.0.1",9000) ) # 接受数据 msg,server_addr = sk.recvfrom(1024) print(msg.decode()) print(server_addr)
<3>关闭连接
sk.close()
四.udp循环发消息
(1)服务端
<1>创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
<2>绑定地址端口号
sk.bind( ("127.0.0.1",9000) )
<3>udp服务器,在一开始只能够接受数据
while True: # 接受消息 msg,cli_addr = sk.recvfrom(1024) print(msg.decode()) message = input("服务端给客户端发送的消息是?:") # 发送数据 sk.sendto(message.encode() , cli_addr)
<4>关闭连接
sk.close()
五.黏包
- 黏包出现的两种情况:
- (1) 发送端发送数据太快
- (2) 接收端接收数据太慢
(1)struct
- pack :
- 把任意长度数字转化成具有固定4个字节长度的字节流
- unpack :
- 把4个字节值恢复成原来的数字,返回最终的是元组
import struct # pack # i => int 要转化的当前数据是整型 # pack 的范围 -2147483648 ~ 2147483647 21个亿左右 res = struct.pack("i",2100000000) print(res , len(res)) # len(res) => 4 # unpack # i => 把对应的数据转换成int整型 tup = struct.unpack("i",res) print(tup) # (2100000000,) print(tup[0]) #2100000000
- 解决黏包场景:
- 应用场景在实时通讯时,需要阅读此次发的消息是什么
- 不需要解决黏包场景:
- 下载或者上传文件的时候,最后要把包都结合在一起,黏包无所谓
(2)使用struct解决黏包问题
<1>服务端
import socket import struct sk = socket.socket() sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) sk.bind( ("127.0.0.1",9000) ) sk.listen() conn,addr = sk.accept() # 处理收发数据的逻辑 strvar = input("请输入你要发送的数据") msg = strvar.encode() length = len(msg) res = struct.pack("i",length) # 第一次发送的是字节长度 conn.send(res) # 第二次发送真实的数据 conn.send(msg) # 第三次发送真实的数据 conn.send("世界真美好123".encode()) conn.close() sk.close()
<2>客户端
import socketimport struct sk = socket.socket() sk.connect( ("127.0.0.1",9000) ) # 处理收发数据的逻辑 # 第一次接受的是字节长度 n = sk.recv(4) tup = struct.unpack("i",n) n = tup[0] # 第二次接受真实的数据 res = sk.recv(n) print(res.decode()) # 第三次接受真实的数据 res = sk.recv(1024) print(res.decode()) sk.close()