I'm writing a proxy with tcp connection that listens to multiple ports from a client and forward it to a server.
The problem is that the software hangs on the sock.accept.
Maybe I'm doing a messy logic here, but I need a client that connects to a PC, and that PC connects to another device. So I wrote that small proxy, and I get INVALID ARGUMENT ERROR in socket.accept()
import select
import socket
import threading
class Proxy(object):
def __init__(self, ip, ports):
self._ip = ip
self._sockets = []
self._proxy = {}
for port in ports:
self._proxy[port] = self.add_socket(port)
def add_socket(self, port=None):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if port:
# sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sock.bind(('0.0.0.0',port))
self._sockets.append(sock)
return sock
def get_client(self, src_sock, src_addr):
src_ip, src_port = src_addr
_, dst_port = src_sock.getsockname()
if src_ip == self._ip:
# got packet from device
dst_addr = ("10.8.8.210", dst_port)
else:
# got packet from client
dst_addr = self._ip, dst_port
print(">", src_port, dst_addr)
dst_sock = self._proxy[src_port]
return dst_sock, dst_addr
def run(self):
while True:
read_list, _, _ = select.select(self._sockets, [], [])
if read_list:
for sock in read_list:
try:
conn, addr = sock.accept()
data = conn.recvfrom(16*2024)
# print("got data from {} {}".format(sock, addr))
dst_sock, dst_addr = self.get_client(sock, addr)
# print("forwarding data from {} to {}".format(addr, dst_addr, len(data)))
dst_sock.sendto(data, dst_addr)
except:
raise # pass # print("no recipient for data")
for s in self._sockets:
s.close()
ports = [30001,30002,30003, 30070, 30071,30072,30075]
p = Proxy("192.168.2.10", ports)
p.run()
You have to call listen on the socket before accept:
adding sock.listen(1) to add_socket after bind
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', port))
sock.listen(1)
self._sockets.append(sock)
then allows you to call accept without the error. You may want to set the listen backlog to a greater number.
Related
So I would like to have a variable as the socket server ip address... I have some issues. I get the issue with server.bind(ADDR)
import socket
import requests
import threading
def controller(conn, addr):
connected = True
while connected:
msg_length = conn.recv(HEADER).decode(FORMAT)
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
if msg == DISCONNET:
connected = False
print(f'{msg}')
def start():
print('Server: Server Started')
server.listen()
while True:
conn, addr = server.accept()
thread = threading.Thread(target = controller, args = (conn, adrr))
thread.start()
host_name = socket.gethostname()
prip = socket.gethostbyname(host_name)
puip = requests.get('https://api.ipify.org').text
HEADER = 128
PORT = 5050
SERVER = puip
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNET = '!DISCONNECT'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
start()
Error Message:
server.bind((SERVER, PORT))
OSError: [WinError 10049] The requested address is not valid in its context
I cant figure out why the client is not communicating with the Server (2 seperate jupyter notebooks with own kernel), no error messages - any suggestions?
the following code is working (without multiprocessing):
Server:
import socket
HOST = '127.0.0.1'
PORT = 50000
def start_server():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
print ('waiting for client')
conn, addr = s.accept()
print('client connected #', addr[0], 'port:', addr[1])
return conn
Server0 = start_server()
Client:
import socket
HOST = '127.0.0.1'
PORT = 50000
data = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect_ex((HOST, PORT))
while True:
byte_message = s.recv(1024)
string_message = byte_message.decode('utf8')
header, time, data = string_message.split(' ')
if header == 'close':
s.shutdown(socket.SHUT_RDWR)
s.close()
print('client connection shut down')
header = ''
elif header == '<<':
print(time,float(data))
else:
pass
As soon as I pack the client into a function and run it as a process, client and server do not connect anymore(no error is given, and the server doesent get to this line:
print('client connected #', addr[0], 'port:', addr[1])
not working client:
import socket
import multiprocessing
HOST = '127.0.0.1'
PORT = 50000
def client():
data = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect_ex((HOST, PORT))
while True:
byte_message = s.recv(1024)
string_message = byte_message.decode('utf8')
header, time, data = string_message.split(' ')
if header == 'close':
s.shutdown(socket.SHUT_RDWR)
s.close()
print('client connection shut down')
header = ''
elif header == '<<':
print(time,float(data))
else:
pass
client_process = multiprocessing.Process(target= client)
client_process.start()
Im trying to implement both TCP and UDP in my server. I can accept a TCP or UDP port connection from a client.
for example, I want to have code to accept TCP and UDP in one program:
# create a socket
sockTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
sockUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
# server address to connect to
server_addressTCP = ('localhost', tcp_port)
server_addressUDP = ('localhost', udp_port)
# bind socket to adress and port number
sockTCP.bind(server_addressTCP)
sockUDP.bind(server_addressUDP)
# wait for connections (clients)
print("Waiting for connections...")
print(" ")
sockTCP.listen(20)
request = ''
while True:
#TCP
client_sock, client_addr = sockTCP.accept()
data, addr = client_sock.recvfrom(1024)
#UDP
udp_data, udp_addr = sockUDP.recvfrom(1024)
# DO SOMETHING WITH DATA.........
client_sock.close()
If you want to implement a server that listens on UDP and TCP then create listener threads: one for UDP and one for TCP connections.
Here is an example of a server listening on both TCP and UDP ports.
import socket
import threading
tcp_port = udp_port = 1234
def udp_listen(conn):
while True:
data = conn.recv(1024)
if len(data) != 0:
print("recv:", data)
def tcp_listen(sock):
while True:
conn, _ = sock.accept()
try:
while True:
data = conn.recv(1024)
if len(data) == 0:
break
print("recv:", data)
except Exception:
pass
try:
conn.close()
except Exception:
pass
# create a socket
sockTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
sockUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
# server address to connect to
server_addressTCP = ('localhost', tcp_port)
server_addressUDP = ('localhost', udp_port)
# bind socket to adress and port number
sockTCP.bind(server_addressTCP)
sockUDP.bind(server_addressUDP)
sockTCP.listen(20)
t1 = threading.Thread(target=tcp_listen, args=(sockTCP,))
t2 = threading.Thread(target=udp_listen, args=(sockUDP,))
print("Waiting for connections...")
t1.start()
t2.start()
t1.join()
t2.join()
I'm trying to send a message from Client to Server using socket. For some reason, the message is not received. example: the client sends 'myname_0' the server needs to receive it and decode it and continue further.
Listener:
import socket
class SocketSender():
def __init__(self):
self.sock = socket.socket()
ip = socket.gethostname() # IP to server.
port = 7000
self.sock.bind((ip, port))
print("Binding successful.")
self.sock.listen(2)
print("Listening....")
self.listening = True
# self.sock.connect((ip, port))
# print("Connected.")
def sendpacket(self, packet):
self.sock.send(packet.encode())
def receivepacket(self):
while self.listening:
con, addr = self.sock.accept()
print("Receiving packet from " + str(addr))
packet = self.sock.recv(1024).decode("utf-8")
return str(packet)
Sender:
import socket
sock = socket.socket()
ip = socket.gethostname()
port = 7000
sock.connect((ip, port))
print("connection to " + ip)
message = "test_0"
sock.send(message.encode("utf-8"))
When run:
import GUI
import SocketSender
# Entry: 0, Exit: 1
gui = GUI.ASGui()
# gui.run()
socket = SocketSender.SocketSender()
id = input()
while 1 == 1:
packet = socket.receivepacket()
name, state = packet.split("_")
break
if state == 0:
print("Welcome back, " + name)
else:
if state == 1:
print("Goodbye, " + name)
I do get the outputs Listening and Binded. But I am unable to receive a message. Help would be appreciated. Thank you.
I found online a simple multiclient echo server in Python using threads:
#!/usr/bin/env python
import socket
import sys
import threading
class Client(threading.Thread):
def __init__(self, ip, port, connection):
threading.Thread.__init__(self)
self.connection = connection
self.ip = ip
self.port = port
def run(self):
data = self.connection.recv(1024)
if data :
self.connection.sendall(data)
else :
self.connection.close()
class Server:
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server = None
self.clients = []
def open_socket(self):
try:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(self.address)
except socket.error, e:
if self.server:
self.server.close()
sys.exit(1)
def run(self):
self.open_socket()
self.server.listen(5)
while True :
connection, (ip, port) = self.server.accept()
c = Client(ip, port, connection)
c.start()
self.clients.append(c)
self.server.close()
if __name__ == '__main__':
s = Server('127.0.0.1', 6666)
s.run()
And I wrote a client:
import socket
import sys
port = 6666
size = 1024
s = None
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
s.connect(('127.0.0.1', port))
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket: " + message
sys.exit(1)
data = raw_input('> ')
s.sendall(data)
data = s.recv(size)
print "Server sent: %s " % data
s.close()
Everything works great but I wonder how could I add to the server the functionality of broadcast to be able to echo back the message to all connected clients? Or be able to send a message to a specific client?
I have all clients in server's class, but I do not know how to (and where in the server's code, in Client class or Server class place the code to broadcast and send private messages? Thank you.
EDIT:
New server:
#!/usr/bin/env python
import socket
import sys
import threading
class Client(threading.Thread):
def __init__(self, ip, port, connection):
threading.Thread.__init__(self)
self.connection = connection
self.ip = ip
self.port = port
def run(self):
while True:
data = self.connection.recv(1024)
if data :
self.connection.sendall(data)
else :
break
self.connection.close()
class Server:
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server = None
self.clients = []
def send_to_all_clients(self, msg):
for client in self.clients :
client.connection.send(msg)
def send_to_client(self, ip, port, msg):
for client in self.clients :
if client.ip == ip and client.port == port :
client.connection.send(msg)
def open_socket(self):
try:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(self.address)
except socket.error, e:
if self.server:
self.server.close()
sys.exit(1)
def run(self):
self.open_socket()
self.server.listen(5)
while True :
connection, (ip, port) = self.server.accept()
c = Client(ip, port, connection)
c.start()
self.clients.append(c)
self.server.close()
if __name__ == '__main__':
s = Server('127.0.0.1', 6666)
s.run()
New client:
import socket
import sys
port = 6666
size = 1024
s = None
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
s.connect(('127.0.0.1', port))
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket: " + message
sys.exit(1)
while True:
data = raw_input('> ')
s.sendall(data)
data = s.recv(size)
print "Server sent: %s " % data
s.close()
Since you already have a list of clients in your Server , you could use it in a function like that :
def send_to_all_clients(self, msg):
for client in self.clients :
client.connection.send(msg)
Then you can make a function to select a specific client :
def send_to_client(self, ip, port, msg):
for client in self.clients :
if client.ip == ip and client.port == port :
client.connection.send(msg)
Note
It's best to add a Send() method to Client and call it to send the msg instead of using client.connection.send(msg)
You could use those functions in the server's run method , if you modify it to handle events
( you could do that with select.select() , or with user input ( KeyboardInterrupt ) , etc , the design is up to you ) .
Also you should modify both client.py and Client , and make them more persistent , because now they close as soon as they sendall or recv .
I hope this gives you some ideas