I just started with networking and am writing a very simple code for multicasting. I am still not sure about the different interfaces. Some examples used "0.0.0.0" while others have used "127.0.0.1".
Code for Server
import socket
import sys
import time
ANY = socket.gethostbyname('localhost')
S_PORT = 1501
M_ADDR = "224.168.2.9"
M_PORT = 1600
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT,1)
sock.bind((ANY,S_PORT))
sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,255)
while 1:
message = raw_input("Enter message: ")
sock.sendto(message,(M_ADDR,M_PORT))
if message == "exit":
break
sock.close()
Code for Client
import socket
import time
import sys
ANY = socket.gethostbyname('localhost')
M_ADDR = "224.168.2.9"
M_PORT = 1600
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT,1)
sock.bind((ANY,M_PORT))
sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,255)
status = sock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(M_ADDR) + socket.inet_aton(ANY))
while 1:
data,addr = sock.recvfrom(1024)
print "Received message from " + str(addr) + " : " + data
if data == "exit":
break
sock.close()
The Client code runs properly and is waiting to receive message on the socket. But the Code Server crashes as soon as I enter any message.
Traceback (most recent call last):
File "multicast_server.py", line 17, in <module>
sock.sendto(message,(M_ADDR,M_PORT))
socket.error: [Errno 49] Can't assign requested address
What is causing this issue ?
The above code works if I use ANY = "0.0.0.0". Why is that ? What changes ?
In IPv4, 0.0.0.0 is a special address, aka INADDR_ANY, that means "bind every possible address on every interface".
So, the multicast network at 224.168.2.9, if it's reachable at all, will certainly be reachable from a socket bound to 0.0.0.0.
Meanwhile, 127.0.0.1 is a special address, aka INADDR_LOOPBACK, that means "bind localhost only on the loopback device". There's no way to reach anything but the local host itself on that socket. In particular, you can't reach your multicast network. Whether you get an ENETUNREACH, ENETDOWN, or EADDRNOTAVAIL is platform-specific, but whether it works is not—it can't possibly work.
If you want to test multicasting without testing across multiple computers, you will need to set up a loopback network with more than one address, so you can bind the client, the server, and the multicast group all to different addresses within that network.
When you use "0.0.0.0" or "" for networking in python, it opens up to any IP inbound. For your case, I would use "0.0.0.0" or "127.0.0.1" (if you are not comfortable opening up to the world.)
get your device ip address
ubuntu: ifcongfig
choose the ip address from any ethernet ,loop, wlan
replace M_ADDR with that ip address
Related
I am trying to implement a simple chat program that uses sockets to transmit data via a UDP connection. However, I can't figure out how to correctly set it up so that people from outside my local network can access it if I am hosting it on my laptop. I am utilizing port 5000, and have port-forwarded that port on my router for my laptop. The port-forwarding doesn't seem to be the issue; at least the "Port Forward Network Utilities" from portforward.com seems to detect it as properly forwarded. Maybe I am mixing up the IP addresses I need to host from and connect with? The code in question is below:
import socket
import threading
import sys
class Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connections = []
def __init__(self):
self.sock.bind(('192.168.1.5', 5000))
self.sock.listen(1)
def handler(self, c, a):
while True:
data = c.recv(1024)
for connection in self.connections:
print(data.decode())
connection.send(data)
if not data:
break
def run(self):
while True:
c, a = self.sock.accept()
cThread = threading.Thread(target=self.handler, args=(c, a))
cThread.daemon = True
cThread.start()
self.connections.append(c)
print(self.connections)
class Client:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
usr_name = ""
def sendMsg(self):
while True:
self.sock.send(bytes(self.usr_name + ": " + input("-> "), 'utf-8'))
def __init__(self, address):
self.sock.connect((address, 5000))
self.usr_name = input("Enter a username: ")
iThread = threading.Thread(target=self.sendMsg)
iThread.daemon = True
iThread.start()
while True:
data = self.sock.recv(1024)
if not data:
break
print(data.decode())
if len(sys.argv) > 1:
client = Client(sys.argv[1])
else:
server = Server()
server.run()
As you can see, I have my current local IP address inputted for hosting the server, while the client asks for an IP to connect to. I'm not sure what to do now for hosting this over the internet, but I have tried every IP combination I can think of and it returns a number of errors.
Thanks in advance.
Edit:
The two main errors I was getting are:
Timeout Error [WinError 10060]
My friend received this when trying to connect from another network
[WinError 10061]
I would receive this when trying to connect using my public IP from the same computer
I'm sorry that I can't be more detailed in my errors and provide a full printout, and I will try to update this if I'm able to replicate them.
Edit:
I was able to rewrite it and get it to work, I don't need anymore help with this.
Thanks.
You're port-forwarding UDP port 5000 to 5000.
But you're opening TCP streams, not UDP. That's what SOCK_STREAM means. If you want UDP, you need to use SOCK_DGRAM.
So, you need to make these two consistent. The only problem is, I'm not sure which one you actually want here.
On the one hand, your code is doing connection-oriented recv, and seems to be assuming reliable transmission, which means you probably want TCP.
On the other hand, your code seems to be assuming that each recv(1024) is going to get exactly one send from the other side, which is only true for UDP; TCP sockets are byte streams, not message streams. When you do a recv(1024), you could easily get just the first 12 bytes of an 80-byte line, which means it could end in the middle of a UTF-8 character, which means decode will throw an exception.
I think you want TCP, but with a framing protocol on top of it. The simplest protocol that would probably make sense here is lines of text. Which is pretty easy to do on your own, but even easier to do with socket.makefile, given that you're dedicating a thread to each connection.
So i'm trying to write a TCP server and client so that when the client connects, a file is sent back from the server. Here's my code for the server:
import socket
import threading
bind_ip = '0.0.0.0'
bind_port = 9999
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(10)
file_to_send = ('file_to_send.txt')
print '[*] Listening on %s:%d' % (bind_ip,bind_port)
def handle_client(client_socket):
request = client_socket.recv(1024)
print '[*] Received %s' % request
client_socket.send('')
client_socket.close(file_to_send)
while True:
client,addr = server.accept()
print '[*] Accepted connection from: %s:%d' % (addr[0],addr[1])
client_handler = threading.Thread(target=handle_client,args=(client,))
client_handler.start()
And here is my code for the client:
import socket
target_host = '0.0.0.0'
target_port = 9999
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target_host,target_port))
client.send('ACK!')
response = client.recv(4096)
print response
When the server and client are run, the server returns the error 'Only one usage of each socket address (protocol/network address/port) is normally permitted' and when the client is run I get the error ' The requested address is not valid in its context'
Does anyone know why these errors are occurring or how I might be able to fix it.
I think this is a case of inaccurate example code. The server code you posted does not cause the issue you're describing (the client code does, but we'll get to that).
Server
The issue with the server code is that you're binding to the same (address, port) twice. Whether this is from wrong indentation or wrong logic it's tough to say, but that error message comes from binding the same protocol to the same address with the same port number more than once at the same time.
The rest of the code seems fine, though you can't do client_socket.close("some string") as you're doing here. socket.close does not accept any arguments.
Client
There's a simple solution here -- just change the target_host to something reasonable. You cannot connect to 0.0.0.0. This should be the addressable IP of the server in the smallest scope possible. Presumably if this is a toy program this is something like localhost.
(N.B. you bind the server to '0.0.0.0' to tell it to accept connections going to any destination IP. You could bind the server instead to '127.0.0.1' to inform the server that it will ONLY be known as localhost and never anything else.)
I've had a similar issue before and it was that I was running old versions of the program on the same port, restarting the PC or closing the processes in task manager should fix it.
I'm aware that this was asked over a year ago, so OP has probably restarted their PC since then, but hopefully this will help someone looking for a solution for a similar problem.
I recently have some difficulties to connect a socket to another computer's socket through Internet, an image is worth a thousand words:
Computer A is running this "listener.py" script:
import socket
PORT = 50007
BUFFER = 2048
HOST = ''
if __name__ == '__main__':
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(BUFFER)
if not data: break
conn.sendall(data)
Computer B is running this "sender.py" script:
import socket
HOST = '101.81.83.169' # The remote host
PORT = 50007 # The same port as used by the server
if __name__ == '__main__':
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
So first of all, I run the "listener" script of the computer A. Then, I run the "sender" script of the computer B. However, when I execute the "sender" script, I received a error message which explains me that I am not authorized to connect to this remote address.
So I would like to know how can I connect a socket to another socket through internet without changing the router configurations.
Thank you very much for your help.
Edit: Here the error message (I didn't execute the same script for some reasons, but it's the same error message)
sock.connect(('101.81.83.169',50007)) Traceback (most recent call last): File "<stdin>", line 1, in
<module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 224, in
meth return getattr(self._sock,name)(*args) socket.error: [Errno 61] Connection refused
So I would like to know how can I connect a socket to another socket through internet without changing the router configurations.
You can't. The public IP address belongs to your router. Your server isn't listening in the router, it is listening in some host behind the router. You have to open that port in your router and forward it to the host your listener is running in: whatever that means in your particular router. Otherwise the router will refuse the connection, as it doesn't have anything listening at that port.
Computer B can't directly connect to computer A since it has an IP address which is not reachable from the outside. You need to set up a port forwarding rule in the 101.81.83.169 router that redirects incoming connection requests for port 50007 to IP address 192.168.0.4.
However, since you say that you are seeking a solution without changing router configurations, you need something different.
In this case, you could setup an intermediate server running on the public Internet that both computers can then connect to and serves as an intermediate tunneling platform between them. Solutions for this already exist, for example have a look at ngrok, which has Python bindings available.
From the book "Computer Networking: A Top-Down Approach", there is a part which is very interesting on page 149 about how Bittorents work:
Each torrent has an infrastructure node called a tracker. When a peer joins a torrent, it registers itself with the tracker and periodically informs the tracker that it is still in the torrent. In this manner, the tracker keeps track of the peers that are participating in the torrent. A given torrent may have fewer than ten or more than a thousand peers participating at any instant of time. Alice, joins the torrent, the tracker randomly selects a subset of peers (for concreteness, say 50) from the set of participating peers, and sends the IP addresses of these 50 peers to Alice. Possessing this list of peers, Alice attempts to establish concurrent TCP connections with all the peers on this list. Let’s call all the peers with which Alice succeeds in establishing a TCP connection “neighboring peers.
So:
- Step 1: Alice connects to the tracker, the tracker gives to Alice the ip addresses of Bob and Mick.
- Step 2:Alice receives the ip addresses of Bob and Mick, then she can try to establish TCP/IP connections for downloading the file.
I don't remember having to set up any router configuration when I wanted to download files from Bittorent.
So what am I missing?
I start to build a simple client - server chat room today and I am new to Python and network connection. I made a simple code on server something like this:
HOST = socket.gethostname()
PORT = 21238
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
On the client:
HOST = socket.gethostbyaddr('54.201.33.XX') #54.201.33.XX is my EC2 public IP
PORT = 21237
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
I have already running my server code on server and when I am trying to run client code on my PC. I got the error:
Traceback (most recent call last):
s.connect((HOST, PORT))
TypeError: Can't convert 'tuple' object to str implicitly
I have found some sample codes but nealy all of them are using local host. Thank you for your helps.
/////
Based on #Jon S.'s answer. My client code should be
HOST = '54.201.33.XX'
But still time out to connect to server. I am sure my ip is correct.
The problem is
HOST = socket.gethostbyaddr('54.201.33.XX')
in your second example. gethostbyaddr returns a tuple, containing (hostname, a list of aliases, ip addresses). connect expects a string as the first element of the tuple that specifies the address and port to connect to.
You can change this to
HOST = '54.201.33.XX'
and it should work.
I found the answer.
On server, the HOST = socket.gethostname(); On client, the HOST = '54.201.33.XX', which is your server ip address
In EC2, the default security setting is only open ssh. You should open the Port you have used in your codes. The operations are following:
2.1 Enter AWS console and enter EC2
2.2 Find Security Group on the left under NETWORK & SECURITY
2.3 Click your current security group (For me, it is not the default one) and open Inbound on the below information
2.4 Choose Custom TCP rule and enter your Port range (21237 in my pasted code) and click on add Rules
2.5 DO NOT forget to press button "Apply Rule Changes"!!!
I'm new to Sockets, please excuse my complete lack of understanding.
I have a server script(server.py):
#!/usr/bin/python
import socket #import the socket module
s = socket.socket() #Create a socket object
host = socket.gethostname() #Get the local machine name
port = 12397 # Reserve a port for your service
s.bind((host,port)) #Bind to the port
s.listen(5) #Wait for the client connection
while True:
c,addr = s.accept() #Establish a connection with the client
print "Got connection from", addr
c.send("Thank you for connecting!")
c.close()
and client script (client.py):
#!/usr/bin/python
import socket #import socket module
s = socket.socket() #create a socket object
host = '192.168.1.94' #Host i.p
port = 12397 #Reserve a port for your service
s.connect((host,port))
print s.recv(1024)
s.close
I go to my desktop terminal and start the script by typing:
python server.py
after which, I go to my laptop terminal and start the client script:
python client.py
but I get the following error:
File "client.py", line 9, in
s.connect((host,port))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused
I've tried using different port numbers to no avail. However, I was able to get the host name using the same ip and the gethostname() method in the client script and I can ping the desktop (server).
Instead of
host = socket.gethostname() #Get the local machine name
port = 12397 # Reserve a port for your service
s.bind((host,port)) #Bind to the port
you should try
port = 12397 # Reserve a port for your service
s.bind(('', port)) #Bind to the port
so that the listening socket isn't too restricted. Maybe otherwise the listening only occurs on one interface which, in turn, isn't related with the local network.
One example could be that it only listens to 127.0.0.1, which makes connecting from a different host impossible.
This error means that for whatever reason the client cannot connect to the port on the computer running server script. This can be caused by few things, like lack of routing to the destination, but since you can ping the server, it should not be the case. The other reason might be that you have a firewall somewhere between your client and the server - it could be on server itself or on the client. Given your network addressing, I assume both server and client are on the same LAN, so there shouldn't be any router/firewall involved that could block the traffic. In this case, I'd try the following:
check if you really have that port listening on the server (this should tell you if your code does what you think it should): based on your OS, but on linux you could do something like netstat -ntulp
check from the server, if you're accepting the connections to the server: again based on your OS, but telnet LISTENING_IP LISTENING_PORT should do the job
check if you can access the port of the server from the client, but not using the code: just us the telnet (or appropriate command for your OS) from the client
and then let us know the findings.
Assume s = socket.socket()
The server can be bound by following methods:
Method 1:
host = socket.gethostname()
s.bind((host, port))
Method 2:
host = socket.gethostbyname("localhost") #Note the extra letters "by"
s.bind((host, port))
Method 3:
host = socket.gethostbyname("192.168.1.48")
s.bind((host, port))
If you do not exactly use same method on the client side, you will get the error: socket.error errno 111 connection refused.
So, you have to use on the client side exactly same method to get the host, as you do on the server. For example, in case of client, you will correspondingly use following methods:
Method 1:
host = socket.gethostname()
s.connect((host, port))
Method 2:
host = socket.gethostbyname("localhost") # Get local machine name
s.connect((host, port))
Method 3:
host = socket.gethostbyname("192.168.1.48") # Get local machine name
s.connect((host, port))
Hope that resolves the problem.
host = socket.gethostname() # Get the local machine name
port = 12397 # Reserve a port for your service
s.bind((host,port)) # Bind to the port
I think this error may related to the DNS resolution.
This sentence host = socket.gethostname() get the host name, but if the operating system can not resolve the host name to local address, you would get the error.
Linux operating system can modify the /etc/hosts file, add one line in it. It looks like below( 'hostname' is which socket.gethostname() got).
127.0.0.1 hostname
in your server.py file make : host ='192.168.1.94' instead of host = socket.gethostname()
Pay attention to change the port number. Sometimes, you need just to change the port number. I experienced that when i made changes over changes over syntax and functions.
I was being able to ping my connection but was STILL getting the 'connection refused' error. Turns out I was pinging myself! That's what the problem was.
I was getting the same problem in my code, and after thow days of search i finally found the solution, and the problem is the function socket.gethostbyname(socket.gethostname) doesnt work in linux so instead of that you have to use socket.gethostbyname('put the hostname manually') not socket.gethostbyname('localhost'), use socket.gethostbyname('host') looking with ifconfig.
try this command in terminal:
sudo ufw enable
ufw allow 12397