Socket Programming Multiple Clients - One Server Python - python

Sorry for the long post. I am writing a TCP socket server which communicates with two different clients (client1 and client2). The server receives request from client1 and on receiving the request, the server sends data to client2 and in turn client2 responds with required data.
In detail, client1 is an android device requesting some location information from the server. On receiving the request, the server communicates with the computer (client2) that hosts the location information and the information is given from client2 to server. The received information is further communicated from server to client1 (android device).
For implementing this, I have the following steps written:
1. Since there may be number of android devices (client1) connecting to the server, there is a thread handling the connections with client1 over a port (port1).
2. Once the server gets a request from android device, it communicates with location client (client2) and get the required data.
3. Communication with client2 happens over same port and that works fine.
4. After receiving the data from client2, the server has to transfer the obtained data back to client1.
I am facing problem in step4. ie, I created a socket inside the function that transfers the data to client2 in a different port (port2) and transferred the data. But I am getting the following error "Address already in use".
To avert this, I tried transferring the information over the socket connection (created on port1) from within the function. The data transfer is failing, that is client2 is not receiving the data sent over the socket.
class ClientThread(Thread):
def __init__(self,ip,port,obj_socket_connect):
Thread.__init__(self)
self.obj_socket_connect = obj_socket_connect
def run(self):
read_data = conn.recv(2048)
if read_data == "loc_info_req":
self.obj_socket_connect.request_for_location()
Another class that communicates the data from client2 and send the data to client1.
class socket_connect:
def __init__(self):
self.write_android_request_port = Port2
def request_for_location(self):
# Information requested to client 2
self.read_loc_data(c_write)
def read_loc_data(self,c_read):
read_data = c_read.recv(15)
# Data processing for sending the info to client1
self.write_to_android_dev_data(read_data)
# Writing the required information to android on another port
# The problem of "Address already in use occurs here"
def write_to_android_dev_data(self,data_to_write):
s2 = socket.socket() # Create a socket object
s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = socket.gethostname()
s2.bind(('', self.write_android_request_port))
s2.listen(5)
c_write,address = self.s2.accept()
c_write.send(data_to_write)
s2.close()
The main function is given below:
if __name__ == "__main__":
obj_socket_connect = socket_connect()
print "Read write ports assigned"
# Multithreaded Python server : TCP Server for android devices connection
TCP_PORT = Port1
BUFFER_SIZE = 20
tcpServer = socket.socket()
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServer.bind(('', TCP_PORT))
threads = []
# Thread is created everytime when new Android device is connected (client1)
while True:
tcpServer.listen(4)
print "Multithreaded Python server : Waiting for connections from TCP clients..."
(conn, (ip,port)) = tcpServer.accept()
# Calling the thread function and creating the object
newthread = ClientThread(ip,port,obj_socket_connect)
newthread.start()
threads.append(newthread)
for t in threads:
t.join()
All the above pieces of code, belongs to same file and this acts as the TCPserver.
Client1 : (Android device)
The android device sends the request through writing on the Port1, sends the string "loc_info_req". This works fine as the information is available in server after request. On receiving the request the server communicates with client 2 (another computer)
Client 2 is another computer sending data on request.
Server - Client2 data transfer works fine, but the problem is when data has to be transferred back to client1 from server.
For receiving the data on Android device, I have the following lines of code:
# When tried to receive the data on Port1, the information is not getting
# transferred here. So, receiving data on another port.
android_loc_client = new Socket(TCP_IP, Port2);
android_loc_client.setSoTimeout(100000);
BufferedReader input_info = new BufferedReader(new
InputStreamReader(android_loc_client.getInputStream()));
message = input_info.readLine();
Note: I am not having enough credits to upload images for better explanation. Or I have a pictorial representation of what is written here. The data transfer works fine for few iterations and after sometime, the error of "Address already in use" error comes. Tried closing and shutdown the socket inside server. Still the error persists.

Related

conn.send('Hi'.encode()) BrokenPipeError: [Errno 32] Broken pipe (SOCKET)

hi i make model server client which works fine and i also create separate GUI which need to two input server IP and port it only check whether server is up or not. But when i run server and then run my GUI and enter server IP and port it display connected on GUI but on server side it throw this error. The Server Client working fine but integration of GUI with server throw below error on server side.
conn.send('Hi'.encode()) # send only takes string BrokenPipeError: [Errno 32] Broken pip
This is server Code:
from socket import *
# Importing all from thread
import threading
# Defining server address and port
host = 'localhost'
port = 52000
data = " "
# Creating socket object
sock = socket()
# Binding socket to a address. bind() takes tuple of host and port.
sock.bind((host, port))
# Listening at the address
sock.listen(5) # 5 denotes the number of clients can queue
def clientthread(conn):
# infinite loop so that function do not terminate and thread do not end.
while True:
# Sending message to connected client
conn.send('Hi'.encode('utf-8')) # send only takes string
data =conn.recv(1024)
print (data.decode())
while True:
# Accepting incoming connections
conn, addr = sock.accept()
# Creating new thread. Calling clientthread function for this function and passing conn as argument.
thread = threading.Thread(target=clientthread, args=(conn,))
thread.start()
conn.close()
sock.close()
This is part of Gui Code which cause problem:
def isOpen(self, ip, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, int(port)))
data=s.recv(1024)
if data== b'Hi':
print("connected")
return True
except:
print("not connected")
return False
def check_password(self):
self.isOpen('localhost', 52000)
Your problem is simple.
Your client connects to the server
The server is creating a new thread with an infinite loop
The server sends a simple message
The client receives the message
The client closes the connection by default (!!!), since you returned from its method (no more references)
The server tries to receive a message, then proceeds (Error lies here)
Since the connection has been closed by the client, the server cannot send nor receive the next message inside the loop, since it is infinite. That is the cause of the error! Also there is no error handling in case of closing the connection, nor a protocol for closing on each side.
If you need a function that checks whether the server is online or not, you should create a function, (but I'm sure a simple connect is enough), that works like a ping. Example:
Client function:
def isOpen(self, ip, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((str(ip), int(port)))
s.send("ping".encode('utf-8'))
return s.recv(1024).decode('utf-8') == "pong" # return whether the response match or not
except:
return False # cant connect
Server function:
def clientthread(conn):
while True:
msg = conn.recv(1024).decode('utf-8') #receiving a message
if msg == "ping":
conn.send("pong".encode('utf-8')) # sending the response
conn.close() # closing the connection on both sides
break # since we only need to check whether the server is online, we break
From your previous questions I can tell you have some problems understanding how TCP socket communication works. Please take a moment and read a few articles about how to communicate through sockets. If you don't need live communications (continous data stream, like a video, game server, etc), only login forms for example, please stick with well-known protocols, like HTTP. Creating your own reliable protocol might be a little complicated if you just got into socket programming.
You could use flask for an HTTP back-end.

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()

How to make 2 clients connect each other directly, after having both connected a meeting-point server?

I'm writing a toy meeting-point/relay server listening on port 5555 for two clients "A" and "B".
It works like this: every byte received by the server from the firstly-connected client A will be sent to the secondly-connected client B, even if A and B don't know their respective IP:
A -----------> server <----------- B # they both connect the server first
A --"hello"--> server # A sends a message to server
server --"hello"--> B # the server sends the message to B
This code is currently working:
# server.py
import socket, time
from threading import Thread
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(('', 5555))
socket.listen(5)
buf = ''
i = 0
def handler(client, i):
global buf
print 'Hello!', client, i
if i == 0: # client A, who sends data to server
while True:
req = client.recv(1000)
buf = str(req).strip() # removes end of line
print 'Received from Client A: %s' % buf
elif i == 1: # client B, who receives data sent to server by client A
while True:
if buf != '':
client.send(buf)
buf = ''
time.sleep(0.1)
while True: # very simple concurrency: accept new clients and create a Thread for each one
client, address = socket.accept()
print "{} connected".format(address)
Thread(target=handler, args=(client, i)).start()
i += 1
and you can test it by launching it on a server, and do two netcat connections to it: nc <SERVER_IP> 5555.
How can I then pass the information to the clients A and B that they can talk directly to each other without making the bytes transit via the server?
There are 2 cases:
General case, i.e. even if A and B are not in the same local network
Particular case where these two clients are in the same local network (example: using the same home router), this will be displayed on the server when the 2 clients will connect to the server on port 5555:
('203.0.113.0', 50340) connected # client A, router translated port to 50340
('203.0.113.0', 52750) connected # same public IP, client B, router translated port to 52750
Remark: a previous unsuccesful attempt here: UDP or TCP hole punching to connect two peers (each one behind a router)
and UDP hole punching with a third party
Since the server knows the addresses of both clients, it can send that information to them and so they would know each others adress. There are many ways the server can send this data - pickled, json-encoded, raw bytes. I think the best option is to convert the address to bytes, because the client will know exactly how many bytes to read: 4 for the IP (integer) and 2 for the port (unsigned short). We can convert an address to bytes and back with the functions below.
import socket
import struct
def addr_to_bytes(addr):
return socket.inet_aton(addr[0]) + struct.pack('H', addr[1])
def bytes_to_addr(addr):
return (socket.inet_ntoa(addr[:4]), struct.unpack('H', addr[4:])[0])
When the clients receive and decode the address, they no longer need the server, and they can establish a new connection between them.
Now we have two main otions, as far as I know.
One client acts as a server. This client would close the connection to the server and would start listening on the same port. The problem with this method is that it will only work if both clients are on the same local network, or if that port is open for incoming connections.
Hole punching. Both clients start sending and accepting data from each other simultaneously. The clients must accept data on the same address they used to connect to the rendezvous server, which is knwn to each other. That would punch a hole in the client's nat and the clients would be able to communicate directly even if they are on different networks. This proccess is expleined in detail in this article Peer-to-Peer Communication Across Network Address Translators, section 3.4 Peers Behind Different NATs.
A Python example for UDP Hole Punching:
Server:
import socket
def udp_server(addr):
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.bind(addr)
_, client_a = soc.recvfrom(0)
_, client_b = soc.recvfrom(0)
soc.sendto(addr_to_bytes(client_b), client_a)
soc.sendto(addr_to_bytes(client_a), client_b)
addr = ('0.0.0.0', 4000)
udp_server(addr)
Client:
import socket
from threading import Thread
def udp_client(server):
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.sendto(b'', server)
data, _ = soc.recvfrom(6)
peer = bytes_to_addr(data)
print('peer:', *peer)
Thread(target=soc.sendto, args=(b'hello', peer)).start()
data, addr = soc.recvfrom(1024)
print('{}:{} says {}'.format(*addr, data))
server_addr = ('server_ip', 4000) # the server's public address
udp_client(server_addr)
This code requires for the rendezvous server to have a port open (4000 in this case), and be accessible by both clients. The clients can be on the same or on different local networks. The code was tested on Windows and it works well, either with a local or a public IP.
I have experimented with TCP hole punching but I had limited success (sometimes it seems that it works, sometimes it doesn't). I can include the code if someone wants to experiment. The concept is more or less the same, both clients start sending and receiving simultaneously, and it is described in detail in Peer-to-Peer Communication Across Network Address Translators, section 4, TCP Hole Punching.
If both clients are on the same network, it will be much easier to communicate with each other. They would have to choose somehow which one will be a server, then they can create a normal server-client connection. The only problem here is that the clients must detect if they are on the same network. Again, the server can help with this problem, as it knows the public address of both clients. For example:
def tcp_server(addr):
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.bind(addr)
soc.listen()
client_a, addr_a = soc.accept()
client_b, addr_b = soc.accept()
client_a.send(addr_to_bytes(addr_b) + addr_to_bytes(addr_a))
client_b.send(addr_to_bytes(addr_a) + addr_to_bytes(addr_b))
def tcp_client(server):
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect(server)
data = soc.recv(12)
peer_addr = bytes_to_addr(data[:6])
my_addr = bytes_to_addr(data[6:])
if my_addr[0] == peer_addr[0]:
local_addr = (soc.getsockname()[0], peer_addr[1])
... connect to local address ...
Here the server sends two addresses to each client, the peer's public address and the client's own public address. The clients compare the two IPs, if they match then they must be on the same local network.
The accepted answer gives the solution. Here is some additional information in the case "Client A and Client B are in the same local network".
This situation can indeed be detected by the server if it notices that both clients have the same public IP.
Then the server can choose Client A as "local server", and Client B as "local client".
The server will then ask Client A for its "local network IP". Client A can find it with:
import socket
localip = socket.gethostbyname(socket.gethostname()) # example: 192.168.1.21
and then send it back to the server. The server will communicate this "local network IP" to Client B.
Then Client A will then run a "local server":
import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.bind(('0.0.0.0', 4000))
data, client = soc.recvfrom(1024)
print("Connected client:", client)
print("Received message:", data)
soc.sendto(b"I am the server", client)
and Client B will run as a "local client":
import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server = ('192.168.1.21', 4000) # this "local network IP" has been sent Client A => server => Client B
soc.sendto("I am the client", server)
data, client = soc.recvfrom(1024)
print("Received message:", data)

Flask - how to read the raw input from non-HTTP request?

I have a device that sends commands to a webserver. I've redirected those commands to my own server, with the goal of use the device to run another part of my system. In short, the device sends commands, I intercept them and use them.
The commands are sent to my server,but are not valid HTTP requests. I'm trying to use flask to read them with python, because I'd like to have these commands go straight into another web app.
Note that I can't change how the commands are sent.
Using sockets, I can read the data. For instance, here is a version of the data sent via socket (data is meaningless, just for illustration):
b'#123456#A'
In constrast, as HTTP message looks like this:
b'POST / HTTP/1.1\r\nHost: 123.123.123.123:12345\r\nRequest info here'
I know how to filter these (they always start with a #). Can I hook flask to let me handle these request differently, before they are parsed as HTTP requests?
Update: The code I used to read the requests, in case it provides context:
import socket
host = ''
port = 5000
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(backlog)
while 1:
client, address = s.accept()
data = client.recv(size)
print("Request:")
print(data)
print("\n\n")
if data:
client.send(data)
client.close()

Connecting to multiple clients TCP modbus

I have a working modbus server and client using a python script I run on the ocmputer, it operates by using socket.connect with the client's ip and port to connect and allow for modbus requests to be exchanged.
I do not know how to apply this for multiple ip's. What I want my program to do is connect to 10 different modbus clients and query them all for information.
Is it possible to call multiple socket.connect to open multiple streams? and if so will it function similarly to a serial connection when each client will need a unique slave ID?
edit:
#sets all the standard values
PLC1_IP = '10.0.238.34'
PLC1_Port = 504
PLC2_IP = '10.0.188.34'
PLC2_Port = 505
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except (socket.error, msg):
print("Unable to create socket. " + msg[1])
sys.exit()
#connects to the plc using the port and ip
s.connect((PLC1_IP, PLC2_Port))
PDU = struct.pack(">BHH", Function_Write, coil_number, Coil_On)
MBPA = struct.pack('>HHHB', 100, PLC1_Protocall, PLC1_Length, PLC1_Unit)
s.send(MBPA+PDU)
s.recv(1024)
#insert main code here
#s.close
This is the code I am using at the moment to open a single connection and send my modbus packet. If I wanted to open a connection to the second PLC how would I do that?
def make_socket(ip):
s= socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.connecnt((ip,port))
return s
my_clients = [make_socket(ip) for ip in ip_addresses]
for client in my_clients:
client.send("Hello")
print client.recv(100) # or whatever
maybe something like that ... its hard without seeing any of your code ...

Categories