Sockets: How would Peer to Peer chat work? - python

I am trying to make a P2P chat without manually adding users IP Address.
These scripts would send and receive UTF-8 message with UDP packets by manually specifying IP address.
# Send
# Let's say this code is executed from PC1.
import socket
PC2_IP = '192.160.4.169' # IP address is not valid, it is just for example.
UDP_PORT = 5005
MESSAGE = "Hey there!"
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
Now as example let's execute Receiver script from PC2.
# Receive
# Let's say this code is executed from PC2.
import socket
ip = socket.gethostbyname(socket.gethostname())
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind((ip, 5005))
while True:
data, addr = udp.recvfrom(1024)
print data
This would work without any problems, The message would be received instantly after script executed.
But in theory how would i make a P2P chat without manually specifying IP addresses?
How would i make application get both users hostnames? Do i need to specify IP Addresses with socket.gethostbyname(socket.gethostname()) in both sender and reciever scripts?
If i need some extra necessary modules which one of them would it be? Can i use P2P module for sockets?

In the 1:1 case the first program doesn't need to know the address of anyone else. It just starts and waits. The second program needs to know the address of the first. As soon as it sends a "hello" the first program now knows the address of the second via recvfrom.
If you want no known addresses, well it stops being a Python question. Now you need to learn about autoconfiguration and network discovery protocols. Multicast? DNS Service Discovery? Bonjour?
That gets complicated real fast. There's a good reason why so many chat and chat-like Internet systems have a single server that everyone knows the address of.
Hope this helps.

maybe help this link P2P Berry Tella=BT
For this exist and python source(if need!)
Hope help you!

Related

Creating a server on python

I’m trying to create a server on my raspberry pi using python and then i want to test the server by accessing it from another device using the IP address of the raspberry pi, but the problem is that everytime i type the IP address of my raspberry pi into my webpage, it doesn’t open and i don’t know if there’s a problem in my code or not, i will write below so that anyone could check
import socket
import sys
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
try:
my_socket.bind((host, 1234))
except socket.error:
print(‘failed’)
sys.exit()
my_socket.listen(5)
While True:
conn, addr = my_socket.accept()
data = conn.recv(1000)
if data:
print(‘got a request’)
my_socket.send(‘Thank you’)
my_socket.close()
conn.close()
after that i tried typing the raspberry pi’s IP address on my laptop’s webpage but it was no use, first i typed ifconfig in the terminal of the raspberry pi to get the IP address and i tried it but it didn’t work, then i added another line in the code which is gethostbyname to the variable host and printed it and it showed different IP address than the one in ifconfig which was confusing to me, but i even tried this another IP address on my webpage and it didn’t work too
Did you check with netstat to see if the code is actually listening? Should list the <IP>:<Port> as LISTENING, i always check that when i do server code.
Sometimes when you try out code and don't terminate it properly, there can be a orphan process still listening to the Interface:Port hogging the port. Been there, done that, got the T-shirt.
Also, try using 0.0.0.0 instead, it tells the socket listener to listen on all interfaces, including loopback.
Got any firewall denying the connection ? Check that.
Also, check try using curl as a debug tool and see if 1) Curl can connect and 2) you get send some HTTP data to the server:
Curl 127.0.0.1:1234/HelloWorld

How can I get the 'correct' IP-Address via Python

For some TCP playing around I need 2 IP-addresses, the public and private one. Public was easy enough with some request to an external service, but if i do
socket.gethostbyname(socket.gethostname())
i get 127.0.0.1/8, which is not correct. If i enter ip a I get 2 blocks of data, the first one being the 127..., labled as lo: <LOOPBACK,UP,LOWER_UP>, but I need the second one, the 192.168... which is ens3: <BROADCAST,MULTICAST,UP,LOWER_UP>.
I don't know very much about networking and the stuff surrounding it so I'm sorry if there is a straightforward, obvious solution, but is there a way that every machine I run my code on I get the IP address I need for my code to run?
Furthermore, what should I put into the host's s.bind()? The program runs over the internet so should i put the public or private ip address in there? some tutorials put an empty string in there which really confuses me now, and most use a local network so i have no idea what to do when doing it over the internet.
You can create a connection and grab the address associated with the active connection.
import socket
def get_internal_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
s.close()
return ip
def get_external_ip():
return socket.gethostbyname(socket.gethostname())
print('Internal:', get_internal_ip())
print('External:', get_external_ip())

(Python/TFTP-Server) how to listen to an non (yet) existing IP-address (RNDIS)?

Hy folks,
my problem: I want to start a (tftp) server for an non-existing IP-address.
the server is meant for USB/RNDIS where its IP-address by nature only is existing when there is actual network-traffic going on -- but I want to start the server 'early' (e.g. when Windows starts).
idea was to bind() the socket to 0.0.0.0 - and then to check each request for "valid" addresses.
problem with that approach: recfrom() only returns the source-address (client), but not the destination (server)!
how do I get the IP-address this client has talked to?
(I could of course check for the same subnet at least, but I need the real server-address this client was talking to!)
or, are there by chance any options to let bind() use a non-existing IP-address?
cheers.
p.s.
this is for the Python tftpy server...
-- at the moment I need to ping from client side when starting the server, which is quite meh...
There's no way to get the local address directly but there's a trick that will usually work for you.
Let's say that you just obtained a buffer and client address from recvfrom. Now you create a new auxiliary UDP socket, connect it to the client's address, and then use getsockname to obtain the local address on this new socket. (With UDP, connect doesn't actually send anything to the peer, it just does address resolution.)
So in this way, you can discover the IP address that the server system would use as source were it to send a datagram back to the client system. That's usually the same address that the client used to target the server.
>>> cbytes, caddr = server_sock.recvfrom(2048)
>>> print(caddr) # Client IP and port
('192.168.0.11', 38869)
>>> aux_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> aux_socket.connect((caddr[0], 9999)) # Connect back to client (port doesn't matter)
>>> saddr = aux_socket.getsockname() # Get local IP and port (ignore port here too)
>>> print(saddr)
('192.168.0.12', 39753)
This works on linux. I'm not 100% sure it would work the same way on Windows but it seems reasonable to expect that it would.

Finding source IP-address when binding to 0.0.0.0

When binding a UDP socket to ("", 1234) or ("0.0.0.0", 1234), is it possible to find out what IP-address it will actually send from?
As you can see in the code below, getsockname only tells me what I bound to. But when I send a packet, I can see that the IP-address is, in my case, 10.0.0.2.
Do I have to infer this address myself by looking at my network interfaces? If so, that is fine, but is there a robust way of doing so?
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("", 1234))
print(s.getsockname()) # prints ("0.0.0.0", 1234)
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2
I've tried doing
import socket
print(socket.gethostbyname(socket.gethostname()))
but that doesn't seem to be very reliable (in the case where I expected 10.0.0.2, I got 127.0.1.1).
I realize that by binding to 0.0.0.0, I bind to all local network interfaces. Does that mean that my source IP-address will be determined by the routing tables when I try to send something? If so, can I still get that address in a robust way from Python?
The IP address used when sending will be determined by the routing table as the packet is sent.
There might be platform specific ways of querying that routing table, but a fairly portable way is to
connect() the socket first.
You can use another socket just for querying this information too. e.g.
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.bind(("", 1234))
print(s.getsockname()) # prints ("0.0.0.0", 1234)
sq = socket(AF_INET, SOCK_DGRAM)
sq.connect(("10.0.0.3", 1234))
print(sq.getsockname()[0])
sq.close()
s.sendto("hello", ("10.0.0.3", 1234)) # sends from 10.0.0.2
This is more a usually-you-do-not-need-it answer. It may not correspond to your usecase.
Have alook at socket.gethostbyname_ex(socket.gethostname()). It shows all possible IP-addresses and the host name. You can receive from all of those since you did not bind to any specific one of those. They will be your source ip addresses.
It is not necessairy for you to know the exact address you send from. The receiver may see another one if it goes behind a NAT, into the internet or through a VPN.
The receiver will then know where the packet came from and can send answers.
#Joachim_Pileborg is also right. It is not usually done.
If you need a specific interface, bind to it. If not, you probaply do not need it.

Simple Python UDP Server: trouble receiving packets from clients other than localhost

So, the very simple code that I'm trying to use is here: http://wiki.python.org/moin/UdpCommunication
(also here):
Sending:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
MESSAGE = "Hello, World!"
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
print "message:", MESSAGE
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
Receiving:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print "received message:", data
The code works fine when I run both applications on my computer. I put the sending code on my laptop with:
UDP_IP="IP address for my computer"
Everything else is the same. Yet, nothing happens. What am I doing incorrectly? I used wireshark and determined that the packet is being sent and received; however, the python program isn't receiving the packet. I'm very confused.
Any help is much appreciated.
Thanks in advance.
Try binding to all local interfaces on the receiving side:
sock.bind(("", UDP_PORT)) # could also use "0.0.0.0"
Note that the behavior of operating systems is not entirely logical (nor consistent) in terms of binding when receiving UDP packets, especially for multicast traffic. This is the behavior you get:
Linux: Binding to a specific IP will filter the incoming UDP packets and only the ones targeted at this specific IP will get through the filter. This means for example that multicast UDP packets received by an interface with IP 192.168.1.100 will not be received when binding to IP 192.168.1.100. On Linux the normal bind does not bind to an interface. Use setsockopt(SO_BINDTODEVICE) for this. Binding to 0.0.0.0 (or "" on Python) will always receive all UDP packets received by the machine on all interfaces, regardless of the destination IP, so this is usually the most useful option on Linux.
Windows: Binding to a specific IP will bind to the interface belonging to this IP, pretty much like setsockopt(SO_BINDTODEVICE) does on Linux. Incoming UDP packets are not filtered by this IP, so multicast traffic can be received even when binding to a concrete IP. (This is probably the first time the Windows behavior seems more consistent to me than the Linux behavior.)
Python does not abstract these OS specific differences away for sockets (as it does in other areas). As long as you have no explicit reason not to do so I suggest to always bind to 0.0.0.0.
eventually figured out my issue and it was pretty complex and highly localized,
I had a very similar problem happen to me. I realize that you have already solved this problem, however I thought it would be good to share how I solved the issue for me.
The issue I found was with my firewall settings. I found that the packets were being blocked by Windows Firewall.
I too had used Wireshark which showed that packets were being sent and received. It is important to note that Wireshark grabs packets at a much lower level than a Python application.
By running my code locally with a listener on one port and a client on another port on the same PC, the firewall wasn't blocking the packets. When I moved to interfacing with an external machine, the firewall rules came into play blocking the incoming packets.
Changing the firewall policy fixed this issue. There are numerous ways and inherent security risks to changing the firewall to make this work so I will leave that part up to the IT professionals. :-)
Make sure that the server port is open while trying to execute recvfrom call. If the destination port from which the socket reading was down then we get this error.
I got the same error and fixed by reading this link - http://www.linuxsa.org.au/mailing-list/2001-04/668.html
So if I want to send a message AND receive a response then how would the code look? Like this?
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
MESSAGE = "Hello, World!"
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print "received message:", data

Categories