I just can't manage to add Multithreading to my UDP Server.
A second client can connect, but instantly gets thrown out of the server when someone is already connected to it.
Could this be caused by something other than SingleThreading?
import sys, socket
localPort, remoteHost, remotePort = sys.argv[1].split(':')
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', localPort))
except:
fail('Failed to bind on port ' + str(localPort))
knownClient = None
knownServer = (remoteHost, remotePort)
sys.stderr.write('Ready.\n')
while True:
data, addr = s.recvfrom(32768)
print addr
if knownClient is None:
knownClient = addr
if addr == knownClient:
try:
s.sendto(data, knownServer)
except:
pass
else:
try:
s.sendto(data, knownClient)
except:
pass
You cannot write an UDP proxy with only port. How should you know from the answer of the server to which of the two connected clients you should send your answer. You have to open for each client a new socket to the remote server.
It's not Python but "networking" and for sure not "multithreading". You need to either direct the clients to different ports or create a new outgoing socket for each new client connection.
Because you have multiple sockets a very effective approach is to sit on select and wait for the incoming calls.
In order to identify the clients, it is also needed to keep a reference of the local addresses the new sockets are using to talk to the server.
Your code reworked to open a socket on each new incoming client connection. No guarantees, because that would involve network testing against an scenario (yours) which is unknown.
For a very robust implementation you would have to add error checking, socket removal for gone connections ...
import select
import socket
import sys
localPort, remoteHost, remotePort = sys.argv[1].split(':')
try:
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('', localPort))
except:
fail('Failed to bind on port ' + str(localPort))
localaddr = s.getsockname() # (localhost, localport)
remaddr = (remoteHost, remotePort)
sys.stderr.write('Ready.\n')
allsockets = [server]
proxysocks = dict()
origins = dict()
while True:
toread, _, _ = select.select(allsockets, [], [])
s = toread[0] # 1st socket available to read
data, orig = s.recvfrom(32768) # data, (remhost,remport)
dest = s.getsockname() # (localhost, localport)
if dst == localaddr: # client -> localserver
try:
p = proxysocks[orig] # find proxy sock
except KeyError: # new client connection
proxysocks[orig] = p = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
proxyaddr = p.getsockname() # keep local address of new socket
origins[proxyaddr] = orig # link proxyaddr -> clientaddr
allsockets.append(p) # make it "selectable"
p.sendto(remaddr, data) # send to server
else: # server -> proxyaddr
s.sendto(origins[dstaddr])
Related
I am trying to establish a peer to peer communication using UDP hole punching. I am first establishing a connection with the server and then trying to make communication between 2 clients, but I am not able to communicate between 2 computers that are behind 2 different NATs as I am not understanding what IP address and port must I enter for the establishment of communication.
Please tell me what changes must I make in the code below so that 2 computers are able to communicate.
P.S : External IP doesn't seem to work and I am not supposed to use any additional tool like ngrok
Server.py
import socket
import struct
import sys
server_listening_port = 12345
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sockfd.bind(("", server_listening_port))
print("Listening on the port " + str(server_listening_port))
client_requests = []
while True:
data, addr = sockfd.recvfrom(32)
client_requests.append(addr)
print("Connection from: " + str(addr))
if len(client_requests) == 2:
break
client_a_ip = client_requests[0][0]
client_a_port = client_requests[0][1]
client_b_ip = client_requests[1][0]
client_b_port = client_requests[1][1]
message = ": "
sockfd.sendto(str(client_a_ip).encode("utf-8") + message.encode("utf-8") + str(client_a_port).encode("utf-8"), client_requests[1])
sockfd.sendto(str(client_b_ip).encode("utf-8") + message.encode("utf-8") + str(client_b_port).encode("utf-8"), client_requests[0])
sockfd.close()
Above is the rendezvous server
ClientA.py
import socket
import struct
import sys
import time
master = ("Server_IP", Port)
#Create dgram udp socket
try:
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = "Hello"
sockfd.bind(('', 0))
sockfd.sendto(message.encode("utf-8"), master)
except socket.error:
print("Failed to create socket")
sys.exit()
# #Receiving peer info from server
peer_data, addr = sockfd.recvfrom(1024)
print (peer_data)
print("trying to communicate with peer")
peer_ip = peer_data.decode("utf-8").split(":")[0]
peer_port = int(peer_data.decode("utf-8").split(":")[1])
peer = (peer_ip, peer_port)
while 1:
message1 = input(str("You:>>"))
message = message.encode("utf-8")
sockfd.sendto(str(message).encode("utf-8"), peer)
incoming_msg, sendaddr = sockfd.recvfrom(1024)
incoming_msg = incoming_msg.decode("utf-8")
print("ClientB:>>",incoming_msg)
Above code is Client A
ClientB.py
import socket #For sockets
import struct
import sys #For exit
import time
master = ("Server_IP", port)
me = ("ClientB_IP", port)
#Create dgram udp socket
try:
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
message = "Hello"
sockfd.bind(('', 0))
sockfd.sendto(message.encode("utf-8"), master)
except socket.error:
print("Failed to create socket")
sys.exit()
# #Receiving peer info from server
peer_data, addr = sockfd.recvfrom(1024)
print (peer_data)
print("trying to communicate with peer")
peer_ip = peer_data.decode("utf-8").split(":")[0]
peer_port = int(peer_data.decode("utf-8").split(":")[1])
peer = (peer_ip, peer_port)
while 1:
incoming_msg, sendaddr = sockfd.recvfrom(1024)
incoming_msg = incoming_msg.decode("utf-8")
print("ClientA:>>", incoming_msg)
message = input(str("You :>>"))
message = message.encode("utf-8")
sockfd.sendto(str(message).encode("utf-8"), peer)
Above is client B
I am facing problem only in the IP address and port. So , please do help me with it to establish communication between 2 computers behind 2 different NATs
I'm currently on the same problem and I want to program it for myself. With some research I found a really good paper explaining the process in detail.
I let you know if I succeed.
https://bford.info/pub/net/p2pnat/
I'm trying to make a Python server where multiple clients can connect but I've run into a problem I tried everything that I found on the internet.
I'm running a laptop whit windows 7 and an I3 processor.
This is the file called tcp:
import socket
def make_server (ip,port):
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((ip, port))
server.listen(1)
return server
except Exception as ex:
print(ex)
return None
def accept(server):
conn, addr = server.accept()
return conn
def make_client():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return client
def client_connect(client,ip,port):
client.connect((ip,port))
def sendall(conn,mess):
conn.send(str(mess).encode("utf-8"))
def rec(conn,rate):
mess = conn.recv(rate).decode("utf-8")
return mess
def close(client):
client.close()
This is the server:
from multiprocessing import Process
from random import randint
import tcp
import sys
def start(sip, sport):
print("Making sob server...")
print("id= {}".format(sport))
sserver = tcp.make_server(sip, sport)
print("Sub Server Started!")
sconn = tcp.accept(sserver)
tcp.sendall(sconn, "connected!!")
while True:
try:
tcp.sendall(sconn, randint(0, 100))
except Exception as ex:
print("")
print("From server {} error:".format(port))
print(ex)
print("")
break
ip = "192.168.0.102"
port = 8000
subport = 9000
server = tcp.make_server(ip, port)
if server is None:
sys.exit(0)
print("Started!")
while True:
print("Wating for new connection!")
con = tcp.accept(server)
print("Connected!")
subport = subport + 1
tcp.sendall(con, subport)
print("New Port Sent!")
print("New Port = {}".format(subport))
subs = Process(target=start, args=(ip, subport))
subs.start()
subs.join()
This is the client:
import tcp
import time
nport = 0
ip = "192.168.0.102"
port = 8000
client = tcp.make_client()
tcp.client_connect(client,ip,port)
nport = tcp.rec(client,1024)
print(nport)
tcp.close(client)
nport = int(nport)
time.sleep(1)
print(nport)
client = tcp.make_client()
tcp.client_connect(client,ip,nport)
while True:
mess = tcp.rec(client, 1024)
if(mess):
print(mess)
The error is:
[WinError 10048]Only one usage of each socket address (protocol/network address/port) is normally permitted Python
Feel free to change anything you want.
If you need any info in plus just ask.
You are creating a socket in the client with tcp.make_client. You are then using that socket to connect to the server via tcp.client_connect. Presumably you successfully receive the new port number back from the server. But then you are trying to re-use the same socket to connect to those ports.
This is the proximate cause of your error: A socket can only be used for a single TCP connection. If you want to create a new connection, you must first create a new socket.
That being said, if you are simply trying to create a server that will accept multiple connections, you're making it way too complicated. The server can receive any number of connections on its single listening port, as long as a different address/port combination is used by each client.
One way to structure this in a server is something like this:
# Create and bind listening socket
lsock = socket.socket()
lsock.bind(('', port))
lsock.listen(1)
while True:
csock, addr = lsock.accept()
print("Got connection from {}".format(addr))
# Start sub-process passing it the newly accepted socket as argument
subs = Process(target=start, args=(csock, ))
subs.start()
# Close our handle to the new socket (it will remain open in the
# sub-process which will use it to talk to the client)
csock.close()
# NOTE: do not call subs.join here unless you want the parent to *block*
# waiting for the sub-process to finish (and if so, what is the point in
# creating a sub-process?)
There are several others ways to do it as well: you can create multiple threads to handle multiple connections, or you can handle all connections in a single thread by using select or with asynchronous I/O.
The client is typically much simpler -- as it usually only cares about its own one connection -- and doesn't care which way the server is implemented:
sock = socket.socket()
sock.connect((ip, port))
while True:
sock.send(...)
sock.recv(...)
If the client does wish to connect to the same server again, it simply creates a second socket and call its connect method with the same server IP and port.
Usually, the client never needs to specify its own port, only the server's port. It simply calls connect and the client-side operating system chooses an unused port for it. So the first time, the client creates a socket and connects it (to the server's listening port), the client-side OS may choose port 50001. The next time it creates and connects a socket, it may get 50002 and so on. (The exact port numbers chosen depend on the operating system implementation and other factors, such as what other programs are running and creating connections.)
So, given client IP 192.168.0.101 and server IP 192.168.0.102, and assuming the server is listening on port 8000, this would result in these two connections:
(192.168.0.101/50001) ====> (192.168.0.102/8000)
(192.168.0.101/50002) ====> (192.168.0.102/8000)
For some reason i cant seem to be able to create a host or client where the client can always send a message to the host whenever . i can only send one message and after that nothing is received .
my while loops should allow me to do this so i don't know why this is no achievable for me ;'()
#Host server
import socket
server_host= 'localhost'
server_port= 88
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((server_host,server_port))
server.listen(5)
print('listening on {} port {}'.format(server_host,server_port))
while True:
client,addr = server.accept()
recieve = client.recv(2024)
print(recieve.decode())
Client :
# Python-Socket-Client
import socket
#'localhost'
# 88
target_server = str(input('Target_Host:'))
target_port = int(input('Target_Port:'))
client = socket.socket(socket.AF_INET , socket.SOCK_STREAM )
client.connect((target_server,target_port))
print('\n')
print('****************************')
print(target_server)
print(target_port)
def send_and_recieve_message(message):
#response = client.recv(4065)
if type(message) == str:
client.send(message.encode())
while True:
mess= input("{}:".format('Client'))
send_and_recieve_message(mess)
In your host code server.accept() is a blocking call. It will wait until someone connects. You need to separate it out of your while loop. And then check if the connection is still valid if not wait for another connection.
while True:
client,addr = server.accept()
while client != None:
recieve = client.recv(2024)
print(recieve.decode())
Something similar to this you probably will want to add a better check to see if the connection is still valid.
I know that similar questions have been raised but they don't seem to work for me! I have tried serializing the dictionary then converting that to a string then encoding it before I send it over the socket. No success so far!
This is my server code:
#library
import socket
import pickle
#socket initialization
host = "127.0.0.1"
port = 5000
mainAddr = (host, port)
#dict initialization
dataDict = {} #just imagine that dict has content
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.bind((mainAddr))
s.listen(4)
print('program started')
print('listening..')
while True:
try:
conn, addr = s.accept()
print("connection from: "+str(addr))
print("sending message..")
pickle.dumps(dataDict)
print('pickled!')
dataS = str(dataP)
print('stringed!')
dataE = dataS.encode('UTF-8')
print('encoded!')
s.sendto(dataE,addr)
print('data sent!')
except:
pass
s.close()
For the socket initialization, I've tried other types:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #UDP
s = socket.socket()
For the sending part, I've tried these alternatives:
s.send(dataE)
s.send(dataE,addr)
s.sendall(dataE)
s.sendall(dataE,addr)
When I run the program, these get printed out:
program started
listening..
connection from:<insert addr here>
sending message..
pickled!
stringed!
encoded!
Only data sent! is not sent. So I am guessing that it's the sending part that has a problem.
For the client side, here's the code:
#library
import socket
import pickle
#initialization
host = '127.0.0.1'
port = 5000
buffer = 1024
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.connect((host,port))
print('connected!')
#receive dictionary
print('receiving message..')
while True:
data, addr = s.recvfrom(buffer)
print('received!')
dataD = data.decode("UTF-8")
print('decoded!')
dataP = pickle.loads(dataD)
print('unpickled!')
print(str(dataP))
s.close()
In the client terminal, only the following prints:
connected!
receiving message..
On the client side, I've tried changing the order of unpickling and decoding but still, to no avail.
A TCP server socket is not actually used for sending/receiving data; I'm surprised you're not getting an error when calling s.send() or similar on it. Instead, it's a factory for producing individual sockets for each client that connects to the server - conn, in your code. So, conn.sendall() is what you should be using. No address parameter is required, the individual socket already knows who it is talking to. (.send() is unreliable without some extra work on your part; .sendto() is only used with UDP sockets that have not been connected to a particular client.)
I have a server written in python 2.7 that executes an infinite loop and process information from port 5000. Is it possible to change this connection port without restarting the server?
For example: the server is running in port 5000 and receives a 'change_port' option, the server module has to stop listening in port 5000 to start listening in port 7000. I don't know if i can manipulate sockets like that... Thanks
Once you have bound a socket to an address (interface, port) it cannot be changed. However, you can create a new socket (or many, depending on your needs) and bind it to your address (interface, port).
The code will differ based on the transport layer protocol you're using:
TCP:
# 1) Create first socket
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('0.0.0.0',5000))
# 2) Create second socket
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind(('0.0.0.0',7000))
# 3) Wait for a connection on the first socket
s1.listen(5)
sc, address = s1.accept()
# 4) Once a connection has been established...
# send, recv, process data
# until you need the next socket
# 5) Open connection on second socket
s2.listen(1)
sc2, address2 = s2.accept()
# now it probably a good time to tell the client (via s1) that s2 is ready
# client connects to s2
There you go
UDP (almost the same):
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.bind(('0.0.0.0',5000))
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2.bind(('0.0.0.0',7000))
data, addr = s1.recvfrom(256)
s1.sendto("s2 ready",addr)
data2, addr2 = s2.recvfrom(256)
Simplified, but that's all there really is to it.
You might consider verifying that the address of the client from s1 is the same as the client connecting to s2.
No, it seems that you cannot run the socket.bind() method when its already bound. However, I have a solution you can use with the Asyncore module.
Heres my server:
import asyncore
import socket
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(8192)
if data:
print "Recieved Data: ", data, ". This server address:", self.getsockname()
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print 'Incoming connection from %s' % repr(addr)
handler = EchoHandler(sock)
server = EchoServer('localhost', 56787)
server = EchoServer('localhost', 56788)
asyncore.loop()
Here are my clients:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 56787))
data = ""
while data.upper() != "Q":
data = raw_input("Enter something to send to the server")
s.send(data)
s.close()
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 56788))
data = ""
while data.upper() != "Q":
data = raw_input("Enter something to send to the server")
s.send(data)
s.close()
This worked well, the python handled both ports. You should also be able to define seperate server classes for each of your ports.