1.tcp协议循环收发消息
1.1服务端
# tcp服务端
# 1.创建一个socket对象
import socket
sk = socket.socket()
# 让当前的端口重复绑定多个程序(仅仅在测试阶段使用)
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2.在网络中注册主机(绑定ip和端口)
sk.bind(("192.168.11.217", 9008))
# 3.监听端口
sk.listen()
# 4.三次握手
# conn, addr = sk.accept()
# 5.收发数据
'''
数据类型:二进制字节流
b修饰的字符串=>代表的是二进制的字节流
里面的字符必须是ascii编码中的字符,不能是中文,否则报错
'''
while True:
conn, addr = sk.accept()
while True:
res = conn.recv(1024)
conn.send(res.upper())
# 6.四次挥手
conn.close()
# 退出端口
sk.close()
1.2 客户端
# 客户端
import socket
# 1.创建一个socket对象
sk = socket.socket()
# 2.连接服务端
sk.connect(('192.168.11.217', 9008))
# 3.收发数据
while True:
strvar = input('请输入你要发送的内容:').strip()
sk.send(strvar.encode('utf-8'))
res = sk.recv(1024)
print(res.decode('utf-8'))
if res == b'q':
break
# 退回端口
sk.close()
2.使用struct解决粘包问题
解决粘包的场景:
对于实时通讯的,需要区分每一次发送的消息时需要解决粘包的现象
不需要解决粘包的场景:
对于上传和下载文件时,最后还是要把所有数据粘合在一起,粘包现象不需要解决
struct模块:
pack方法 : 可以把任意长度的数字转换为4个字节的二进制字节流(1字节等于8位)
utf-8中一个字母为1个字节,一个汉字3个字节
pack方法有两个参数,第一个为数据的类型(i 整型 f 浮点型),第二个为参数
unpack方法:可以把4个字节的二进制字节恢复成原来的数据类型,返回元组,原数据为第一个元素
2.1服务端
# 创建一个tcp协议对象
import socket
import struct
sk = socket.socket()
# 在bind前加这个代码,可以让一个端口同时被多个程序绑定,重复使用(仅仅在测试时使用)
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 在网络上注册(绑定ip和端口)
sk.bind(('192.168.11.217', 9008))
# 开始监听
sk.listen()
#三次握手
conn, addr = sk.accept()
# 收发消息
# 第一次先发送要发送数据的长度
strvar = input('your word:').strip()
b_strvar = strvar.encode('utf-8')
# 注意:无论是中文字符还是英文字母都是通过二进制字节流传送,
# 因此传到服务端要设置的接收字节数为传送数据的二进制字节流大小
res = len(b_strvar)
n = struct.pack('i', res)
conn.send(n)
# 发送第一段数据
conn.send(strvar.encode('utf-8'))
# 发送第二段数据
conn.send('hello, word !'.encode('utf-8'))
# 四次挥手
conn.close()
# 关闭连接,退回端口
sk.close()
2.2客户端
# 创建一个tcp协议对象
import socket
import struct
sk = socket.socket()
# 连接服务端
sk.connect(('192.168.11.217', 9008))
# 收发数据
# 第一次收到的是第一段数据的长度
res = sk.recv(4)
n = struct.unpack('i', res)[0]
# 接收第一段数据的内容
res1 = sk.recv(n)
print(res1.decode('utf-8'))
# 接收第二段数据的内容
res2 = sk.recv(1024)
print(res2.decode('utf-8'))
# 关闭连接
sk.close()
3.使用socketserver模块让tcp协议支持服务端并发通讯
3.1服务端
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# self.request 返回三次握手连接对象conn
print(self.request)
# self.client_address 返回客户端地址信息
print(self.client_address)
conn = self.request
while True:
msg = conn.recv(1024)
print(msg.decode('utf-8'))
conn.send(msg.upper())
server = socketserver.ThreadingTCPServer(('192.168.11.217', 9012), MyServer)
# 循环调用,建立连接
server.serve_forever()
3.2 客户端
# 客户端
import socket
sk = socket.socket()
sk.connect(('192.168.11.217', 9012))
while True:
strvar = input('你要给服务端发送的内容:').strip()
if strvar == 'q':
break
sk.send(strvar.encode('utf-8'))
msg = sk.recv(1024)
sk.close()