关于TCP/IP异机通讯字符串断线的问题
About the issue that the character string is broken in TCP/IP communication between different machines
我尝试了 TCP/IP 同一台机器之间的通信和 TCP/IP 不同机器之间的通信。
首先,我尝试在同一个Windowsmachine.The服务器和客户端进行通信,使用的代码是:
TCP_server.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 50001))
s.listen(1)
while True:
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(30000)
if not data:
break
if len(data.decode('utf-8')) < 35:
print("error")
break
print(data.decode('utf-8')+"\n")
TCP_client.py
# -*- coding : UTF-8 -*-
import socket
target_ip = "192.168.1.5"
target_port = 50001
buffer_size = 4096
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((target_ip,target_port))
message = b'123456789101112131415161718192021222324252627282930\n'
while True:
tcp_client.send(message)
我的 Windows 机器的 IP 地址是 192.168.1.5,所以上面的代码有效。并且它执行成功,没有任何错误。打印出来的字符串如下图所示
但是当我尝试使用完全相同的代码与 Mac 和 Windows 通信时,我遇到了问题。我在客户端用了Mac,在服务器端输出的server.The字符串是Windows,如下
从上图可以看出,正常打印是正常的,但有时会出现换行,字符串被分割。
而我的服务器端代码说,如果字符数少于 35,就会打印错误。但是,这次执行并没有打印错误result.In 也就是说,没有进行两次通信,而是在一次通信中插入换行符。
是否可以避免这个问题?从另一台机器通过 TCP/IP 发送时,我是否总是需要注意换行符?
我在此示例中只使用了 Python,但我在使用 iOS 的 Swift 作为客户端代码时遇到了类似的问题。所以我想知道一个通用的解决方案。
传输数据时没有添加换行符。此换行符是由服务器代码添加的:
print(data.decode('utf-8')+"\n")
print
本身都会导致换行,然后您还要添加另一个。
一般来说,您假设每个 send
都有一个匹配的 recv
。这个假设是错误的。 TCP 是字节流而不是消息流,来自多个 send
的有效负载可能会合并在一起以减少发送的开销,也可能导致“拆分”为单个“消息”。
在机器之间发送流量时尤其如此,因为机器之间的带宽小于本地带宽,数据层的 MTU 也小得多。
鉴于您必须首先在服务器端收集您的“消息”。只有在您获得完整的“消息”(无论您的情况是什么)之后,您才应该 decode('utf-8')
。否则,当您尝试解码具有 multi-byte UTF-8 编码但尚未收到所有字节的字符时,您的代码可能会崩溃。
我尝试了 TCP/IP 同一台机器之间的通信和 TCP/IP 不同机器之间的通信。
首先,我尝试在同一个Windowsmachine.The服务器和客户端进行通信,使用的代码是:
TCP_server.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 50001))
s.listen(1)
while True:
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(30000)
if not data:
break
if len(data.decode('utf-8')) < 35:
print("error")
break
print(data.decode('utf-8')+"\n")
TCP_client.py
# -*- coding : UTF-8 -*-
import socket
target_ip = "192.168.1.5"
target_port = 50001
buffer_size = 4096
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((target_ip,target_port))
message = b'123456789101112131415161718192021222324252627282930\n'
while True:
tcp_client.send(message)
我的 Windows 机器的 IP 地址是 192.168.1.5,所以上面的代码有效。并且它执行成功,没有任何错误。打印出来的字符串如下图所示
但是当我尝试使用完全相同的代码与 Mac 和 Windows 通信时,我遇到了问题。我在客户端用了Mac,在服务器端输出的server.The字符串是Windows,如下
从上图可以看出,正常打印是正常的,但有时会出现换行,字符串被分割。
而我的服务器端代码说,如果字符数少于 35,就会打印错误。但是,这次执行并没有打印错误result.In 也就是说,没有进行两次通信,而是在一次通信中插入换行符。
是否可以避免这个问题?从另一台机器通过 TCP/IP 发送时,我是否总是需要注意换行符?
我在此示例中只使用了 Python,但我在使用 iOS 的 Swift 作为客户端代码时遇到了类似的问题。所以我想知道一个通用的解决方案。
传输数据时没有添加换行符。此换行符是由服务器代码添加的:
print(data.decode('utf-8')+"\n")
print
本身都会导致换行,然后您还要添加另一个。
一般来说,您假设每个 send
都有一个匹配的 recv
。这个假设是错误的。 TCP 是字节流而不是消息流,来自多个 send
的有效负载可能会合并在一起以减少发送的开销,也可能导致“拆分”为单个“消息”。
在机器之间发送流量时尤其如此,因为机器之间的带宽小于本地带宽,数据层的 MTU 也小得多。
鉴于您必须首先在服务器端收集您的“消息”。只有在您获得完整的“消息”(无论您的情况是什么)之后,您才应该 decode('utf-8')
。否则,当您尝试解码具有 multi-byte UTF-8 编码但尚未收到所有字节的字符时,您的代码可能会崩溃。