UDP Hole Punching Not Working For A P2P Network - python

I am back again with another UDP Hole Punching problem, I seem to have figured out the concept, but I still can not seem to apply it. Apparently, to punch a hole in the NAT you must first send a welcome message (or any message really) first then send the actual data. I am doing this, but it doesn't seem to be working when node to node communication needs to happen.
This code is apart of a P2P chat system I am developing.
import socket
import threading
import json
nodes = {}
class Marboo:
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.bi = ""
self.bp = 5002
self.cmds = {
"checkin":self.checkin,
"msg":self.msg,
}
self.nick = "test"
self.room = "a"
def main(self):
self.get_nodes()
while True:
data, addr = self.sock.recvfrom(102400)
data = json.loads(data)
print data
def prompt(self):
while True:
msg = raw_input(self.nick+"> ")
data = json.dumps({"cmd":"msg", "message":msg, "room":self.room, "nick":self.nick})
self.send(data)
def get_nodes(self):
self.sock.sendto("", (self.bi, self.bp))
data = self.sock.recv(1024)
nodes = json.loads(data)
for x in nodes:
self.connect(tuple(nodes[x]))
self.sock.sendto(json.dumps({"cmd":"checkin"}), tuple(nodes[x]))
def send(self, msg):
for x in nodes:
self.connect(tuple(nodes[x]))
self.sock.sendto(msg, tuple(nodes[x]))
def connect(self, addr):
self.sock.sendto(json.dumps({"cmd":"connect"}), addr)
def checkin(self):
pass
def msg(self):
pass
if __name__ == "__main__":
threading.Thread(target=Marboo().prompt).start()
Marboo().main()

Related

How I can check connection correctly

I have a boolean variable:
is_conected = False
And I have this part of code:
def start(self, host='localhost', port=32767):
self.__connection.bind((host, port))
self.__connection.listen(5)
def send_frame(self, frame: str):
if not self.__connection.send(bytes(frame, encoding='utf-8')):
raise RuntimeError("Connection broken.")
def recieve_frame(self) -> str:
socket, adress = self.__connection.accept()
str(__data) = socket.recv(1024)
__frame_buffer.append(__data)
Where I need to put If... Else, for checking, if someone connected or not? And what kind of condition I need to use?
The whole code:
import socket
class TCPServer():
__frame_buffer = list()
__connection = None
is_conected = True
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(TCPServer, cls).__new__(cls)
return cls.instance
def __init__(self):
self.__connection = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
def start(self, host='localhost', port=32767):
# """ Start server """
self.__connection.bind((host, port))
self.__connection.listen(5)
def send_frame(self, frame: str):
# """ Send frame """
if not self.__connection.send(bytes(frame, encoding='utf-8')):
raise RuntimeError("Connection broken.")
def recieve_frame(self) -> str:
socket, adress = self.__connection.accept()
str(__data) = socket.recv(1024)
__frame_buffer.append(__data)
def get_frame(self) -> str:
if self.__frame_buffer:
self.__frame_buffer.pop(0)
server = TCPServer()
while True:
if server.is_conected:
server.send_frame(str(input("String to send")))
print(server.get_frame())
That's the whole code. I don't write a more part of it, only a send and recieve frame function. So, that's kinda a school project for me and I'm not too good in working with any kind of connection or protocols
This is how the server generally works
with socket(AF_INET, SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen() # Start listening
while True:
conn, addr = s.accept() # Accept connection request
Connected = True # You are connected
try:
#Work with connection
except:
Connected = False
Figure out how you can do this with your code

How do multi-threading and infinite loops work together

I'm trying to learn python, doing exercise watching video online. I'm currently trying to do a multi-threading chat server but I think I have trouble understanding the way threads work.
Here's my code:
<!-- language: lang-py -->
import socket
import threading
class ThreadedServer(threading.Thread):
def __init__(self, host, port, buff_size):
threading.Thread.__init__(self)
self.host = host
self.port = port
self.buff_size = buff_size
self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(5)
while True:
print('Waiting for a connexion...')
self.c, self.addr = self.sock.accept()
listening = listenToClient(self.c, self.addr)
class listenToClient(threading.Thread):
def __init__(self, client, address):
threading.Thread.__init__(self)
global socks
socks.append(client)
client.send(("Bienvenue sur le serveur, entre ton pseudo: ").encode('utf-8'))
self.name = client.recv(buff_size).decode('utf-8')
welcome = "Welcome " + self.name + "! If ever you want to quit, type {quit}"
client.send(welcome.encode('utf-8'))
msg = self.name + " has joined the chat"
broadcast(msg)
while True:
msg = client.recv(buff_size).decode('utf-8')
if msg != '{quit}':
broadcast(msg, self.name + ": ")
print('TEST6')
else:
client.close()
leave_msg = self.name + " has left"
broadcast(leave_msg)
break
def broadcast(msg, prefix=''):
for sck in socks:
content = prefix + msg
sck.send(content.encode('utf-8'))
def Main():
ThreadedServer(host,port,buff_size).listen()
host = '127.0.0.1'
port = 10000
buff_size = 1024
socks = []
if __name__ == '__main__':
Main()
The code is working ok for only one user.
I think the problem is in my comprehension of threads.
In my mind, when I type
listening = listenToClient(self.c, self.addr)
a new thread is created running in parallel with the first one.
What I see in reality is that my new thread is indeed executing and ends in the infinite loop in here(managing whatever my first user connected is typing):
while True:
msg = client.recv(buff_size).decode('utf-8')
if msg != '{quit}':
broadcast(msg, self.name + ": ")
print('TEST6')
But I thought as the original thread would have continued looping here:
while True:
print('Waiting for a connexion...')
self.c, self.addr = self.sock.accept()
listening = listenToClient(self.c, self.addr)
Printing 'Waiting for a connection' and waiting for a second connection.
But it is not the case.
I'm pretty sure it's a misunderstanding on my side, I spent hours trying and trying changing everything etc, at some point the listenToClient() thread was just a method in the ThreadedServer(). But now I'm very lost and I don't know what to do, so I came here for help.
Thanks in advance,
Vincent

python TCP communication threaded, delay and error

I would like to ask you a question about a trouble i found while i was coding to improve my skill in TCP communication. Basically i first learn about socket and how to open server/client socket and communication. So i wrote one class for server and one for client, i test it and i found they work very fine for what i care: this is the server
class server_class:
def __init__(self, sock=None):
if sock is None:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
else:
self.sock = sock
def bind(self,host, port):
self.sock.bind((host, port))
def listen(self,client):
self.sock.listen(client)
def close_client(self):
self.client.close()
def accept(self):
self.client,self.c_addr=self.sock.accept()
def invia(self,MSGLEN,msg):
totalsent = 0
if(len(msg)<MSGLEN):
while(len(msg)<MSGLEN):
msg=msg+'*'
while totalsent < MSGLEN:
sent = self.client.send(msg[totalsent:].encode('ascii'))
if sent == 0:
raise RuntimeError
totalsent = totalsent + sent
def ricevi(self,MSGLEN):
msg = ''
while len(msg) < MSGLEN:
chunk = self.client.recv(MSGLEN-len(msg)).decode('ascii')
if chunk == '':
raise RuntimeError
msg = msg + chunk
i=0
messaggio=''
while(i<MSGLEN):
if(msg[i]!='*'):
mess=msg[i]
messaggio=messaggio+mess
else:
pass
i+=1
return messaggio
and this is the client:
class client_class:
def __init__(self, sock=None):
if sock is None:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
else:
self.sock = sock
def connect(self,host,port):
self.sock.connect((host, port))
def invia(self,MSGLEN,msg):
totalsent = 0
if(len(msg)<MSGLEN):
while(len(msg)<MSGLEN):
msg=msg+'*'
while totalsent < MSGLEN:
sent = self.sock.send(msg[totalsent:].encode('ascii'))
if sent == 0:
raise RuntimeError
totalsent = totalsent + sent
def ricevi(self,MSGLEN):
msg = ''
while len(msg) < MSGLEN:
chunk = self.sock.recv(MSGLEN-len(msg)).decode('ascii')
if chunk == '':
raise RuntimeError
msg = msg + chunk
i=0
messaggio=''
while(i<MSGLEN):
if(msg[i]!='*'):
mess=msg[i]
else:
pass
messaggio=messaggio+mess
i+=1
return messaggio
So no at all problem at this time. Next step i tried to do was to write a program that while doing some math or GUI or both, keep a server on for communicate to a client the information it work out in math for example. The only way i found to do this is use threading module.
I write 2 function, one for server and one for math (increase x value in while loop) and add in main a GUI. Then i pass each function to a thread.
This is the server function (that use server class defined before):
def server():
global Stop,x
server=server_class()
ip='192.168.1.134'
port=8033
server.bind(ip,port)
Stop=True
client=0
c_addr=0
while(Stop):
server.listen(1)
print("* inizio ascolto su",ip,":",port)
server.accept()
print("* mi sono connesso con",server.c_addr[0],":",server.c_addr[1])
while(Stop):
data=server.ricevi(100)
print(data)
if(data=="disconnetti"):
msg="bye bye"
server.invia(100,msg)
server.close_client()
print("*disconnetto il client")
break
if(data=="inviami x"):
msg=str(x)
server.invia(100,msg)
if(data=="chiudi server"):
print("*chiudo server")
server.close_client()
Stop=False
else:
msg="come?"
server.invia(100,msg)
This is the math function named 'go':
def go():
global x
while(x<10000):
x+=1
time.sleep(1)
Finally the main function is:
finestra=Tk()
finestra.geometry('800x800+300+300')
finestra.title('Prova threading')
testo_0=Label(finestra,text="Valore attuale:").grid(sticky=W,row=0,column=0)
gobutton=Button(finestra,text='Acquisisci',command=lambda: leggi())
gobutton.grid(row=2, column=1)
goo=threading.Thread(target=go)
serv=threading.Thread(target=server)
goo.start()
serv.start()
finestra.mainloop()
So go function increase continuously x value, server function keep a server listening and main thread keep a GUI within which a user can see x value by pressing a botton.
The server knows just 3 commands from client:
1)pass x to client
2)close client
3)close server
for other message it answer as unknown command.
What happen is that the communication doesn't work good; for example when from a client (running on other machine using the client class defined before) ask to server to pass x value (that go function is constantly increasing) happen 2 wrong things:
1) After the first communication other seems delayed, for example the second time i ask x value the server answer as unknown command, third time i send a request for x value it give me a value. Next time its going to answer as unknown and next give me a value and so on.
2) After the first communication too, the values that server pass to client are delayed, so for example if at the same time i send to server request for x and push the botton in GUI for read x value, these are going to be appreciably different.
This is the client script i use:
import time
import socket
class client_class:
def __init__(self, sock=None):
if sock is None:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
else:
self.sock = sock
def connect(self,host,port):
self.sock.connect((host, port))
def invia(self,MSGLEN,msg):
totalsent = 0
if(len(msg)<MSGLEN):
while(len(msg)<MSGLEN):
msg=msg+'*'
while totalsent < MSGLEN:
sent = self.sock.send(msg[totalsent:].encode('ascii'))
if sent == 0:
raise RuntimeError
totalsent = totalsent + sent
def ricevi(self,MSGLEN):
msg = ''
while len(msg) < MSGLEN:
chunk = self.sock.recv(MSGLEN-len(msg)).decode('ascii')
if chunk == '':
raise RuntimeError
msg = msg + chunk
i=0
messaggio=''
while(i<MSGLEN):
if(msg[i]!='*'):
mess=msg[i]
else:
pass
messaggio=messaggio+mess
i+=1
return messaggio
client=mysocket()
ip='192.168.1.134'
port=8033
client.connect(ip,port)
while(True):
print("inserire comando da inviare (max 100 Bytes)")
msg=input().encode('ascii')
client.invia(100,msg)
print(client.ricevi(100).decode('ascii'))
Any help will be appreciate, thank you very much and sorry for bad english
UPDATE
I found that if i close socket on each communication, so for example everytime i need to send a message i open a client socket and close it after send it, could solve the problem, no error and no delay.
Can't explain me why, so if anyone could answer it will be appreciated.
Thank you very much

Python - multithreaded sockets

From my understanding python can only run 1 thread at a time so if I were to do something like this
import socket, select
from threading import Thread
import config
class Source(Thread):
def __init__(self):
self._wait = False
self._host = (config.HOST, config.PORT + 1)
self._socket = socket.socket()
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._sock = None
self._connections = []
self._mount = "None"
self._writers = []
self._createServer()
Thread.__init__(self)
def _createServer(self):
self._socket.bind(self._host)
self._socket.listen(2)
self._connections.append(self._socket)
self._audioPackets=[]
def _addPacket(self, packet):
self._audioPackets.append(packet)
def _removePacket(self, packet):
self._audioPackets.remove(packet)
def _getPacket(self):
if len(self._audioPackets) > 0:
return self._audioPackets[0]
else:
return None
def _sendOK(self, sock):
sock.send("OK")
def _sendDenied(self, sock):
sock.send("DENIED")
def _sendMount(self, sock):
sock.send("mount:{0}".format(self._mount))
def _sendBufPacket(self, sock, packet):
packet = "buffer:%s" % packet
sock.send(packet)
def recv(self, sock, data):
data = data.split(":", 1)
if data[0] == "WAIT": self._wait = True
elif data[0] == "STOP_WAITING": self._wait = False
elif data[0] == "LOGIN":
if data[1] == config.SOURCE_AUTH:
self._source = sock
self._sendOK(sock)
else:
self._sendClose(sock)
elif data[0] == "MOUNT":
if self._source == sock:
self._mount = data[1]
else:
self._sendClose(sock)
elif data[0] == "CLIENT":
self._sendMount(sock)
self._writers.append(sock)
def _sendCloseAll(self):
for sock in self._connections:
sock.send("CLOSE")
sock.close()
def _sendClose(self, sock):
sock.send("CLOSE")
sock.close()
def main(self):
while True:
rl, wl, xl = select.select(self._connections, self._writers, [], 0.2)
for sock in rl:
if sock == self._socket:
con, ip = sock.accept()
self._connections.append(con)
else:
data = sock.recv(config.BUFFER)
if data:
self.recv(sock, data)
else:
if sock in self._writers:
self._writers.remove(sock)
if sock in self._connections:
self._connections.remove(sock)
for sock in wl:
packet = self._getPacket()
if packet != None:
self._sendBufPacket(sock, packet)
def run(self):
self.main()
class writeThread(Thread):
def __init__(self):
self.running = False
def make(self, client):
self.client = client
self.running = True
def run(self):
host = (config.HOST, config.PORT+1)
sock = socket.socket()
sock.connect(host)
sock.send("CLIENT")
sock.send("MOUNT:mountpoint")
while self.running:
data = sock.recv(config.BUFFER)
if data:
data = data.split(":", 1)
if data[0] == "buffer":
self.client.send(data[1])
elif data[0] == "CLOSE":
self.client.close()
break
if __name__=="__main__":
source = Source()
source.start()
webserver = WebServer()
webserver.runloop()
if I need to build the webserver part I will. But, I'll explain it.
Okay, so basically when someone connects to the websever under the mountpoint that was set, They will get there own personal thread that then grabs the data from Source() and sends it to them. Now say another person connects to the mount point and the last client as well as the source is still going. Wouldn't the new client be blocked from getting the Source data considering there are two active threads?
Your understanding of how Threads work in Python seems to be incorrect, based on the question you are asking. If used correctly, threads will not be blocking: you can instantiate multiple thread with Python. The limitation is that, due to the Global Interpreter Lock (GIL), you cannot get the full parallelism expected in thread programming (e.g. simultaneous execution and thus, reduced runtime).
What is going to happen in your case is that the two threads will take, together, the same amount of time that they would take if they were executed sequentially (although that is not necessarily what happens in practice).
Okay, I have copy and pasted some Python3 code that I have already written for a project that I am currently working on. With modification, you can make this code serve your purposes.
The code uses multiprocessing and multithreading. For my purposes, I am using multiprocessing so that sockets will run on one processor, and I can run a GUI program on another processor. You can remove the multiprocessor part if you prefer. The code below runs a socket message server. The server will listen for clients one at a time. Once a client has connected, a new thread will be initiated to handle all the communications between the server and each client. The server will then continue to search for for clients. At the moment however, the server only listens to data being sent from each client, and then it prints it to the terminal. With a small amount of effort, you can modify my code to send information from the server to each client individually.
import multiprocessing
import threading
from threading import Thread
class ThreadedServer(object):
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket(AF_INET, SOCK_STREAM)
self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(3) #Allow 3 Clients to connect to this server
while True:
#The program will search for one client at a time
print("Searching for Client")
client, address = self.sock.accept()
print(address, " is connected")
#client.settimeout(60)
#Once a client has been found, start a individual client thread
d = threading.Thread(target = self.listenToClient, args=(client, address))
d.daemon = True
d.start()
def listenToClient(self, client, address):
size = 1024
while True:
try:
data = client.recv(size)
if not data:
break
if data:
print(data)
#client.send(response)
else:
raise error('Client disconnected')
except:
client.close()
return False
def dataSharingHost():
#Using Sockets to send information between Processes
#This is the server Function
#ThreadServer(Host_IP, Port_Number), for LocalHost use ''
ThreadedServer('', 8000).listen()
def Main():
commServer = multiprocessing.Process(target=dataSharingHost, args=())
commServer.daemon = True
commServer.start()
if __name__== '__main__':
Main()
And to be fair, my code is modified from https://www.youtube.com/watch?v=qELZAi4yra8 . The client code is covered in those videos. I think the 3rd video covers the multiple client connects.

How do i control what socket thread I want to connect to in a asychronous reverse server python?

Good evening, This is my 1st time on this site, I have been programming a python based user monitoring system for my work for the past 3 months and I am almost done with my 1st release. However I have run into a problem controlling what computer I want to connect to.
If i run the two sample code I put in this post I can receive the client and send commands to client with the server, but only one client at a time, and the server is dictating which client I can send to and which one is next. I am certain the problem is "server side but I am not sure how to fix the problem and a Google search does not turn up anyone having tried this.
I have attached both client and server base networking code in this post.
client:
import asyncore
import socket
import sys
do_restart = False
class client(asyncore.dispatcher):
def __init__(self, host, port=8000):
serv = open("srv.conf","r")
host = serv.read()
serv.close()
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
def writable(self):
return 0
def handle_connect(self):
pass
def handle_read(self):
data = self.recv(4096)
#Rest of code goes here
serv = open("srv.conf","r")
host = serv.read()
serv.close()
request = client(host)
asyncore.loop()
server:
import asyncore
import socket
import sys
class soc(asyncore.dispatcher):
def __init__(self, port=8000):
asyncore.dispatcher.__init__(self)
self.port = port
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(5)
def handle_accept(self):
channel, addr = self.accept()
while 1:
j = raw_input(addr)
#Rest of my code is here
server = soc(8000)
asyncore.loop()
Here is a fast and dirty idea that I threw together.
The use of raw_input has been replaced with another dispatcher that is asyncore compatable, referencing this other question here
And I am expanding on the answer given by #user1320237 to defer each new connection to a new dispatcher.
You wanted to have a single command line interface that can send control commands to any of the connected clients. That means you need a way to switch between them. What I have done is created a dict to keep track of the connected clients. Then we also create a set of available commands that map to callbacks for your command line.
This example has the following:
list: list current clients
set <client>: set current client
send <msg>: send a msg to the current client
server.py
import asyncore
import socket
import sys
from weakref import WeakValueDictionary
class Soc(asyncore.dispatcher):
CMDS = {
'list': 'cmd_list',
'set': 'cmd_set_addr',
'send': 'cmd_send',
}
def __init__(self, port=8000):
asyncore.dispatcher.__init__(self)
self._conns = WeakValueDictionary()
self._current = tuple()
self.port = port
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', port))
self.listen(5)
self.cmdline = Cmdline(self.handle_input, sys.stdin)
self.cmdline.prompt()
def writable(self):
return False
def handle_input(self, i):
tokens = i.strip().split(None, 1)
cmd = tokens[0]
arg = ""
if len(tokens) > 1:
arg = tokens[1]
cbk = self.CMDS.get(cmd)
if cbk:
getattr(self, cbk)(arg)
self.cmdline.prompt(self._addr_to_key(self._current))
def handle_accept(self):
channel, addr = self.accept()
c = Conn(channel)
self._conns[self._addr_to_key(addr)] = c
def _addr_to_key(self, addr):
return ':'.join(str(i) for i in addr)
def cmd_list(self, *args):
avail = '\n'.join(self._conns.iterkeys())
print "\n%s\n" % avail
def cmd_set_addr(self, addr_str):
conn = self._conns.get(addr_str)
if conn:
self._current = conn.addr
def cmd_send(self, msg):
if self._current:
addr_str = self._addr_to_key(self._current)
conn = self._conns.get(addr_str)
if conn:
conn.buffer += msg
class Cmdline(asyncore.file_dispatcher):
def __init__(self, cbk, f):
asyncore.file_dispatcher.__init__(self, f)
self.cbk = cbk
def prompt(self, msg=''):
sys.stdout.write('%s > ' % msg)
sys.stdout.flush()
def handle_read(self):
self.cbk(self.recv(1024))
class Conn(asyncore.dispatcher):
def __init__(self, *args, **kwargs):
asyncore.dispatcher.__init__(self, *args, **kwargs)
self.buffer = ""
def writable(self):
return len(self.buffer) > 0
def handle_write(self):
self.send(self.buffer)
self.buffer = ''
def handle_read(self):
data = self.recv(4096)
print self.addr, '-', data
server = Soc(8000)
asyncore.loop()
Your main server is now never blocking on stdin, and always accepting new connections. The only work it does is the command handling which should either be a fast operation, or signals the connection objects to handle the message.
Usage:
# start the server
# start 2 clients
>
> list
127.0.0.1:51738
127.0.0.1:51736
> set 127.0.0.1:51736
127.0.0.1:51736 >
127.0.0.1:51736 > send foo
# client 127.0.0.1:51736 receives "foo"
To me
while 1:
j = raw_input(addr)
seems to be the problem:
you only accept a socket an then do something with it until end.
You should create e new dispatcher for every client connecting
class conn(asyncore.dispatcher):
...
def handle_read(self):
...
class soc(asyncore.dispatcher):
def handle_accept(self):
...
c = conn()
c.set_socket(channel)
Asyncore will call you back for every read operation possible.
Asyncore uses only one thread. This is its strength. every dispatcher that has a socket is called one after an other with those handle_* functions.

Categories

Resources