Echoing messages received through UDP back through a different TCP port - python

I use Python 2.7.x (2.7.8) and am trying to write a program using twisted python to function like this:
Program waits for a messaged received through TCP 7001 or UDP 7000.
Messages received through UDP 7000 are bridged over to TCP 7001 going out.
I couldn't figure out how to bridge UDP to TCP, so I looked up an example on this site, like this one, Twisted UDP to TCP Bridge but the problem is that the example is lying because it doesn't work. I added a "print datagram" on datagramReceived to see if UDP responds to receiving anything at all and it does not. This is totally frustrating.
Here's my current test code altered a little bit from that example:
from twisted.internet.protocol import Protocol, Factory, DatagramProtocol
from twisted.internet import reactor
class TCPServer(Protocol):
def connectionMade(self):
self.port = reactor.listenUDP(7000, UDPServer(self))
def connectionLost(self, reason):
self.port.stopListening()
def dataReceived(self, data):
print "Server said:", data
class UDPServer(DatagramProtocol):
def __init__(self, stream):
self.stream = stream
def datagramReceived(self, datagram, address):
print datagram
self.stream.transport.write(datagram)
def main():
f = Factory()
f.protocol = TCPServer
reactor.listenTCP(7001, f)
reactor.run()
if __name__ == '__main__':
main()
As you can see I changed the ports to comply with my test environment and added a print datagram to see if anything calls datagramReceived. I have no problems sending TCP things to this program, TCPServer works just fine because dataReceived can be called.

I ran the code from your question (with one slight modification: I enabled logging). I used telnet to connect to the TCP server on port 7001. I used a Python REPL to create a UDP socket and send some datagrams to port 7000.
Here is my REPL transcript:
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.sendto('hello', ('127.0.0.1', 7000))
5
>>> s.sendto('world', ('127.0.0.1', 7000))
5
>>>
Here is my server log (formatted to fit on your screen):
... Log opened.
... Factory starting on 7001
... Starting factory <twisted.internet.protocol.Factory instance at 0x2b9b128>
... UDPServer starting on 7000
... Starting protocol <__main__.UDPServer instance at 0x2e8f8c0>
... hello
... world
And here's my telnet session transcript:
$ telnet localhost 7001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
helloworld
My interpretation of these results is that the program actually works as specified. I wonder what you did differently when you tried it that produced different, non-working results.

Related

Is it possible to use the same network socket simultaneously for listen and connect with the same port?

I want to use socket to implement that the client/server can send and receive the files from each other. The client can send and receive the files from the server and vice versa for the server. Also, need to use the Tkinter module to complete the server and client GUI.
When the 2 GUIs are initialed, a thread is started to listen to the connection from the opposite end. That means the server has a thread for listening and accepting the connection from the client while receiving the file from the client, and at the client-side, the thread is used to listen and accept the connection from the server.
My confusion is that whether do I need 2 ports, one is used for sending file from the client to the server, another one is to receiving the files from the server? And do I need to create 2 sockets for sending and receiving files?
My current solution is using 2 ports and 2 sockets in the client-side. when sending the file, the client-side acts the client, while receiving file it acts the server. Correct?
To be brief, is it possible to use the same network socket simultaneously for listen and connect to with the same port? Or must I have two separate sockets, and if so, must the separate sockets also be bound to separate network ports? 
Here is a simplified code that explains my questions. Any advice/comments are appreciated. Thanks.
class client():
def __init__(self):
self.clientTcpSock = None
self.initUI()
def initUI(self):
#create UI here
def createSocket(self):
s.clientTcpSock = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind((HOST, PORT_1)) #PORT_1 download file port
s.listen(5)
self.clientTcpSock = s
def sendFile(self):
# !!! Here creates a new TCP socket, or can i still use the same clientTcpSock??
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.connect((HOST, PORT_2)) # PORT_2 upload file port
s.send(b'hello world') # just for example
def receiveFile(self):
while True:
### receivefile here
self.clientTcpSock.close()
# call this function when init UI
def newTherad(self):
thread = threading.Thread(target=self.receiveFile, args=())
thread.setDaemon(True)
thread.start()

Twisted: How to send messages by twisted client on single port?

I may send messages to server from twisted client by calling connector.connect(). But clients will be made on different ports. Following code is demonstrated this case:
SERVER_HOST = 'localhost'
SERVER_PORT = '5000'
class EchoClient(protocol.Protocol):
def connectionMade(self):
self.transport.write("message")
self.transport.loseConnection()
class EchoFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
print('Connected.')
return EchoClient()
def clientConnectionLost(self, connector, reason):
print('Lost connection. Reason:', reason)
connector.connect()
def main():
reactor.connectTCP(SERVER_HOST, SERVER_PORT, EchoFactory())
reactor.run()
And my twisted server say me:
Packet received, client 127.0.0.1:41930, size: 7
Connection lost
Packet received, client 127.0.0.1:41931, size: 7
Connection lost
Packet received, client 127.0.0.1:41932, size: 7
Connection lost
Packet received, client 127.0.0.1:41933, size: 7
Clients has different ports - 41930, 41931, etc. How send messages from twisted client with single port?
You can use the bindAddress parameter in either connectTCP, clientFromString, TCP4ClientEndpoint, or TCP6ClientEndpoint. Using your example, your code would look like:
reactor.connectTCP(SERVER_HOST, SERVER_PORT, EchoFactory(), bindAddress=('127.0.0.1',9999))
I would advise you to avoid this if it's not absolutely necessary because the port may be in use by another process and will cause an exception. It's better for the OS to chose the ip:port for your app to bind to.

Get the bare socket fd from a Twisted protocol in python?

What I would like to do is combine Twisted with the Cmd module in python's stdlib.
In short I would like to be able to get the bare-bones socket fd object from a connected Protocol to use as the stdin of the cmd.Cmd module in the stdlib.
In Long, My client that interfaces with my server uses the Cmd module to process commands and send those commands to the server.
On my server I would also like to use the same command processing method with the builting Cmd module. To do this i would need to specify the stdin and stdout of the command interpreter.
I could do this easily with the builtin sockets module, but i would like to do it with twisted if possible.
Here is some code to do what i want with plain sockets:
(Works with telnet)
# server
import socket
import cmd
class CmdProcessor(cmd.Cmd, object):
def __init__(self, sock, addr):
network = sock.makefile()
super(CmdProcessor, self).__init__(stdin=network, stdout=network)
self.sock = sock
self.addr = addr
# Run the cmd.Cmd processing loop
self.cmdloop()
def do_sayhi(self, args):
# When 'sayhi' is recieved over the socket,
self.sock.send("Hey yourself!")
def do_quit(self, args):
self.sock.close()
if __name__ == "__main__":
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.bind(("0.0.0.0", 2319))
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.listen(5)
sock, addr = server_sock.accept()
print("Connection accepted")
connection = CmdProcessor(sock, addr)
This is almost what i want to to do. I just typed this up quick so i may be missing somthing. Half of it works. Currently, if you telnet into the server like:
telnet 127.0.0.1 2319
And you send 'sayhi' nothing happens. But if you type 'sayhi' at the terminal you started the server from (There is a (Cmd) prompt) the output goes to the telnet client. So the stdout of the cmd.Cmd is working. But not the stdin. That probably has something to do with the fact that telnet sends CR-LF ('\r\n') by default. Where the cmd module may just listen for \n.
So how can get the fd or file object from a protocol in twisted to do what i am trying do achieve here with bare sockets?
And any insights on what the input from telnet connected to the server is not registering with the CmdProcessor?
Any advice, tips or pointers welcome. (Wait no, no pointers.)
Thanks.
I suggest that instead you might want to look at Manhole.
In general, the point of Twisted is not to use Python socket objects directly. That's a big part of Twisted's job. When you want to interact with the network using Twisted, you use Twisted's APIs instead - protocols and transports, if you're thinking about the lowest level.
You can add use_rawinput = False
class CmdProcessor(cmd.Cmd, object):
use_rawinput = False
def __init__(self, sock, addr):
....
This produces response for sayhi from telnet

Python asyncore UDP server

I am writing server application in Python that listens for requests, processes them, and sends a response.
All req/resp are send from the same address and port to the server application. I need to recv/send messages simultaneously, and the server need to recieve/send messages from/to the same port and address. I found some tutorials for asynchore sockets, but there are only examples for TCP connections.
Unfortunately, I need UDP. When I change SOCK_STREAM to SOCK_DGRAM in the create method, I get an error.
return getattr(self._sock,name)(*args)
socket.error: [Errno 95] Operation not supported
I tried to use twisted, but I dont know how to write the sender part, which can bind to the same port as its listening. The last result was blocked port.
Is there any way how to use asyncore sockets with UDP or how to use twisted to send from the same port? Some examples will be higly appreciated.
You can pretty much just write the sending and receiving part of your code and they'll work together. Note that you can send and receive on a single listening UDP socket - you don't need one for each (particularly if you want to send from and receive on the same address).
from __future__ import print_function
from sys import stdout
from twisted.python.log import startLogging
from twisted.internet import reactor
from twisted.internet.protocol import DatagramProtocol
class SomeUDP(DatagramProtocol):
def datagramReceived(self, datagram, address):
print(u"Got a datagram of {} bytes.".format(len(datagram)))
def sendFoo(self, foo, ip, port):
self.transport.write(
(u"Foo datagram: {}".format(foo)).encode("utf-8"),
(ip, port))
class SomeSender(object):
def __init__(self, proto):
self.proto = proto
def start(self):
reactor.callLater(3, self._send)
def _send(self):
self.proto.sendFoo(u"Hello or whatever", b"127.0.0.1", 12345)
self.start()
startLogging(stdout)
proto = SomeUDP()
reactor.listenUDP(12345, proto)
SomeSender(proto).start()
reactor.run()

Python TCP socket doesn't close?

Maybe someone here will have a response for this thing which is just driving me insane.
To make it simple, I'm making a kind of proxy. Whenever it receives something, it forwards everything to a server, and sends back the response. So there is one socket always listening on port 4557 for clients, and for each incoming connection, there is a new socket created on a random port to connect to the server port 4556.
Clients <==> Proxy <==> Server
Also, there another socket which is instantiated and listening for requests coming from the server and to be forwarded to the corresponding client.
Here is an example:
Client A connects to proxy on port 4557
Proxy creates a socket to Server on port 4556
Along with that, it creates a socket listening on port 40100
Client sends stuff, forwarded to Server
Client disconnects. Close client connection and socket to server
Some time later, Server sends stuff to proxy on port 40100
Everything's forwarded to Client A (port 40100 corresponding to Client A)
And so on..
So far in my tests, I use a simple python script for sending a unique tcp packet to the proxy, along with a dump server showing received data and echoing back.
So the issue is that when a connection to the proxy is closed, the connection to the Server should also be closed with "sock.close()". However it just seems to be completely ignored. The socket remains as ESTABLISHED.
About the code now.
A few notes.
DTN and Node are respectively Server and Clients.
runCallback is called in a loop until thread dies.
finalCallback is called when the thread is dying.
Associations between remote hosts (Client), proxy ports (to Server) and proxies are kept in the dictionaries: TCPProxyHostRegister (RemoteHost => Proxy), TCPProxyPortRegister (Port => Proxy), TCPPortToHost (Port => RemoteHost).
The first class is TCPListenerThread.
It just listen on a specific port and instantiate proxies (one for each Client=>Server couple and Server=>Client couple) and forward them connections.
class TCPListenerThread(StoppableThread):
def __init__(self, tcp_port):
StoppableThread.__init__(self)
self.tcp_port = tcp_port
self.sock = socket.socket( socket.AF_INET, # Internet
socket.SOCK_STREAM ) # tcp
self.sock.bind( (LOCAL_ADDRESS, self.tcp_port) )
self.sock.listen(1)
def runCallback(self):
print "Listen on "+str(self.tcp_port)+".."
conn, addr = self.sock.accept()
if isFromDTN(addr):
tcpProxy = getProxyFromPort(tcp_port)
if not tcpProxy:
tcpProxy = TCPProxy(host, True)
else:
host = addr[0]
tcpProxy = getProxyFromHost(host)
if not tcpProxy:
tcpProxy = TCPProxy(host, False)
tcpProxy.handle(conn)
def finalCallback(self):
self.sock.close()
Now comes the TCP Proxy:
It associates a remote host (Client) with a port connecting to Server.
If it's a connection coming from a new Client, it will create a new listener (see above) for the Server and create a socket ready to forward everything to Server.
class TCPProxy():
def __init__(self, remote, isFromDTN):
#remote = port for Server or Remote host for Client
self.isFromDTN = isFromDTN
self.conn = None
#add itself to proxy registries
#If listening from a node
if not isFromDTN:
#Set node remote host
self.remoteHost = remote
TCPProxyHostRegister[self.remoteHost] = self
#Set port to DTN interface + listener
self.portToDTN = getNewTCPPort()
TCPPortToHost[self.portToDTN] = self.remoteHost
newTCPListenerThread(self.portToDTN)
#Or from DTN
else:
self.portToDTN = remote
TCPProxyPortRegister[self.portToDTN] = self
self.remoteHost = getRemoteHostFromPortTCP(self.portToDTN)
def handle(self, conn):
print "New connection!"
#shouldn't happen, but eh
if self.conn != None:
self.closeConnections()
self.conn = conn
#init socket with remote
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if self.isFromDTN:
self.sock.connect((self.remoteHost, 4556)) #TODO: handle dynamic port..
else:
self.sock.connect((DTN_Address, DTN_TCPPort))
#handle connection in a thread
self.handlerThread = newTCPHandlerThread(self)
#handle reply in a therad
self.replyThread = newTCPReplyThread(self)
def closeConnections(self):
try:
if self.conn != None:
print "Close connections!"
self.sock.close()
self.conn.close()
self.conn = None
self.handlerThread.kill()
self.replyThread.kill()
except Exception, err:
print str(err)
#pass
def forward(self, data):
print "TCP forwarding data: "+data
self.sock.send(data)
def forwardBack(self, data):
print "TCP forwarding data back: "+data
self.conn.send(data)
In this proxy class, I instantiate two classes, TCPHandlerThread and TCPReplyThread. They are responsible for forwarding to Server, and forwarding back to Client, respectively.
class TCPHandlerThread(StoppableThread):
def __init__(self, proxy):
StoppableThread.__init__(self)
self.proxy = proxy
def runCallback(self):
test = False
while 1:
data = self.proxy.conn.recv(BUFFER_SIZE)
if test:
self.proxy.sock.close()
test = True
if not data:
break
print "TCP received data:", data
self.proxy.forward(data)
self.kill()
def finalCallback(self):
self.proxy.closeConnections()
class TCPReplyThread(StoppableThread):
def __init__(self, proxy):
StoppableThread.__init__(self)
self.proxy = proxy
def runCallback(self):
while 1:
data = self.proxy.sock.recv(BUFFER_SIZE)
if not data:
break
print "TCP received back data: "+data
self.proxy.forwardBack(data)
self.kill()
def finalCallback(self):
self.proxy.closeConnections()
You see that whenever a connection is closed, the thread dies and the other connection (Client/Server to proxy or Proxy to Server/Client) should be closed in Proxy.closeConnections()
I noticed that when closeConnections() is "data = self.proxy.conn.recv(BUFFER_SIZE)", it goes well, but when it's called even right after the latter statement, it goes wrong.
I wiresharked TCP, and the proxy doesn't send any "bye signal". The socket state doesn't go to TIME_WAIT or whatever, it just remains ESTABLISHED.
Also, I tested it on Windows and Ubuntu.
On Windows it goes exactly as I explained
On Ubuntu, it works well for usually (not always), 2 connections, and the third time I connect with the same client in exactly the same way to the proxy, it goes wrong again exactly as explained.
Here are the three files i'm using so that you can have a look at the whole code. I'm sorry the proxy file might not be really easy to read. Was SUPPOSED to be a quick dev.
http://hognerud.net/stackoverflow/
Thanks in advance..
It's surely something stupid. Please don't hit me too hard when you see it :(
First I'm sorry that I currently have not the time to actually run and test your code.
But the idea came to my mind, that your problem might actually have something todo with using blocking mode vs. non-blocking mode on the socket. In that case you should checkout the "socket" module help in the python documentation, especially socket.setblocking().
My guess is, that the proxy.conn.recv() function only returns, when actually BUFFER_SIZE bytes where received by the socket. Because of this the thread is blocked until enough data was received and therefore the socket doesn't get closed.
As I said first, this is currently just a guess, so please don't vote me down if it doesn't solve the problem...

Categories