I have this little piece of code that returns a 10048 after printing the response
I have tried adding socket.SO_REUSEADDR and it did help for the first time. After running the program for the first time it prints 0. Which from my knowledge means the port is open, but after that it returns 10048. I have also tried changing the port.
This is my code:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = '127.0.0.1'
port = 1024
s.bind((host,port))
result = s.connect_ex((host,port))
print(result)
s.close()
I am not sure why it is returning this. I have looked everywhere but cant find an answer. I am trying to get it to return either 0 or 1. That why I can tell if the port is open or closed.
This cannot work when host is the local machine: you try to use the same port on same machine as both source and destination.
You must either use two different ports, or different machines on do not fix the source port and let the system choose one (do not bind before connect).
Related
I'm having a strange problem with python udp sockets. When I send data over them, they open an udp port on 0.0.0.0 and I cannot find out why they do, what they do listen to and how to deactivate that behaviour. Our system administrators don't like ports to be listened on 0.0.0.0 (reasonably).
Minimum example:
import socket
fam = socket.AF_INET
family, _, _, _, addr = socket.getaddrinfo('localhost', 9999, fam, socket.SOCK_DGRAM)[0]
sock = socket.socket(family, socket.SOCK_DGRAM)
sock.sendto('foobar'.encode('ascii'), addr)
Right after the last method call, the python program listens to:
udp 0 0 0.0.0.0:41972 0.0.0.0:* 1000 308716 17777/python3
And this seems to stay until the python executable stops. So my question is, does anyone here have the same problem and how can I avoid it?
Thank you very much!
Which port do you expect your packets to come from?
Sockets have ports at both ends. Packets come from a port and go to a port. You didn't pick a port (with bind), so the operating system chose one for you.
It's not a problem, it's how sockets work.
0.0.0.0 means "any IP address" by the way.
just to elaborate on my comment, here's how I'd put the socket calls together:
import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind(('127.0.0.1', 0)) # optional
sock.connect(('localhost', 9999))
sock.send(b'foobar')
notes:
connecting a UDP socket should cause it to be bound to something more appropriate than 0.0.0.0, and hence why I put an optional comment
getaddrinfo doesn't help you much, hence I'm just passing names and letting Python resolve them internally
using a name for the connect call and dotted-quad notation for bind looks a little strange. I'd suggest using just one format for consistency, or just using connect and not using bind
getaddrinfo is really useful when you want to be able to transparently handle IPv6 along with IPv4 addresses, especially for hosts that resolve to multiple addresses. see the Happy Eyeballs algorithm for an example
So, I've found a workaround, even if I think it's not the cleanest way to do that, I couldn't find another one.
I used the method bind(addr: tuple) on the udp socket to make it listen to only a specific IP. In my case this looks like:
import socket
fam = socket.AF_INET
family, _, _, _, addr = socket.getaddrinfo('localhost', 9999, fam, socket.SOCK_DGRAM)[0]
sock = socket.socket(family, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 0)) # This is the new line where I bind only to 127.0.0.1
sock.sendto('foobar'.encode('ascii'), addr)
Thanks to #user253751 for leading me in the right direction.
So far I have made a VERY basic client/server application that creates a TCP connection. I have a lot of programming experience, just never did this low-level stuff and especially nothing with networks. Note that all the prints are just to help me figuring out what is going on. One of the known issues is that jsonip sometimes gives me an IPv4 and sometimes v6, I don't know why but that doesn't matter for now, just to warn anyone who wants to recreate my code.
Server:
import socket
import requests
port = int(input("Enter port you want to open:\n"))
#todo: add errorhandling
print("Adding socket...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
hostname = socket.gethostname()
print(f"Hostname: {hostname}")
ip_address = socket.gethostbyname(hostname)
print(f"Host address: {ip_address}")
r = requests.get(r'http://jsonip.com')
public_ip_address = r.json()['ip']
s.bind((ip_address, port))
print("Is open for connections on IP: "+public_ip_address+" and Port: "+str(port))
s.listen(5)
print("Done initialisation, listening for incoming connections...")
while True:
clientsocket, address = s.accept()
print(f"Connection from {address} has been established")
clientsocket.send(bytes(f"You have connected to server: {hostname}", "utf-8"))
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = input("Enter IP to connect to:\n")
port = int(input("Enter Port to connect to:\n"))
print(f"Connecting to server {ip} ...")
s.connect((ip, port))
msg = s.recv(1024)
print(msg.decode("utf-8"))
On my local machine: Open 20000 in my server.py, it tells me the host is 127.0.1.1, I then enter 127.0.1.1 into my client script and 20000, and they connect. So the Socket has been bound with the 127.0.1.1. (Side question: What is this IP address, is it like the internal IP address of processes in my PC or something? If running ip a on my other machine it is the first one shown of 2)
Using Virtmanager on my machine and running one Linux Server (command line only) and one normal Ubuntu, the server tells me the host is, again, 127.0.1.1 which I don't need to enter into the other VM to know it won't work, what does work however, is getting the IP-address of the Server via ip a, which in this case is 192.168.122.37, and when I enter this IP address into the client, it connects. But in the socket here I bind, again, the 127.0.1.1, so is it arbitrary what I put here? What SHOULD I bind here, the public, the weird or the 192. address?
The first thing I could not get to work was using 2 physical devices. When opening a server on my Linux machine, I cannot connect with my windows machine at all, no matter if I use my public, my 127. or my 192. IP-address. Now my end goal is doing this over the internet so I am walking myself up, describing here the steps I took to try and get where I want to be but here I hit a brick wall where I don't know what is wrong. Am I binding the wrong address on the server, is my router being a problem, is there something else wrong?
I also tried leaving my network using my friends pc a few countries over, but this also just results in a timeout (my theory is that the Router port he is trying to open is closed and I have now idea how I can make the router send data to his PC, which should be not impossible as firefox and every application using internet does it without me having to manually forward every port, I just don't know how). This is my end goal, creating a connection between my friends PC and mine, and this is how far I got (I wouldn't mind skipping the local network if it is not relevant for fixing the global connection problem), so, tl;dr: what did i do wrong, what do i need to bind and what do i need to do for the final result to work?
There are many questions to answer.
Addresses 127.X.X.X are reserved for the loopback interface, most common one is 127.0.0.1. The loopback is a virtual, but important interface and as you have probably guessed, it is usable on the local machine only. You cannot use 127.X.X.X address to make two hosts to communicate with each other.
Addresses 192.168.X.X (and also 10.X.X.X and 172.16-31.X.X.) are reserved for local LANs. They are not valid on the Internet.
You cannot use these addresses to make two hosts to communicate with each other over the public Internet (unless you create a tunnel, an advanced networking topic)
Almost everybody uses them, because we ran out of IPv4 addresses long time ago, they were difficult to get, expensive, etc. Also such hosts are isolated from the Internet, they can be reached only via a router that translates addresses. Such router feature is called NAT. A typical router has one valid Internet address and all connections to the Internet appear as coming from the router. If you contant a service like jsonip.com from a PC, you get your router's address, not your PC's address.
See also: Finding local IP addresses using Python's stdlib
To make your program working, make it to accept connections on all interfaces. See the first example in the socket docs. On Linux, use port numbers >= 1024. Ports < 1024 are reserved, not available to regular users.
Final point is that a firewall may prevent connections to your server. It depends on your system and setup.
I'm trying to run a python socket server on my local network, with this server code:
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((socket.gethostname(), 9876))
serversocket.listen(5)
while True:
c, addr = serversocket.accept()
while True:
data = c.recv(1024).decode()
print(data)
c.send(data.encode())
Then, using netcat on another network machine, I can connect to the server and send text in, and have it mirrored back. However, after about two or three tries, it suddenly drops back out to the command line and no longer accepts any connections. The server side, however acts the same, and appears like it didn't see the last incoming message.
If I try to connect to it with another socket, it does the same thing, but instead throws error 104, and then error 32.
I am completely stumped. I've tried adding threads, and everything else that I can think of. If anyone on has any ideas on why this is happening, or ways to work around it, I'd love to hear. Thanks! I'm using python 3.5.
Thanks!
An eye-tracking application I use utilizes UDP to send packets of data. I made a python socket on the same computer to listen and dump the data into a .txt file. I already have this much working.
A separate application also written in python (what the eye-tracked subject is seeing) is running on a separate computer. Because the eye-tracking application is continuous and sends unnecessary data, so far I've had to manually parse out the instances when the subject is looking at desired stimuli. I did this based on a manually synchronized start of both the stimuli and eye-tracking applications and then digging through the log file.
What I want to do is have the second computer act as a second UDP client, sending a packet of data to the socket on the eye-tracking computer everytime the subject is looking at stimuli (where a marker is inserted into the .txt file previously mentioned). Is it possible to have a socket listening to two IP addresses at one time?
Here's my socket script:
#GT Pocket client program
import datetime
import socket
now = datetime.datetime.now()
filename = 'C:\gazelog_' + now.strftime("%Y_%m_%d_%H_%M") + '.txt'
UDP_IP = '127.0.0.1' # The remote host (in this case our local computer)
UDP_PORT = 6666 # The same port as used by the GT server by default
sock = socket.socket(socket.AF_INET, #internet
socket.SOCK_DGRAM) #UDP
sock.bind( (UDP_IP, UDP_PORT) )
while True:
data, addr = sock.recvfrom( 1024) #I assume buffer size is 1024 bytes.
print "Received Message:", data
with open(filename, "a") as myfile:
myfile.write(str(data + "\n"))
sock.close()
myfile.close()
EDIT:
#abarnert I was able to bind to the host address on the Ethernet interface and send a message from computer B to computer A, but computer A was no long able to receive packets from itself. When I specified UDP_IP = '0.0.0.0' computer B was no longer able to send data across the Ethernet. When I specified UDP_IP = '' I received the `error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
This have to do with the script I used on the Computer B to send the data:
import socket
UDP_IP = "169.254.35.231" # this was the host address I was able to send through.
UDP_PORT = 6666
MESSAGE = "Start"
print ("UDP target IP:"), UDP_IP
print ("UDP target port:"), UDP_PORT
print ("message:"), MESSAGE
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT) )
I didn't know where (or if at all) I needed to specify INADDR_ANY, so I didn't. But I did try once where import socket.INADDR_ANY but got ImportError: No module named INADDR_ANY
Seems like a simple issue based on your response, so I'm not sure where I'm messing up.
EDIT2: I just reread your answer again and understand why socket.INADDR_ANY doesn't work. Please disregard that part of my previous edit
EDIT3: Okay so the reason that I wasn't picking up data when specifying the host IP was that the application I was collecting data from on Computer A was still specified to send to 127.0.0.1. So I figured it out. I am still curious why 0.0.0.0 didn't work though!
No. A socket can only be bound to a single address at a time.*
If there happens to be a single address that handles both things you want, you can use a single socket to listen to it. In this case, the INADDR_ANY host (0.0.0.0) may be exactly what you're looking for—that will handle any (IPv4) connections on all interfaces, both loopback and otherwise. And even if there is no pre-existing address that does what you want, you may be able to set one up via, e.g., an ipfilter-type interface.
But otherwise, you have to create two sockets. Which means you need to either multiplex with something like select, or create two threads.
In your case, you want to specify a host that can listen to both the local machine, and another machine on the same Ethernet network. You could get your host address on the Ethernet interface and bind that. (Your machine can talk to itself on any of its interfaces.) Usually, getting your address on "whatever interface is the default" works for this too—you'll see code that binds to socket.gethostname() in some places, like the Python Socket Programming HOWTO. But binding to INADDR_ANY is a lot simpler. Unless you want to make sure that machines on certain interfaces can't reach you (which is usually only a problem if you're, e.g., building a server intended to live on a firewall's DMZ), you'll usually want to use INADDR_ANY.
Finally, how do you bind to INADDR_ANY? The short answer is: just use UDP_IP = '', or UDP_IP = '0.0.0.0' if you want to be more explicit. Anyone who understands sockets, even if they don't know any Python, will understand what '0.0.0.0' means in server code.(You may wonder why Python doesn't have a constant for this in the socket module, especially when even lower-level languages like C do. The answer is that it does, but it's not really usable.**)
* Note that being bound to a single address doesn't mean you can only receive packets from a single address; it means you can receive packets from all networks where that single address is reachable. For example, if your machine has a LAN connection, where your address is 10.0.0.100, and a WAN connection, where your address is 8.9.10.11, if you bind 10.0.0.100, you can receive packets from other LAN clients like 10.0.0.201 and 10.0.0.202. But you can't receive packets from WAN clients like 9.10.11.12 as 10.0.0.100.
** In the low-level sockets API, dotted-string addresses like '0.0.0.0' are converted to 32-bit integers like 0. Python sometimes represents those integers as ints, and sometimes as 4-byte buffers like b'\0\0\0\0'. Depending on your platform and version, the socket.INADDR_ANY constant can be either 0 or b'\0\0\0\0'. The bind method will not take 0, and may not take b'\0\0\0\0'. And you can't convert to '0.0.0.0' without first checking which form you have, then calling the right functions on it. This is ugly. That's why it's easier to just use '0.0.0.0'.
I believe you can bind a raw socket to an entire interface, but you appear to be using two different interfaces.
It's probably best to use two sockets with select().
I am trying to make a simple server/client program pair.
On LAN they work fine, but when i try to connect from the "outside" it says connection refused. I shut down firewalls on both machines but i am still unable to connect, and i double checked the ip.
What am i doing wrong?
Thanks
Jake
Code:
import socket
host = ''
port = 9888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(1)
conn, adrr = s.accept()
conn.send("Hello, world!")
s.close()
Client:
import socket
host = '68.x.x.x'
port = 9888
s = socket.socket(socket.AF_INET, socket_SOCK_STREAM)
s.connect((host,port))
print s.recv(200)
s.close()
You have one of two possible issues.
Erroneous network configuration
Bug(s) in code
The way to debug this is to try and rule one out. If we can get rid of the Code issue then we know it is a network issue.
Get a Socket Server and client that you know works and then try them as standalone programs. inside and outside of the firewall.
Go to this site and download the examples. Change the ports in both the client and the server, compile and run them. First on same machine within network, second from two machines on same network and then server from within and client from outside of network.
How's the argument you're passing to the .bind call for your server socket? That's the single likeliest cause -- e.g. if you're using 192.168.x.y for whatever values of x and y, or 10.x.y.z likewise, that's a local-network address only, not routed by inter-network routers by internet conventions (most routers can be programmed to forward some incoming packets to a specific local-network address, typically depending on ports, but that's very specific to router's brands and models).