Threading and tcp/ip connections problems - python

I'm new in python and threading so please be indifferent. I'm trying to do 2-players game in python. Data are send through tcp/ip protocol (client-server architecture). On server I have three threads. One comunicate with one user, second with second and in third thread I'm getting data which was send by client form two others threads. This data are used to check if game is over. And it's all working good. Problems start now. When the game is over I want to send another data to client. So Thread 3 need to send data to client, but two others threads are still working and they still have connections with clients. Generally I do not know how to do this. I tried to send information through the Queue from third thread to others that they should close theirs connections. It's thread class code:
class myThread(threading.Thread):
def __init__(self, threadID, name, conn, conn2, kto, wartosc,
wybor,kolejkaZadan,gracz1,gracz2):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.conn = conn
self.conn2 = conn2
self.kto = kto
self.wartosc = wartosc
self.wybor = wybor
self.kolejkaZadan = kolejkaZadan
self.gracz1 = gracz1
self.gracz2 = gracz2
def run(self):
if self.wybor == None:
toClient(self.conn,self.conn2,self.kto,self.wartosc,self.gracz1)
else:
while True:
data,kolejkaZwrotna = self.kolejkaZadan.get() // I receive data from two others threads
time.sleep(10)
dataKolejne,kolejkaZwrotna = self.kolejkaZadan.get() // I receive data from two others threads
if data is dataKolejne: // if end
tworzenieXmla(self.gracz1, self.gracz2)
odczytywanieXmla('itemGracza1',gracz1Otrzymane)
plik = open('Marcin.xml', 'rb')
czyZamknacConnection = True
kolejkaZwrotna.put(czyZamknacConnection) // send data to two others threads
while True:
czescXmla = plik.read(10000)
#self.conn2.send(czescXmla)
And It's my send/receiv function which is executed by two other threads:
def toClient(conn, conn2, kto, wartosc,gracz):
wordsBackup = None
kolejkaZwrotna = queue.Queue()
while True:
data = conn.recv(BUFFER_SIZE)
if not data:
break
if kolejkaZwrotna.get() is True://receive form thread 3
conn2.close()
print('closed')
break
if len(data)>7:
print('WARNING', data)
words = str(data.decode()).split()
#print(words[0], words[1])
if kto==1:
conn2.send(data)
if kto==2:
conn2.send(data)
kolejkaZadan.put(words[2],kolejkaZwrotna) // send to thread 3
xmlTablicaDoZapisu(str(int(words[0])),str(int(words[1])),str(int(words[2])),gracz)
Generally there is no error and we can play but there is only one player on each computer so I think server don't send data. I would appreciate any help.

A fix for your current situation would be to change all those connection variables into an array of connections which you could iterate over. You might want to build some container classes which define their behavior since not all clients are the same ( server client, and player clients ). That way you aren't limited by the amount of variables you've declared, and threads available.
Then once a new client connects you simply add it to the array and your iterator will take care of the rest.
This is a common problem with TCP/IP though, in that you always have to have open connections to n clients, which not only takes up resources but since TCP/IP is a queued protocol it could also set the entire game back if any client has a slower connection. In practice your game will always be as laggy as the player with the worst connection.
You have a couple of options.
You can have one thread always open which handles connections. Your supervisor thread. It holds an array of open connections' data and dispenses actions to the other threads. This isn't the best option since you'll quickly encounter Race Conditions such as two threads trying to use the same data.
You can switch over to UDP which will leave your threads wide open since there's no persistent connection. You'd then need to send states to each client, and once they ACK them you can get rid of the data. The majority of games implement UDP now'a'days, even turn based ones.
Beej's guide is probably the most extensive on the internet about UDP/TCP and socket control theory.
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html
And there's also Gaffer on Games which is a fantastic resource as well.
http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/

Related

Python multiprocessing queue generating strange data behavior

I'm working with a little project that is essentially one RPi2 distributing data to four RPi1. This is done via socket, and every client that connects to the RPi2 gets its own process. There are also one process capturing images and one waiting for new clients(on the RPi2).
The capture process sends four(at most) vectors to the "client processes" and they send to the (ecery) RPi1:s via socket.
My problem is: When I run more than one client, there seem to be some kind of communication fault, ether in the IPC or the socket. Because data that are supposed to be sent to RPi1_A ends up on RPi1_B.
Can it have something to do with the queue going between processes that aren't in a Parent-Child relation?
Some snippets from the code:
# Create a list of queues
Main_Queue = [Queue(IPC_QUEUE_SIZE)]*MAX_NUMBER_OF_CONNECTIONS
#Creation of Camera process:
Camera_process = Process(target=Camera_capture, args=(Main_Queue,Client_Update_Queue, ))
#Wait for client snippet:
conn, addr = s.accept()
p.append((Process(target=clientthread, args=(conn , Main_Queue[nr_of_clients] ,Client_Update_Queue, sock_lock, )),addr[0],addr[1]))
p[len(p)-1][0].start()
nr_of_clients = nr_of_clients + 1

Python Twisted: read from file and send as TCP server

I am completely new to Twisted, but it looks very promising for my project.
I would like to write a Python Twisted application which reads a record from text file every x seconds and contemporary listen on a TCP port (acting as TCP server). If no clients are connected to the TCP server the records are just discarded. If one or more clients are connected to the TCP server, the records are sent to all clients (all clients will receive the same line of the text file)
Can Twisted make this possible with a reasonable amount of LOCs?
Could anybody suggest an example to start with?
Thanks
C
Twisted's documentation includes information about how to run a TCP server. It also includes an information about how to perform work based on the passage of time. This should cover most of what you need to know.
Jean-Paul,
thanks for your answer.
Below is what i put together. The program is sending strings with time stamps to one or more clients connected to the server. Read synchronously from file in this scenario is very simple so i just use a fixed string with the time stamp.
My next step is to substitute the datetime.datetime.now() function call with a call to web service. Basically what i would like to create is kind of proxy that is
client versus a web service and invoke it every x seconds to get the data
TCP server versus a set of clients to stream data continuously, or better to say once a new data chunk is available (as is doing the example below)
The questions are:
Can you point me to an example of a similar system?
How can I combine the runEverySecond() method call with an asynchronous call to the web service using TCPClient capability of Twisted?
Thanks
C
from twisted.internet import protocol, reactor
from twisted.internet import task
import datetime
class Stream(protocol.Protocol):
def __init__(self, f):
self.factory = f
def connectionMade(self):
self.start = True
def forward(self, data):
if self.start:
self.transport.write(data)
class StreamFactory(protocol.Factory):
def __init__(self):
self.connections = []
def buildProtocol(self, addr):
s = Stream(self)
self.connections.append( s )
return s
def runEverySecond(self):
for c in self.connections:
c.forward( str(datetime.datetime.now()) )
f = StreamFactory()
l = task.LoopingCall(f.runEverySecond)
l.start(1.0) # call every second
reactor.listenTCP(8000, f)
reactor.run()

Producing content indefinitely in a separate thread for all connections?

I have a Twisted project which seeks to essentially rebroadcast collected data over TCP in JSON. I essentially have a USB library which I need to subscribe to and synchronously read in a while loop indefinitely like so:
while True:
for line in usbDevice.streamData():
data = MyBrandSpankingNewUSBDeviceData(line)
# parse the data, convert to JSON
output = convertDataToJSON(data)
# broadcast the data
...
The problem, of course, is the .... Essentially, I need to start this process as soon as the server starts and end it when the server ends (Protocol.doStart and Protocol.doStop) and have it constantly running and broadcasting a output to every connected transport.
How can I do this in Twisted? Obviously, I'd need to have the while loop run in its own thread, but how can I "subscribe" clients to listen to output? It's also important that the USB data collection only be running once, as it could seriously mess things up to have it running more than once.
In a nutshell, here's my architecture:
Server has a USB hub which is streaming data all the time. Server is constantly subscribed to this USB hub and is constantly reading data.
Clients will come and go, connecting and disconnecting at will.
We want to send data to all connected clients whenever it is available. How can I do this in Twisted?
One thing you probably want to do is try to extend the common protocol/transport independence. Even though you need a thread with a long-running loop, you can hide this from the protocol. The benefit is the same as usual: the protocol becomes easier to test, and if you ever manage to have a non-threaded implementation of reading the USB events, you can just change the transport without changing the protocol.
from threading import Thread
class USBThingy(Thread):
def __init__(self, reactor, device, protocol):
self._reactor = reactor
self._device = device
self._protocol = protocol
def run(self):
while True:
for line in self._device.streamData():
self._reactor.callFromThread(self._protocol.usbStreamLineReceived, line)
The use of callFromThread is part of what makes this solution usable. It makes sure the usbStreamLineReceived method gets called in the reactor thread rather than in the thread that's reading from the USB device. So from the perspective of that protocol object, there's nothing special going on with respect to threading: it just has its method called once in a while when there's some data to process.
Your protocol then just needs to implement usbStreamLineReceived somehow, and implement your other application-specific logic, like keeping a list of observers:
class SomeUSBProtocol(object):
def __init__(self):
self.observers = []
def usbStreamLineReceived(self, line):
data = MyBrandSpankingNewUSBDeviceData(line)
# broadcast the data
for obs in self.observers[:]:
obs(output)
And then observers can register themselves with an instance of this class and do whatever they want with the data:
class USBObserverThing(Protocol):
def connectionMade(self):
self.factory.usbProto.observers.append(self.emit)
def connectionLost(self):
self.factory.usbProto.observers.remove(self.emit)
def emit(self, output):
# parse the data, convert to JSON
output = convertDataToJSON(data)
self.transport.write(output)
Hook it all together:
usbDevice = ...
usbProto = SomeUSBProtocol()
thingy = USBThingy(reactor, usbDevice, usbProto)
thingy.start()
factory = ServerFactory()
factory.protocol = USBObserverThing
factory.usbProto = usbProto
reactor.listenTCP(12345, factory)
reactor.run()
You can imagine a better observer register/unregister API (like one using actual methods instead of direct access to that list). You could also imagine giving the USBThingy a method for shutting down so SomeUSBProtocol could control when it stops running (so your process will actually be able to exit).

Multiple socket monitoring

I'm designing a python program that'll talk to two other process at the same time through sockets. One of the process is a C daemon so this socket will be alive all the time - no problem there. The other process is a PHP web page. So that socket isn't established all the time. Most of the time, the socket is listen()ing on a port.
If both socket are alive all the time, a simple select() call can be used to monitor input from both. But in my situation, this is not possible. How can I achieve this easily?
Thanks,
You can use select() in this case, even in a single-threaded single-process program with only blocking sockets. Here's how you would accept incoming connections with select():
daemonSocket = socket.socket()
...
phpListenSocket = socket.socket()
phpListenSocket.bind(...)
phpListenSocket.listen(...)
phpSocket = None
while True:
rlist = ...
rready, wready, eready = select(rlist, [], [])
if phpListenSocket in rready:
phpSocket, remoteAddr = phpListenSocket.accept()

Do I have a threading issue here?

I have been experimenting with GNU Radio and came across the tunnel.py program. This program allows you to tunnel IP traffic over a wireless radio link using Linux TUN/TAP devices. For the most part it is working however one part of the code is confusing me.
There is a class which implements a 'basic MAC layer'. This class has a callback function which writes a new packet to the TUN device. This function (phy_rx_callback) is called from a separate thread.
The function main_loop does a carrier sense before transmitting a new packet. The thing I don't understand is why it is sensing a receive channel before transmitting on a separate non-overlapping transmit channel.
Both the RX and TX channels are separate frequencies, and our hardware allows full-duplex communication.
SO, my question is with main_loop executing, what are the implications of another thread asynchronously calling the phy_rx_callback function? The problem is I am trying to understand the purpose of the carrier sense loop, I found that commenting that code severely decreases performance. It doesn't make sense to me that you would monitor a receive channel before using a transmit channel, essentially turning it into half-duplex. Then I don't see the purpose of using two frequencies, one for transmit and one for receive. I began to wonder if there was a strange threading issue at work here.
A single instance of the cs_mac class is created initially. A 'pointer' to the rx_callback function is passed down a few levels to the thread class which actually calls it. Here is the cs_mac class:
class cs_mac(object):
def __init__(self, tun_fd, verbose=False):
self.tun_fd = tun_fd # file descriptor for TUN/TAP interface
self.verbose = verbose
self.tb = None # top block (access to PHY)
def set_top_block(self, tb):
self.tb = tb
def phy_rx_callback(self, ok, payload):
if self.verbose:
print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload))
if ok:
os.write(self.tun_fd, payload)
def main_loop(self):
min_delay = 0.001 # seconds
while 1:
payload = os.read(self.tun_fd, 10*1024)
if not payload:
self.tb.send_pkt(eof=True)
break
if self.verbose:
print "Tx: len(payload) = %4d" % (len(payload),)
delay = min_delay
while self.tb.carrier_sensed():
sys.stderr.write('B')
time.sleep(delay)
if delay < 0.050:
delay = delay * 2 # exponential back-off
self.tb.send_pkt(payload)
Ok, so using ctypes.CDLL('libc.so.6').syscall(186)), which calls gettid I discovered that the thread calling the rx_callback function has the same PID, but a different TID.
The question becomes, what are the implications of having a separate thread call a function from an object in the main thread (while that thread is constantly looping)?
The function main_loop does a carrier sense before transmitting a new packet. The thing I don't understand is why it is sensing a receive channel before transmitting on a separate non-overlapping transmit channel.
The CSMA/CA is intended to be used with half-duplex systems, where all nodes use the same frequency to TX and RX. So you are right, there is no point in sensing the RX channel if you are transmitting in a different one.
carrier_sensed() is called in the receive_path.py file so it should run in the RX thread. In my code I comment out the lines sys.stderr.write('B') and time.sleep(delay) and this does not seem to affect performance. It might be different in my case since I use an XCVR daughter board which is half-duplex.

Categories