socket.bind() vs socket.listen() - python

I've learned how to write a python server, and figured out that I have a hole in my knowledge.
Therefore, I would glad to know more about the differences between the commands bind(), listen() of the module called socket.
In addition, when I use bind() with a specific port as a parameter, Is the particular port being in use already, before using the listen() method?!

I found a tutorial which explains in detail:
... bind() is used to associate the socket with the server address.
Calling listen() puts the socket into server mode, and accept() waits for an incoming connection.
listen() is what differentiates a server socket from a client.
Once bind() is called, the port is now reserved and cannot be used again until either the program ends or the close() method is called on the socket.
A test program that demonstrates this is as follows:
import socket
import time
HOST = '127.0.0.1'
PORT = 65432
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
while 1:
time.sleep(1)
when running two instances of this program at once, you can see that the one started last has the error:
Which proves that the port is reserved before listen() is ever called.

Related

Simple pair communication with pynng

I am trying to set up a very simple pair communication using pynng, but the listening instance never seems to receive any messages when sending via TCP from a different device.
client.py
s = Pair0(send_timeout=10000)
s.dial('tcp://192.168.0.44:5556')
time.sleep(2)
try:
s.send(b'asdf')
except pynng.exceptions.Timeout:
pass
s.close()
server.py
s = Pair0(recv_timeout=10000)
s.listen('tcp://127.0.0.1:5556')
time.sleep(2)
try:
print(s.recv())
except pynng.exceptions.Timeout:
pass
s.close()
so really I am just trying to send anything to the server here, but it never receives anything.
What am I missing here?
As #larsks pointed out in the comments
You are binding your server to the loopback address, 127.0.0.1. This address is only available on the local machine. If you expect your server to accept connections from other devices on the network, you need to bind to a nonlocal ip address, or 0.0.0.0 (which means "all addresses").

socket.recvfrom(1024) throws socket.error invalid argument supplied

I have started to learn UDP sockets but for some reason this code is throwing an error. why does this code:
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
x=s.recvfrom(1024)
throw an error of invalid argument supplied?
UDP datagram communications take place between source and destination ports. You can assign a port with a bind call or let the network stack choose one for you by simply calling one of the send/recv methods. If you call sendto (and you have no bound a port), the stack will assign a number in the dynamic port range. If you call recvfrom, the stack will typically assign port 0. But there is no port 0. What happens next is platform dependent. Windows will attempt to bind you as a promiscuous listener. But that is a privileged call and you will likely get an invalid argument error. But it may work if you are administrator - i'm not sure.
To start a conversation, the first entity to send something needs to know what destination port to use. That means that the entity that receives the first communication needs to bind to a port number that the other side knows about in advance. This could be a well-known port number, a port hardwired into your code, something in a config file or even something advertised with a name service protocol such as LDAP.
Once that first datagram is received the receiving entity now has the senders address and port number so can talk back.
In your example, your entities could agree on a well-known port and begin a conversation. here is a datagram echoer listening on port 9999.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 9999))
while 1:
data, addr = s.recvfrom(8096)
s.sendto(data, addr)
and a client that talks to it
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for i in range(10):
s.sendto(str(i), ('', 9999))
print(s.recvfrom(1024))

closing a previously opened socket

I created a program which listens to particular socket in python, however I ctrl+c'd script which resulted in .close() nor called, however how can I free the socket now.
The socket is closed when the process exits. The port it was using may hang around for a couple of minutes, that's normal, then it will disappear. If you need to re-use the port immediately, set SO_REUSEADDR before binding or connecting.
Set the SO_REUSEADDR socket option before calling the bind method, like this:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
That will instruct the socket to freely reuse the ports left in a waiting state by recent runs of the program.
Or, use the SocketServer.TCPServer class from the standard library, which will automatically do this if you set the allow_reuse_address property on the server instance to a true value.

python socket/port problem/question

I am writing 2 small programs (a server and a client) and whenever I run both, and have the client connect to the server, the server output says that I am connected on a port of which I didn't bind in the code. I binded both the server and the client socket to the localhost and port 8000, but every time the server is connected to by the client, it says that the client is connected on port 52304 or some other number larger than 50000, shouldn't it at least be a constant port number even if it isn't the one I bound it to? Also, I know, that if I run the server program more than once in the same terminal, even if I exited the program, the port is still taken, so I usually run the server, quit, then exit the terminal, which usually solves that problem. That is another note I should make, when I do run the server program the second time in the same terminal, it recognizes I am trying to bind to port 8000 and the program wont run, then when it does it chooses some random port.
Here is my server code:
import socket
import os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind('', 8000)
s.listen(5)
while 1:
client,addr = s.accept()
print "Accepted a connection from: ", addr
data = client.recv(1024)
client.send("You said: " + data)
The port number it's reporting is the one the client connected from. And it will be a random port number. If (as your question seems to imply) you have a bind call in the client that looks just like the one in the server, then I'm surprised it's succeeding since the server has already bound itself to that port and only one thing can be bound to a given port at a time.
Please post your client code. Contrary to what your question implies, I don't think that you are binding to a port on the client side. I'm betting you're just connecting. Now, that, generally speaking, is what you're supposed to be doing. So the fact you're confused by the results just means that you don't really understand what's happening exactly. The results you're seeing are perfectly expected and normal.
Here is an explanation of what's going on:
A TCP connection is uniquely identified (globally unique, as in no other TCP connections in the entire world will have the same identifier (though this isn't really exactly true with NAT and private IP ranges)) by these 4 pieces of information:
client ip
client port #
server ip
server port #
When your server is reporting a connection, it's printing out the first two values because they are what is returned by the accept call. When you are doing a bind call in the server, you are specifying values 3 and 4. The OS generally picks values 1 and 2 for the client automatically when it does a connect call.
A client normally does not bind to a port (though it can). It normally lets the OS pick a port for it. The client's OS will pick a port number from a list of unused port numbers. In your connect call on the client side, you are giving values 3 and 4 (the values specified in the bind call on the server side). The OS should automatically assign your client values 1 and 2 for you.
Think about it like the sender and recipient address on an envelope. The accept call on the server side reports the sender address because presumably the server already knows its own address. The client is most concerned with the recipient address (the address of the server) and lets a clerk (the OS) just paste on a return address,
The port and socket that the server listens on is not the same socket that is used once the connection is established. The accept call creates a new socket when a client connects for sending and receiving data. Otherwise if it used the same socket...then no other clients would be able to connect.
You also need to properly close your socket so it does not hang around after your program terminates.
You can never bind the same port to more then one program, the port the server gives you is the port the client wants you to send the data over. I think its to avoid connection collisions.
So you don't have to worry about the ports if the connection is establish.
But if you want the server to be able to receive more the one connection take a look at this:
Multiple simultaneous network connections - Telnet server, Python

I can't connect to socket from the outside

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).

Categories

Resources