如何解决socket编程中tcp连接的粘包问题
在socket编程中,因为tcp连接发送的内容之间没有间隔,读取时会一次性读出积累的所有内容,即使这些内容并非仅仅是由一次发送而来。这被称之为粘包。
# client.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.connect(ADDRESS)
s.sendall('hello!'.encode())
s.sendall('hello!'.encode())
s.sendall('hello!'.encode())
# sever.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.bind(ADDRESS)
s.listen()
connect, address = s.accept()
with connect:
print(connect.recv(1024).decode())
print(connect.recv(1024).decode())
print(connect.recv(1024).decode())
hellp!hello!hello!
(空行)
(空行)
解决办法
1. 在每次发送之间制造一些时间间隙
# client.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.connect(ADDRESS)
s.sendall('hello!'.encode())
time.sleep(1)
s.sendall('hello!'.encode())
time.sleep(1)
s.sendall('hello!'.encode())
2. 把多次发送融合成一次发送
# client.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.connect(ADDRESS)
s.sendall('*'.join(["hello", "hello", "hello"]).encode())
# sever.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.bind(ADDRESS)
s.listen()
connect, address = s.accept()
with connect:
data = connect.recv(1024).decode()
result = data.split('*')
print(result)
3. 收到回复再发送
# client.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.connect(ADDRESS)
s.sendall('hello!'.encode())
print(s.recv(1024).decode())
s.sendall('hello!'.encode())
print(s.recv(1024).decode())
s.sendall('hello!'.encode())
print(s.recv(1024).decode())
# sever.py
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
ADDRESS = ('localhost', 8000)
s.bind(ADDRESS)
s.listen()
connect, address = s.accept()
with connect:
print(connect.recv(1024).decode())
connect.sendall('I have received message'.encode())
print(connect.recv(1024).decode())
connect.sendall('I have received message'.encode())
print(connect.recv(1024).decode())
connect.sendall('I have received message'.encode())