I am using my Raspberry as a server and client at the same time. However, my RPI don't enable the connection as server after it connecting to another device as a client. The requirement is, the RPI has to connect to several devices at once.
The minimal example with ethernet cable would be:
Device A <-----ETH-----> RPI <-----ETH-----> Device B
So in the above configuration, first connecting it to Device B as a client, Device A can not be connected to the RPI. If I use it as a standalone server/client it works perfectly but as parallel functionality it doesnt work. There is no error message, Device A just doesnt connect to the Raspberry.
Note that, I am connecting device A via Ethernet-to-USB adapter and it works perfectly as standalone server. I am using multiprocessing for each device on the raspberry.
Any help is appreciated.
I note that in that configuration the raspberry acts as access point (?). The functionality of the raspberry is, that it has to forward the incoming messages to another device, so that each device doesn't know the port or IP address of each other, only the PI does.
So my simplified code for the raspberry is:
walkie_talkie.py
import socket
# socket.socket(socket.AF_INET, socket.SOCK_STREAM)
class walkie_talkie(socket.socket):
'''Inherits all functionalities of sockets.sockets
Use this class for connection using TCP/IP e.g. internet/ethernet
Example usage:
>>> from walkie_talkie import walkie_talkie
>>> wt = walkie_talkie()
>>> wt.BUFFERSIZE = 8
...
'''
def __init__(self):
self.BUFFERSIZE = 8192
self.STATE = None
self.IP = None # Server IP
self.PORT = 5000
self.NUMBER_OF_UNACCEPTED_CONNECTIONS = 1
self.bytestream = None
self.PROTOCOL = socket.SOCK_STREAM # Using UDP: socket.SOCK_DGRAM
super().__init__(socket.AF_INET, self.PROTOCOL)
def setup_server(self):
print('****** SERVER SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** SERVER SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'SERVER'
self.bind((self.IP, self.PORT))
self.listen(self.NUMBER_OF_UNACCEPTED_CONNECTIONS)
self.CONN, self.ADDRESS = self.accept()
def setup_client(self):
print('****** CLIENT SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** CLIENT SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'CLIENT'
#self.settimeout(10.0)
self.connect((self.IP, self.PORT))
#self.settimeout(None)
print('Connected.')
Since I also have to stream the data through multiple ports of the same devices, I am using multiprocessing for each communication tunnel.
multiprocessing_rpi.py
import socket
from walkie_talkie import walkie_talkie
import multiprocessing
import time
def setup_alpha_watchdog(IP, PORT):
''' Creates an alpha watchdog
:param str IP: Server IP on Raspberry to listen to
:param int PORT: Server Port to open for Device A
'''
global BUFFERSIZE
print('alpha Watchdog >> {} @ {}'.format(IP, PORT))
alpha_watchdog = walkie_talkie()
alpha_watchdog.IP = IP
alpha_watchdog.PORT = PORT
alpha_watchdog.BUFFERSIZE = BUFFERSIZE
try:
# Setup alpha watchdog and omega watchdog right afterwards
alpha_watchdog.setup_server()
omega_watchdog = setup_omega_watchdog(DEVICE_B_IP, PORT) # returns a walkie_talkie object as client
superstream(alpha=alpha_watchdog,
omega=omega_watchdog)
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
pass
def setup_omega_watchdog(IP, PORT):
''' Creates an omega watchdog
Description:
omega watchdog takes data from alpha watchdog and pass them to the specified device
If the connection is denied, abort both watchdogs.
:param str IP: Server IP of Device B to connect to
:param int PORT: Server Port on Device B to send data to
'''
global BUFFERSIZE
print('omega Watchdog >> {} @ {}'.format(IP, PORT))
watchdog = walkie_talkie()
watchdog.IP = IP
watchdog.PORT = PORT
watchdog.BUFFERSIZE = BUFFERSIZE
try:
watchdog.setup_client()
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
return watchdog
def superstream(alpha, omega):
'''Streams data between the watchdogs on Request-Response scheme
Description:
After setting alpha & omega watchdogs, the communication takes place after incoming signal from alpha passed to omega.
For example, the byte b'\x02\x00\x00\x00\xff\x00' coming from Device A will be passed to alpha watchdog
and the raspberry will then pass this byte to the omega watchdog and finally to the Device B.
:param object alpha: An alpha watchdog
:param object omega: An omega watchdog
'''
while 1:
try:
# Get data coming from Device A and send it directly to Device B
data_from_Device_A = alpha.CONN.recv(alpha.BUFFERSIZE)
omega.send(data_from_Device_A )
# Get response from Device B and send back to Device A
RESPONSE= omega.recv(omega.BUFFERSIZE)
alpha.CONN.send(RESPONSE)
except Exception as e1:
print('Error: ' + str(e1))
break
alpha.shutdown(2)
alpha.close()
omega.shutdown(2)
omega.close()
if __name__ == '__main__':
THIS_RPI_IP= '169.254.244.192' # IP of raspberry, so Device A can connect to it
DEVICE_B_IP = '192.xxx.....' # Device B IP
# Reserve ports correlating number of devices
SERVER_PORTS = [5000,
# 5001,
# 5002,
# 5003,
# 5004,
5005]
SERVER_IP = THIS_RPI_IP
BUFFERSIZE = 8192
PROCESS_LIST = []
#For each port, setup a socket for clients
for PORT in SERVER_PORTS:
p = multiprocessing.Process(target=setup_alpha_watchdog, args=(THIS_RPI_IP, PORT,))
PROCESS_LIST.append(p)
p.start()
for _ in PROCESS_LIST:
_.join()
In setup_alpha_watchdog
I can swap the line, where I first connect as client to device B (Successfully!) and then listen to device A, however I am not able to establish a connection as server to device A.