tcp socket server get name of server client used - sockets

Let's say I have a server, which has multiple domain names which resolve to its IP address. For example my server is 10.0.0.33 and can be accessed by serverA.mysite.com, serverB.mysite.com, and serverC.mysite.com. If I have a process running with code similar to the following:
#!/usr/bin/env python
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.listen(5)
while True:
client, client_addr = server.accept()
#server_name = <some function>(client)
#Do Something with the client knowing the value of servername...
server.close()
Is there a way to determine if the tcp connection made by the client was aimed at serverA.mysite.com or serverB.mysite.com...?
My Example is in python but I don't need a python specific answer.

No, TCP/IP connections work at the IP address level, so you cannot determine how the client obtained the IP address on which your server was listening.
HTTP works around this by requiring (since 1.0) that the client send the original host name as part of the request data.

I believe - you are listening on INADDR_ANY ("0.0.0.0") and would like to know exactly which one the client connected to, if you were listening on multiple ports? That's fairly simple you should use s.getsockname after the accept. So your code would look something like this
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", 10000))
s.listen(5)
while True:
s2 = s.accept()
print s2.getsockname()
s2.close()

Related

How to let client application outside your netowrk connect to your server

I'm new to socket programming. I have developed fundamental/simple client and server application where client successfully communicates with server. Currently, both the server is on my system (local host) and client is also my system.
Now I want to somehow allow clients outside the network ( network where my system belongs to) to communicate with the server but i have no idea what to do and how to proceed. Any help would be appreciated.
Here's a smaple code taken from here
server.py
enter code here
import socket
# next create a socket object
s = socket.socket()
print "Socket successfully created"
port = 12345
s.bind(('', port))
print "socket binded to %s" %(port)
s.listen(5)
print "socket is listening"
while True:
# Establish connection with client.
c, addr = s.accept()
print 'Got connection from', addr
c.send('Thank you for connecting')
c.close()
client.py
import socket
s = socket.socket()
port = 12345
s.connect(('127.0.0.1', port))
print s.recv(1024)
s.close()
You don’t really need to change anything in your code, except for the IP that the client connects to. It needs to be the server PC’s public Internet IP instead of 127.0.0.1.
If the server PC is connected directly to the Internet modem, then you are done.
Otherwise, if the server PC is behind a router or proxy, then you need to configure port forwarding on that router/proxy to forward traffic from its public WAN IP/port to the server PC’s LAN IP/port. Consult your router/proxy’s documentation for how to do that configuration.
If the router/proxy has uPNP enabled, your server code can dynamically forward the WAN IP/port to itself at runtime. See Python: Open a Listening Port Behind a Router (upnp?)

Socket Connection Without Knowing Port Number - Python

I would like to create a connection between a server and a client via socket on 2 different computers (but the question is relevant also to a connection on the same computer). I know the IP of the server, but I would like to connect without knowing the port number of the server - is there a way to do so?
for example:
from socket import *
s = socket(AF_INET, SOCK_STREAM)
s.bind((127.0.0.1, " "))
s.listen(1)
conn, addr = s.accept()
Is there a way to do so?
Can it also be done without knowing IP?
You can't open a socket without knowing the port number. However, you can use the predefined port numbers in the protocol. For example, if port is not specified, HTTP uses port 80 and HTTPS uses port 443 by default.

Using SO_REUSEPORT to simulate stateful UDP

I am building a p2p application in which every peer can maintain a connection with multiple other peers.
Maintaining a connection is easy with TCP. I have a server listening on a specific port on every node. Whenver peerA wants to connect to peerB, it creates a socket and makes a connect call to the listening port of peerB. This creates a new socket on which both the peers can do all their subsequent conversation on.
I want to simulate the same concept of workflow in UDP. Something similar to this question The traditional way of conversing with multiple peers on UDP from what I found is that every peer is listening on a predefined port. Every sendTo call specifies the ip and port of the peer we want to connect to and on the receiver side, we use recvFrom to handle it based on which peer it is coming from (e.g. passing the msg to a thread which handles messages from that specific peer).
However, I wanted to know if there is any way of doing the same without the need to demultiplex at the receiver. I found the SO_REUSEPORT flag can be used to implement this http://man7.org/linux/man-pages/man7/socket.7.html
https://lwn.net/Articles/542629/.
Basically, SO_REUSEPORT allows multiple sockets call bind on the same port. So, I bind a server port similarly as before. However, when I get a connection from a new peer, I bind a new socket to the same port and call connect on the sender's address. Then I pass this new socket to a thread which listens to messages from the sender.
makeListeningSocket ip port = do
sock <- socket ip port
setSocketOption sock ReusePort 1
bind sock
return sock
runUDPServer sock = do
(receivedMessage, peerAddr) <- recvFrom sock 4096
newSock <- makeListeningSocket "0.0.0.0" 3001
connect newSock peerAddr
async (readMessagesFromSock newSock)
runUDPServer sock
I was able to make this approach work. However, SO_REUSEPORT option doesn't seem to be created with this specific use case in mind. So my question is, is there anything horribly wrong with using SO_REUSEPORT in this manner which I am not able to see? Are there better ways of doing this?

Using UDP between remote server and client

I am currently working on a project that needs a UDP communication between a server Amazon Frankfurt) and several hosts (Arduino). I need to be able to send JSON data from server to a host over UDP and it needs to work in real time (time is a real constraint here). Also, periodically a host will speak to server to inform server about its status.
The problem I'm facing is that although I can ping the server, when I create the UDP socket with a port, I get this error (for any port):
errno99: cannot assign requested address
I also believe that since the hosts are in different countries, I can only get router's IP. Hosts will be given to users therefore it is impossible to alter user's router by hand. I need to use something that can handle these by code.
I have been searching on Hole Punching and other techniques. I cannot decide what suits more to my scenario here. Sorry for my lack of network information, any help or guidance as "read or search these techniques" are appreciated.
This code runs on server:
import socket
import time
#Host's public IP
UDP_IP_ADDRESS = "178.243.98.86"
UDP_PORT_NO = 13000
Destination = (UDP_IP_ADDRESS,UDP_PORT_NO)
Message = "Hello, Server"
senderSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
senderSock.sendto(Message, Destination)
time.sleep(1);
And this code runs on my machine:
import socket
#Server's public IP
UDP_IP_ADDRESS = "172.31.46.111"
UDP_PORT_NO = 13000
recieverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recieverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
while True:
data, addr = recieverSock.recvfrom(1024)
print "Message: ", data
Server
# Host's public IP
UDP_IP_ADDRESS = "178.243.98.86"
You cannot rely on 178.243.98.86. Your arduinos are behind one or several NATs. With NAT, when a packet leaves a network, your packets source and/or destination addresses (and most likely ports) get rewritten. When this conversion happens, a device responsible for NAT remembers this conversion, but only for a limited period of time. The period usually defaults to 24h.
In order to overcome this issue, it's up to clients to initiate conversations with the server. Introduce a new message type to your protocol saying something like hey it's me, client #34. The server should be associating source IP and port of the received message with client #34 for some period of time, like hours.
In this case the server binds a socket to an address and port as well as a client. And beware that hey it's me, client #34 sent over UDP is not encrypted and is extremely vulnerable to record and replay attacks. I believe an emergency system should be encrypted.
Client
# Server's public IP
UDP_IP_ADDRESS = "172.31.46.111"
172.31.46.111 cannot be server's public IP, because it is an address from an IPv4 private space. You probably meant to say "host's private address". It makes sense to bind to such an address. You get an error most likely because you have incorrectly determined the IP address of your host.
There are several ways to get the correct IP. If you use DHCP (you use it if you've never though about what IPs to use in your SOHO), log into your nearest router's admin interface and check the DCHP Pool. Alternatively, Linux and Windows have terminal commands to do the same. For Arduino, you have probably assigned it a static address. If so, bind to it.
You also seem to open a tcp socket on the server, and connect to it from client via udp socket. Is this intentional?
gsn

When will one socket suffice, when do I need to create more?

The "connectionless" aspect of UDP has thrown me for a loop...
If I setup a UDP socket set to INADDR_ANY, then bind that to port 33445 on the local machine, the machine will accept incoming connections from various clients. All of these connections will be serviced by that one socket, since this is not TCP and I cannot spawning a new child sockets to handle each connection directly. I am able to reply to any, some, or all of these connected clients, from their latest message.
So where things get a little fuzzy for me is here...
Am I able to also send out messages at any time to any of these clients? or can I only send messages that in response of recvfrom() ?
Separately, if I wanted that server (while it is serving clients) to connect to another server and have a conversation about something else, I assume I will need to create a new socket for this purpose? I cannot just use the existing server socket and specify a new destination address?
Many thanks to this wonderful community.
Edit: Let me put it another way.. It seems to be that I can only use the bound socket for responding to clients that have previously reached me on that socket. To initiate a conversation with a new host, I cannot simply use the bound socket for that purpose? I must create a new socket in order to reach a server that is listening, correct?
UDP sockets can operate in two different modes:
default not-connected mode: all datagrams sent to the port/address of your process are received; you need to specify destination address for each send you do.
connected mode: only the datagrams sent from the address/port you connected to are received; you don't need to specify destination address on each send.
Here's a small review of connected UDP sockets.
Edit:
Here's a little python UDP server that accepts packets from any client and copies them to a second server. Everything is done with one not-connected UDP socket.
#!/usr/bin/env python
import sys, socket, string
if len( sys.argv ) != 4:
print "Usage: udptee <local-listen-port> <copy-host> <copy-port>"
exit( 1 )
copy = ( sys.argv[2], int( sys.argv[3] ))
s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
#s.bind(( 'localhost', int( sys.argv[1] )))
s.bind(( '', int( sys.argv[1] )))
print "listening on ", s.getsockname()
print "copying to", copy
while True:
line, addr = s.recvfrom( 1024 )
print "received: ", line, " from ", addr
s.sendto( line, addr ) # echo to source
s.sendto( line, copy ) # copy to tee
if string.strip( line ) == "exit": break
print "Goodbye and thanks for all the fish"
s.close()
Run it in one terminal as:
~$ ./udptee 9090 <IP-of-copy-server> 9999
Then start netcat in server mode in second term. This one will accept copies of the datagrams:
# this used to be "nc -ul 127.0.0.1 9999" which only listened on loopback
~$ nc -ul 9999
Start netcat client in third term to send stuff to the first server:
~$ nc -u <IP-of-tee-server> 9090
Start typing and see both servers echo what you type.
UDP sockets aren't connected to a remote host or client, so all you need to do is to use sendto() using the destination address and the UDP socket you have initialized. So yes, you can send out messages using the UDP socket at any time given that you have set up the UDP socket correctly. Just set the receiving address in the sockaddr struct you are using. If the receiving part have a UDP socket bound on the port you are sending the message, then it will receive it.
On that 2nd question it all depends if the conversation with that 2nd server uses a different port. If it uses the same port then there is no need to create another UDP socket. You just have to separate the messages the server 1 gets from its clients from messages it gets from server 2 somehow.
Ill recommend taking a look at Beej's excellent guide chapter 5.8 and 6.3.
Beej's Guide to Network Programming