如何在套接字之间正确中继 TCP 流量?
我正在尝试编写一些 Python 代码来在两个 TCP 套接字之间建立不可见的中继。我当前的技术是设置两个线程,每个线程在特定方向上一次读取并随后写入 1kb 数据(即 1 个线程用于 A 到 B,1 个线程用于 B 到 A)。
这适用于某些应用程序和协议,但并非万无一失 - 有时特定应用程序在通过这个基于 Python 的中继运行时会表现不同。有的甚至崩溃。
我认为这是因为当我完成对套接字 A 的读取时,运行在那里的程序认为它的数据已经到达 B,而事实上我 - 中间那个狡猾的人 - 还没有将其发送到 B。在 B 尚未准备好接收数据的情况下(即 send()
阻塞一段时间),我们现在处于 A 认为它已成功向 B 发送数据的状态,但我我仍然持有数据,等待 send()
调用执行。我认为这是我在使用当前中继代码时在某些应用程序中发现的行为差异的原因。我错过了什么吗?或者这听起来正确吗?
如果是这样,我真正的问题是:有办法解决这个问题吗?当我们知道 B 准备好接收数据时,是否可以只从套接字 A 读取数据?或者是否有另一种技术可以用来在[已经打开和已打开]之间建立真正的“隐形”双向中继。已建立] TCP 套接字?
I'm trying to write some Python code that will establish an invisible relay between two TCP sockets. My current technique is to set up two threads, each one reading and subsequently writing 1kb of data at a time in a particular direction (i.e. 1 thread for A to B, 1 thread for B to A).
This works for some applications and protocols, but it isn't foolproof - sometimes particular applications will behave differently when running through this Python-based relay. Some even crash.
I think that this is because when I finish performing a read on socket A, the program running there considers its data to have already arrived at B, when in fact I - the devious man in the middle - have yet to send it to B. In a situation where B isn't ready to receive the data (whereby send()
blocks for a while), we are now in a state where A believes it has successfully sent data to B, yet I am still holding the data, waiting for the send()
call to execute. I think this is the cause of the difference in behaviour that I've found in some applications, while using my current relaying code. Have I missed something, or does that sound correct?
If so, my real question is: is there a way around this problem? Is it possible to only read from socket A when we know that B is ready to receive data? Or is there another technique that I can use to establish a truly 'invisible' two-way relay between [already open & established] TCP sockets?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当然:在套接字 A 和B(如果它返回说只有其中一个准备好,则在另一个上使用它),并且只有当您知道它们都准备好时才从 A 读取并写入 B。例如:
Sure: use select.select on both sockets A and B (if it returns saying only one of them is ready, use it on the other one), and only read from A and write to B when you know they're both ready. E.g.:
我认为这不太可能是你的问题。
一般来说,发送应用程序无法判断接收应用程序何时实际调用 recv() 来读取数据:发送方的 send() 可能已完成,但源和源中的 TCP 实现可能已完成。目标操作系统将进行缓冲、流量控制、重传等。
即使中间没有中继,A“认为其数据已经到达 B”的唯一方法就是接收来自 B 的响应,说“是的,我得到了它”。
I don't think that's likely to be your problem.
In general, the sending application can't tell when the receiving application actually calls recv() to read the data: the sender's send() may have completed, but the TCP implementations in the source & destination OS will be doing buffering, flow control, retransmission, etc.
Even without your relay in the middle, the only way for A to "consider its data to have already arrived at B" is to receive a response from B saying "yep, I got it".
也许您代理的应用程序编写得不好。
例如,如果我调用
recv(fd, buf, 4096, 0);
我不会承诺 4096 字节。系统会尽力提供它。如果 1k 不是应用程序的
recv
或send
大小的倍数,并且应用程序已损坏,则将发送的数据分组为 1k 块将会损坏应用程序。Perhaps the application you're proxying is poorly written.
For instance, if I call
recv(fd, buf, 4096, 0);
I'm not promised 4096 bytes. The system makes a best-effort to provide it.If 1k isn't a multiple of your application's
recv
orsend
sizes, and the application is broken, then grouping the data sent into 1k blocks will break the app.