tcp协议套接字通讯(循环通讯,粘包,并发通讯)

本文深入解析TCP协议的循环收发消息机制,演示了服务端与客户端的具体实现过程,并介绍了如何使用struct模块解决粘包问题,以及利用socketserver模块实现服务端并发通讯,适合网络编程初学者和进阶者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值