Python TCP 服务器与 C++ 客户端之间的对话

4 投票
2 回答
4550 浏览
提问于 2025-04-15 14:19

我在尝试让一个Python的TCP服务器和一个C++的TCP客户端进行通信时遇到了一些问题。第一次调用时一切正常,但后面的调用就出现了问题。

根据WinSock的情况,send()函数工作得很好,它返回了正确的长度,而且WSAGetLastError()也没有返回什么重要的错误信息。

不过,当我用wireshark监控数据包时,我发现第一次调用发送了两个数据包,一个是带有所有数据的PSH,ACK包,紧接着又发送了一个ACK包。但是后面的调用就不一样了,它们只发送了PSH,ACK包,没有后续的ACK包。

接收方的wireshark也证实了这一点,而Python服务器没有任何反应,socket里没有数据流出,我也无法深入调试,因为socket是一个原生类。

当我运行一个C++客户端和一个C++服务器(其实是对Python服务器的一个修改版)时,客户端始终如一地发送PSH,ACK和ACK包,即使在第一次调用之后也是如此。

winsock的send函数是不是应该总是发送PSH,ACK和ACK包?如果是的话,为什么在连接到我的C++服务器时会这样,而连接到Python服务器时却不行?有没有人遇到过类似的问题?

2 个回答

1

你发送的数据包大小是多少?

如果数据包很小,可能是Nagle算法和延迟确认算法让你头疼?根据你描述的情况,感觉是跟延迟确认有关...

2

客户端发送了一个 PSH,ACK,然后服务器也发送了一个 PSH,ACK 和一个 FIN,PSH,ACK。

因为有一个 FIN,所以可能是你的 Python 版本的服务器在第一次读取后就立即关闭了连接?

如果你没有明确关闭服务器的套接字,那么很可能是服务器的远程套接字变量超出了作用域,从而导致它被关闭(而这个问题在你的 C++ 版本中不存在)?

假设情况确实如此,我可以用这段代码在服务器上产生一个非常类似的 TCP 序列:

# server.py
import socket
from time import sleep

def f(s):
        r,a = s.accept()
        print r.recv(100)

s = socket.socket()
s.bind(('localhost',1234))
s.listen(1)

f(s)
# wait around a bit for the client to send it's second packet
sleep(10)

客户端的代码是:

# client.py
import socket
from time import sleep

s = socket.socket()
s.connect(('localhost',1234))

s.send('hello 1')
# wait around for a while so that the socket in server.py goes out of scope
sleep(5)
s.send('hello 2')

启动你的数据包嗅探器,然后运行 server.py,再运行 client.py。这里是 tcpdump -A -i lo 的输出,与你的观察结果相符:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes
12:42:37.683710 IP localhost:33491 > localhost.1234: S 1129726741:1129726741(0) win 32792 <mss 16396,sackOK,timestamp 640881101 0,nop,wscale 7>
E..<R.@.@...............CVC.........I|....@....
&3..........
12:42:37.684049 IP localhost.1234 > localhost:33491: S 1128039653:1128039653(0) ack 1129726742 win 32768 <mss 16396,sackOK,timestamp 640881101 640881101,nop,wscale 7>
E..<..@.@.<.............C<..CVC.....Ia....@....
&3..&3......
12:42:37.684087 IP localhost:33491 > localhost.1234: . ack 1 win 257 <nop,nop,timestamp 640881102 640881101>
E..4R.@.@...............CVC.C<......1......
&3..&3..
12:42:37.684220 IP localhost:33491 > localhost.1234: P 1:8(7) ack 1 win 257 <nop,nop,timestamp 640881102 640881101>
E..;R.@.@...............CVC.C<......./.....
&3..&3..hello 1
12:42:37.684271 IP localhost.1234 > localhost:33491: . ack 8 win 256 <nop,nop,timestamp 640881102 640881102>
E..4.(@.@...............C<..CVC.....1}.....
&3..&3..
12:42:37.684755 IP localhost.1234 > localhost:33491: F 1:1(0) ack 8 win 256 <nop,nop,timestamp 640881103 640881102>
E..4.)@.@...............C<..CVC.....1{.....
&3..&3..
12:42:37.685639 IP localhost:33491 > localhost.1234: . ack 2 win 257 <nop,nop,timestamp 640881104 640881103>
E..4R.@.@...............CVC.C<......1x.....
&3..&3..
12:42:42.683367 IP localhost:33491 > localhost.1234: P 8:15(7) ack 2 win 257 <nop,nop,timestamp 640886103 640881103>
E..;R.@.@...............CVC.C<......./.....
&3%W&3..hello 2
12:42:42.683401 IP localhost.1234 > localhost:33491: R 1128039655:1128039655(0) win 0
E..(..@.@.<.............C<......P...b...

9 packets captured
27 packets received by filter
0 packets dropped by kernel

撰写回答