Socket programming in Python -- actual remote port - python

I've been doing a bit of network programming these days in Python and would like to confirm the flow I think happens between the client and the server:
The servers listens to a given
advertised port (9999)
The client connects to the server by creating a new socket (e.g. 1111)
The servers accepts the client request and automatically spawns a new socket (????) which would now handle the communication between the client and the server
As you can see, in the above flow there are 3 sockets involved:
The server socket which listens to clients
The socket spawned by the client
The socket spawned by the server to handle client
I'm aware of getting the ports for the first two sockets (9999 and 1111) but don't know how to get the "real" port which communicates with the client on the server side.The snippet I'm using right now is:
def sock_request(t):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 9999))
print('local sock name: ' + str(s.getsockname()))
print('peer sock name: ' + str(s.getpeername()))
s.send('a' * 1024 * int(t))
s.close()
Any help on getting the "port" number on the server which actually communicates with the client would be much appreciated. TIA.

The new socket is on the same port. A TCP connection is identified by 4 pieces of information: the source IP and port, and the destination IP and port. So the fact that your server has two sockets on the same port (i.e. the listening socket and the accepted socket) is not a problem.

Related

Connect to a server using public IPv4 address in python

I'm experimenting with socket server-client communication using python 3 socket module. Just to test if an eventual connection can be made, I've tried to program the simplest scenario possible. Thus the server code has the only purpose to print new connections; its code is:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("0.0.0.0", 30000))
while True:
server.listen()
print("listening...")
conn, addr = server.accept()
print(f"{addr} connected")
while the client only tries to connect to the server using the public IPv4 address of my computer:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Trying to connect...")
client.connect(("99.99.99.99", 30000))
client.close()
When I try to run the server and then the client nothing happens: the server just waits for conections, while the client displays nothing. After a while on the client side it is displayed the socket timeout error. I've tried to establish the connection even running the server and the client on the same computer, I've tried changing the ip of the server to "localhost" or "127.0.0.1", but nothing happens. Have you got any ideas on how this issue can be solved?
P.S. Thank you in advance for eventual answers and excuse my poor English, I'm still practising it!

Can't connect to local Machine IP through TCP From Arduino Uno using SIM900 Shield

So you have a basic understanding of the parts im using, I have:
Arduino Uno
Seeed Studio GPRS Shield v2.0 (http://www.seeedstudio.com/wiki/GPRS_Shield_V2.0)
Ultimate GPS for Adafruit V3.3 (https://www.adafruit.com/products/746?gclid=Cj0KEQjw3-W5BRCymr_7r7SFt8cBEiQAsLtM8qn4SCfVWIvAwW-x9Mu-FLeB6hLmVd0PAPVU8IAXXPgaAtaC8P8HAQ)
Here is my problem:
I have tested the Arduino stacked with the GPRS shield, and it works fine with regards to accessing the internet through TCP, sending SMS, etc.. However, my application requires me to send GPS data from the adafruit GPS to a web server that I have already coded with Django and postgresql. The backend is set up.
I need to send the data from the Uno (client) to my laptop (server), which I coded in python (This is just to check whether it is creating a connection):
#!/usr/bin/env python
import socket
# import postgres database functions
TCP_IP = '192.168.1.112'
TCP_PORT = 10000
BUFFER_SIZE = 40
server_address = (TCP_IP,TCP_PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created.'
# Bind socket to TCP server and port
try:
s.bind(server_address)
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket Bind Complete.'
# Start Listening on socket
s.listen(1) # Puts socket into server mode
print 'Listening on port: ', TCP_PORT
# Now Keep Talking with the client
while (1):
# Wait to accept a connection
conn, addr = s.accept() # Wait for incoming connection with accept()
print 'Connection address:', addr
data = conn.recv(BUFFER_SIZE)
if not data: break
print "recieved data: data", data
conn.send(data) #echo
conn.close()
I dont think there is a problem with this. From this I will post data to my postgreSQL database. However, When I try to use AT commands on the SIM900 module to connect to the server using port 10000, I cannot connect:
AT+CIPSHUT
SHUT OK
AT+CGATT?
+CGATT: 1
OK
AT+CIPMUX=0
OK
AT+CSTT="fast.t-mobile.com","",""
OK
AT+CIICR
OK
AT+CIFSR
6.60.94.49
AT+CIPSTART="TCP","192.168.1.112,"10000"
OK
STATE: TCP CLOSED
CONNECT FAIL
I have tried connecting through TCP and replaced the AT+CIPSTART line with the below statement and it worked, so I know TCP works:
AT+CIPSTART="TCP","www.vishnusharma.com", "80"
Is the IP i'm using wrong? I'm new to this, but if it makes a difference, im using Ubuntu 16.04 partitioned on my Mac OSX. I have also checked the APN for T-mobile and it seems fine.
Any help would be greatly appreciated. Thank You!
The IP you're using is inside a NAT since it starts with 192.168. Unless you have a private apn with the mobile operator you're using, you won't be able to reach your Ubuntu from a public IP. Your ISP gives you a public IP address which ir administrated by your router, so if you want this to work, you'll have to do a port forwarding from your router to your Ubuntu.
To do the port forwarding you have to get in the router's configuration page (Typically 192.168.1.1 but depends on the model) an there you'll have to redirect the port XXX to 192.168.1.112:10000. After that you have to obtain your public IP (curl ifconfig.co) and use it to access from the SIM900.
First of all as a suggestion, you can combine the two shields by using SIM908 (unless you are getting more precision on your GPS shield). Since your TCP connection is working, I bet that the port 10000 on your ubuntu is blocked by the firewall. You can first try to turn off your firewall and see if it works. If it did not worked its something else. If it worked, turn on your firewall and then unblock the tcp port using the following command:
sudo ufw allow 10000/tcp

Python client can not communicate with ruby server. I get [Errno 10061] No connection could be made because the target machine actively refused it

I have the intention of running machine learning algorithms written in Python on data in a database of a Ruby on Rails app. After some research I have discovered sockets and therefore created a Ruby server and Python client. I am running them both on two different command prompt terminals.
Here is the Ruby server code:
require "socket"
server = TCPServer.open(2000)
loop {
client = server.accept
client.puts(Time.now.ctime)
client.puts "Closing the connection. Bye!"
client.close
}
Here is the Python client code:
import socket
s = socket.socket()
host = "localhost"
port = 2000
s.connect((host , port))
I do not understand where the problem is. Kindly assist.
Given insightful answers to my question above the code Ruby server and Python client should be as below.
For the Ruby server:
require "socket" # Get sockets from stdlib
server = TCPServer.open("127.0.0.1" , 2000) # Socket to listen on port 2000
loop { # Server runs forever
client = server.accept # Wait for a client to connect
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}
For the Python client:
import socket # Import socket module
s = socket.socket() # Create a socket object
host = "127.0.0.1"
port = 2000 # Reserve a port for your service.
s.connect((host , port))
print s.recv(1024)
s.close() # Close the socket when done
The open() method of the TCPServer class in Ruby takes two parameters. The first being the host name and the second the port i.e
TCPServer.open(hostname , port)

Python Sockets: Connection Timeout

I'm trying to write two short python scripts that will connect two or more machines to each other, one as the server and the others as clients. It worked perfectly when testing the client and the server script on the same computer, but when I tried it from another computer the client kept timing out; it couldn't connect to the server. Here's my server code:
import socket
server = socket.socket()
host = "computername"
port = 12345
server.bind((host, port))
server.listen(5)
client, addr = server.accept()
Client code:
import socket
server = socket.socket()
host = "computername"
port = 12345
server.connect((host, port))
Any clue as to why the machines can't connect?
I think, you are changing host variable properly when running both client and server scripts in different machines. Try by changing that properly/or using IP address of server machine.
The communication could be prohibited by a firewall.
To rule out DNS related problem, try IPs instead of hostnames:
# server: listen on all interfaces
server.bind(('', port))
and:
# client: specify server's IP address
server.connect(("192.168.XX.YY", port))
with a real IP address, of course.

Python sockets - connecting using the same src IP/Port doesn't work

I have the server bind to a particular port:
serv_sock = socket(AF_INET, SOCK_STREAM)
serv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serv_sock.bind((gethostname(), MAGIC_FLOW_PORT))
serv_sock.listen(MAX_MAGIC_FLOWS)
while True:
(client_sock, address) = serv_sock.accept()
print "Accepted a flow"
And the client does this:
client_sock = socket(AF_INET, SOCK_STREAM)
client_sock.bind((gethostname(), MAGIC_FLOW_PORT+1))
client_sock.connect((server_ip, MAGIC_FLOW_PORT))
while True:
client_socket.send("ABCDEF")
time.sleep(5)
So the expectation is client sends a TCP/IP packet with src port MAGIC_FLOW_PORT+1 and dst port MAGIC_FLOW_PORT every 5 seconds.
I enabled tcpdump in the server and I can see the packet as expected every 5s. However, the server prints the "Accepted a flow" only once, and nothing after that.
However if I comment this line in the client socket:
client_sock.bind((gethostname(), MAGIC_FLOW_PORT+1))
client then generates a packet with a different src port every time and the server accepts that. I also tried the server with
serv_sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
I still don't the second packet picked up the server.
Can I connect with the same src IP/port multiple times to the same server?
Thanks
Binding to a certain port should always work if you have the permissions to do so (<1024 you need to be root) and no other socket is inhabiting the same port on the same interface.
Except, if you use SO_REUSEPORT, then you can bind multiple listening sockets to the same port.
Just think about it, how would the server side know where to send the reply? (Assuming no anycast routing magic here.)
If you comment out that client_sock.bind() then the kernel picks a free port as the source of your connection, so that explains why the port is different after every connect().
The counterpart of the server's accept() is the client's connect(), not send(). So you should get an accept() call to return every time some other socket connects to that listening socket. If you want to react to received messages you should use client_sock.recv(). (Docs).

Categories