TCP Sockets defined as tuples and python - python

If a TCP socket is defined by a 4-tuple (source IP,source port,destination IP,destination port), then what would be the values for a TCP socket created in Python after the following Python code has been executed (i.e. when a server application is set to 'listen' to this socket)?
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind((‘’,serverPort))
serverSocket.listen(1)
print ‘The server is ready to receive’
In particular, what does Python set for the destination values of a socket that a server is listening to?
Are these values randomly set, and if so how can I view them once a socket has been created?
The above code and question is taken from, and relates to, Kurose-Ross-Computer Networking.
Thanks in advance.

To query the source and destination addresses of a socket, call the getsockname() and getpeername() methods on the socket object.
In your case, serverSocket.getsockname() returns ('0.0.0.0', 12000) because that is the bind address you specified. getpeername() on a server socket always raises a socket.error: Transport endpoint is not connected because the server socket cannot be connected to a remote peer.
For a server socket to accept incoming connections, you must call its accept() method. This will return a client socket for which the peer name will be the pair of (address, port), address being the IP address of the peer, and port being the local port number assigned for communication with the peer.

If a TCP socket is defined by a 4-tuple (source IP,source port,destination IP,destination port)
It isn't. A TCP connection is so defined. A TCP socket is just an endpoint.
then what would be the values for a TCP socket created in Python after the following Python code has been executed (i.e. when a server application is set to 'listen' to this socket)?
It would have a local port of serverPort, a local address of 0.0.0.0, and no remote address or port.

Related

How to get broadcast address with python socket in localhost?

I try to send messages in localhost to broadcast address, but it does not work. When I use socket.INADDR_BROADCAST, I get [Errno 11001] getaddrinfo failed.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_server.bind(("127.0.0.1", 12345))
client_server.connect((f"{socket.INADDR_BROADCAST}", 12345))
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))
You are creating a TCP (SOCK_STREAM) socket. TCP has no notion of broadcasting. A TCP client socket cannot connect() to a broadcast IP, and a TCP server socket cannot listen() on a broadcast IP. That just makes no sense to do. The only way to broadcast a message in TCP is for the server to keep track of each client connected to it and then send the message to each client one at a time.
A UDP (SOCK_DGRAM) socket, on the other hand, can sendto() a message to a broadcast IP (if you enable the socket's SO_BROADCAST option beforehand), and it can recvfrom() a message that was sent to a broadcast IP belonging to the adapter that the socket is bound to.
Just note that bind()'ing a broadcasting UDP socket to 127.0.0.1 means that only UDP receivers also bound to 127.0.0.1 will be able to receive the broadcasts. You won't be able to broadcast over the network.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#client_server.bind(("127.0.0.1", 12345))
client_server.setsockopt(client_server.SOL_SOCKET, client_server.SO_BROADCAST, 1)
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))

Socket module (python) works but doesn't use specified port number?

I'm using the socket module from Python 3.7 (shouldn't matter, as I tried activating a different Python version from different venv's).
The problem is that I've created a TCP connection listening at port 65432, an arbitrary number that I selected for this simple demo.
server.py looks like the following:
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Non-privileged ports are > 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
client.py is relatively straightforward as it makes a connection with 127.0.0.1:65432.
import socket
HOST = '127.0.0.1' # The server's hostname or IP address
PORT = 65432 # Port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# Send its message and then read the server's reply and prints it
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
Executing server.py to open the port 65432 for listening (in first console) and then executing client.py to send a simple 'hello world' message (in a second console). This is what got printed to the first console:
Connected by ('127.0.0.1', 56051)
So far so good. Port 56051 connecting to port 65432, right? No.
I execute netstat -am (command tool utility to see state of sockets on the host machine) and found this:
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.51495 *.* LISTEN
Instead of 127.0.0.1.65432 as local address, it is using port 51495 instead.
Doing another verification check, this time firing off lsof -i -n:
COMMAND PID FD TYPE DEVICE SIZE/OFF NODE NAME
Code\x20H 51214 37u IPv4 0x1af15eb424ba89f3 0t0 TCP 127.0.0.1:51495 (LISTEN)
Both verifications confirmed that port 51495 is being used instead of 65432 as specified in my server.py and client.py scripts. Any leads or tips? Many thanks in advance!
65432 is the port number of your server socket, not your client socket. As the client end is not attached with any specific port number, it will be dynamically allocated with port number, every time you run the client code.
As far as I understood, you mentioned -
Connected by ('127.0.0.1', 56051)
is shown on the first console which is your server console. so this port number is port number of client socket. not the server socket.
In the server code, you are using, s.accept(), this function returns the connection temporary id and the address of the client which made the request. same thing you are trying to print in the code.
As #ottomeister pointed out, the process name was the first giveaway. The process name should have been Python but it showed VS Code instead, which is indicative that the port 51495 is opened by the VS Code process and has nothing to do with our socket module code.
The way the context manager was setup means that the connection will be closed the moment the last line (in this case, socket.sendall()) is executed. So the server socket is not active anymore.
I run netstat after the client socket has connected, by this point the server port is closed.
When I monitor the ports status while the server port is open (before the client socket connects with it) then sure enough 65432 is what appeared. This is confirmed in netstat, lsof and also nmap. A simple print statement after the socket connection is successful will also confirmed that the server port is in fact using the specified port number, which is 65432.
Sorry for the inconvenience, and again much appreciation to Ottomeister for first pointing this out.

Python 3 localhost connection

I'm trying to run the below program but I keep getting connection error's:
from socket import *
from codecs import decode
HOST = 'localhost'
PORT = 5000
BUFSIZE = 1024
ADDRESS = (HOST, PORT)
server = socket(AF_INET, SOCK_STREAM)
server.connect(ADDRESS)
dayAndTime = decode(server.recv(BUFSIZE), 'ascii')
print(dayAndTime)
server.close()
ERROR: ConnectionRefusedError: [Errno 61] Connection refused
Any idea what's going on?
If your book doesn't mention the other half of sockets, you need a better book.
Socket basics are easy. You have one process listen on a port, waiting for connections. Commonly we'll call this a 'server'. Another process (perhaps on the same machine, perhaps remote) attempts to connect to that port. We'll call that the client.
If no one is listening, then when the client attempts to connect they'll get your error Connection Refused.
So, set up a listening process. Below, on the left is server code; on the right is client code. Top-to-bottom is the "flow".
server = socket(AF_INET, SOCK_STREAM) # <- just like your example
server.bind(ADDRESS) # rather than 'connect', we 'bind' to the port
server.listen(1) # bind "claims" the port, so next we call listen & wait...
# Meanwhile...
# Your client process
client = socket(AF_INET, SOCK_STREAM)
client.connect(ADDRESS)
# It's only at this moment that the client reaches across the network to the server...
# On connect, the listening server wakes up, and needs to "accept" the connection
(s, remote_addr) = server.accept()
Once accepted, you can now send/recv on the s socket on the server-side, and send/recv from the client socket on the client side. Note that the server variable is not the socket to communicate on -- it's used to listen for new connections. Instead, you read/write on the socket object returned as first item of accept().
There's lots more to consider but this is at the heart of the Internet and has been pretty much unchanged since the 1980s.
Image from wikipedia entry for Berkeley Sockets:

how to avoid two socket with same port number python

Now here is sample for the server part of socket.
I want to have serverSocket and connectionSocket with different port number, but for now, they are using same port number.
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind((‘’,serverPort))
serverSocket.listen(1)
print (‘The server is ready to receive’)
while 1:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024)
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence)
connectionSocket.close()
if they are using same port number, would there be some collision?
There is nothing to avoid, and there is really no easy way to avoid it - this is how TCP is supposed to work.
In TCP there are 2 kinds of sockets:
listening server sockets
connected sockets
The server sockets start listening to incoming connections with listen; and wait for client connections with accept. Clients create a socket that is connected to the server address (host, port). When the server accepts a connection, a new connected socket is created between the (client_address, client_port) and (server_address, server_port). The TCP stack on the server can see from status bits easily if the packet is a connection request, or destined to an already connected socket. If it is a communication between already connected sockets, then it finds out the file descriptor that is bound on the local address and local port and is connected with the source address, source port of the remote end.
The connected socket will have the same port as the listening server socket; both Ende of the socket know 4 things: local address, local port, remote address and remote port. You can have 1 server socket bound on 10.20.30.40:12345 at the same time with thousands of sockets connected from 10.20.30.40:12345 to thousands distinct addresses.
There is really congestion only in the connection attempt phase; the server_socket.listen(1) means that the server will queue just 1 incoming connection; subsequent connections will be rejected until the incoming connection is accepted.
From Linux manual pages, listen(2) on the backlog argument of sock.listen:
The backlog argument defines the maximum length to which the
queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may
receive an error with an indication of ECONNREFUSED or, if the
underlying protocol supports retransmission, the request may be
ignored so that a later reattempt at connection succeeds.
Althouh I've never used raw sockets in Python, I guess this question more generally deals with how TCP and IP work.
When a server listens for connections on a port, clients will connect to that port, and the TCP connection can be identified by the quadruple (server_addr, server_port, client_addr, client_port), so there is no ambiguity when packets belonging to different connections will be sent or recieved, because the (client_addr, client_port) part will be different for each of them.
That said, there is no conflict in the addressing.
However, note that it is common that servers fork (or spawn a thread) after accepting each request, so that the main proces (or thread) can keep acceprint connections while other connections are handled by the forked processes (or threads). In your case, instead, once your server starts processing a request, it computes the response before calling accept() again, so any other client will have to wait before having its request served.

Selecting random port on a remote host

I want to select a random high port on a remote linux machine and use it for my application. On my localhost, I can bind to port 0 and get a random high port, but this does not work if I give a remote host.
The code is as follows:
host = "remote_host"
def get_open_port():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
Error:
Traceback (most recent call last):
File "server.py", line 25, in <module>
port = get_open_port()
File "server.py", line 11, in get_open_port
s.bind((host,0))
File "<string>", line 1, in bind
Well I guess you are bit confused with the client-server communication. Before getting to the solution of your problem lets first revisit the client-server communication process. Normally it is the client who makes/initiates the connection request (simply a connection) to the server. The client makes a request to the server on a remote port which is listening for incoming connections. This remote port should be open on the server side and should be waiting for incoming connections. For eg: If you want to connect to a remote server on the remote port number 15200, then it is mandatory that you should open the port number 15200 on the server side and it should be listening for any incoming connections/requests. Also, the client will know this in advance to which remote port it should make a request for a connection!
Lets understand some more facts before getting to the one of the possible solution to your problem. First lets understand the server side.
Server side: You are trying the server to use any random port for accepting incoming connections from a client. It will surely work as you are binding port number 0 in your server code as s.bind((host,0)). When you bind the port number 0 then your server (actually the OS which is running the server script) will use any random high port number for accepting the remote connections which will be usually greater than 1023. You can test this by following code snippet. Run the following code snippet and you may notice that the server is opening random high port numbers.
import socket
host = "127.0.0.1"
def get_open_port():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
for i in range(0,5):
print "Opening port no. %s"%get_open_port()
On executing the above code you'll shall see that a random port number is being selected by the server code to accept incoming connections every time. But it is also closing it after wards using s.close(). In my case the output was as below (You may get a different set of port numbers):
Opening port no. 60876
Opening port no. 60877
Opening port no. 60878
Opening port no. 60879
Opening port no. 60880
So, I guess now you understood the server part. Lets discuss the client side now.
Client side: As mentioned earlier that a client needs to know the remote server port to which it needs to connect. A typical client code looks as given below:
import socket
host = "127.0.0.1"
port = 60880
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
In the above code snippet this line s.connect((host, port)) you need to mention the host the remote host name or IP and port the remote port to which you want to connect to.
So it means that client should know the port number in advance! As a result you have to mention the port in your client code. As I have done in my code snippet as port = 60880.
Now coming to your question: As you already noticed from above text that you have to mention the remote server's port number in client code to make a request for a connection. So, you can't expect your client to figure out itself the remote port of the server which is actually listening for incoming request. The client code can't do this by its own.
Solution:
So what if the client code can't figure out by itself the remote port number we'll make it to figure it out! ;) What we know is if you bind the port number 0 on server side then a random port number will be selected which will be greater than 1023. So, it means the random port number will always be greater than 1023. Also, the maximum value of port number is 65535. Ultimately we come to a conclusion that the random port that will used by the server will be any port number in this range 1024 - 65335.
Now all you have to do is in your client code you have to use a range of port numbers to which it should make connection. Because we don't know what remote port is listening on the server side for accepting incoming requests/connection!
Sample code for plying around: I tested these code snippets using my localhost. Here is the server code. Run the server code first then run the client code. Upon executing the server code, it'll display in console/output that what is the random port number opened for accepting incoming request/connections. When a client is connected the server will display a message the Got a client connected along with the IP of the client.
#This is the server script
import socket
host = "127.0.0.1"
def get_open_port():
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind((host,0))
mySocket.listen(1)
port = mySocket.getsockname()[1]
print "Port opened for incoming connections %d"%port
(clientSocket, clientAddress) = mySocket.accept()
print "Got a client: ", clientAddress
clientSocket.close()
mySocket.close()
get_open_port()
Here is a client code sample that will do this crazy stuff. It will try to connect on all the ports from 1024 - 65335 and when it finds any remote port which is listening for incoming connections. It will display a message "Connected to remote port" and then close the socket and continue looking for more open ports until it reaches the last port number 65355.
#This is the client script
import socket
host = "127.0.0.1"
def startConn():
for port in range(1024,65336):
try:
myClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Trying remote port: ",port
myClientSocket.connect((host,port))
print "Connected to remote port: ",port
myClientSocket.close()
except socket.error as msg:
myClientSocket.close()
continue
startConn()
This is just a sample code, I am intentionally closing the sockets after a successful is established. You can do something else what you ever you prefer. I hope now it is quite clear to you regarding server-client communication.

Categories

Resources