English 中文(简体)
How to correctly relay TCP traffic between sockets?
原标题:

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?

最佳回答

Is it possible to only read from socket A when we know that B is ready to receive data?

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.:

import select

def fromAtoB(A, B):
    r, w = select.select([A], [B], [])
    if not r: select.select([A], [], [])
    elif not w: select.select([], [B], [])
    B.sendall(A.recv(4096))
问题回答

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".

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 or send sizes, and the application is broken, then grouping the data sent into 1k blocks will break the app.





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签