-2

Background

Since TCP sockets are identified with src IP/port and dest IP/port, I thought that two having TCP clients on same IP address with same port is possible if each of them connects to different servers.

So I tested it on my Macbook

  • Two servers(A and B) are listing on different port number.

  • 1st client is bound to some port(i.g. 1234) and connect to A.

  • 2nd client is bound to same port(1234) and connect to B.

The result is that 1st client successfully connected to A, but 2nd client failed to connect to B with error code 48 which means "Address already in use"

Question

So I guess that theoretically multiple TCP sockets can bind to same port on same IP address if dest IP or port are different, but practically (or in real world) OS does not allow different TCP sockets to bind to same port on same IP address except allocating new socket for TCP connection request at server-side .

Would you mind to comment if I mistake?

How to run test code

Compile

gcc server.c -o server

gcc client.c -o client

Run

I tested like this

./server 9000 <-- A server with port number 9000

./server 8000 <-- B server with port number 8000

./client 9000 1234 <-- 1st client succeeded to connect to A with local port 1234

./client 8000 1234 <-- 2nd client failed to connect to B with local port 1234

Code

server.c

#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // read(), write(), close()
#define MAX 80
#define SA struct sockaddr

// Function designed for chat between client and server.
void func(int connfd)
{
    char buff[MAX];
    int n;
    // infinite loop for chat
    for (;;) {
        bzero(buff, MAX);

        // read the message from client and copy it in buffer
        read(connfd, buff, sizeof(buff));
        // print buffer which contains the client contents
        printf("From client: %s\t To client : ", buff);
        bzero(buff, MAX);
        n = 0;
        // copy server message in the buffer
        while ((buff[n++] = getchar()) != '\n')
            ;

        // and send that buffer to client
        write(connfd, buff, sizeof(buff));

        // if msg contains "Exit" then server exit and chat ended.
        if (strncmp("exit", buff, 4) == 0) {
            printf("Server Exit...\n");
            break;
        }
    }
}

// Driver function
int main(int argc, char **argv)
{
    int sockfd, connfd, len;
    struct sockaddr_in servaddr, cli;

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    
    bzero(&servaddr, sizeof(servaddr));

    // assign IP, PORT
    int port = atoi(argv[1]);
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);

    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully binded..\n");

    // Now server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0) {
        printf("Listen failed...\n");
        exit(0);
    }
    else
        printf("Server listening..\n");
    len = sizeof(cli);

    // Accept the data packet from client and verification
    connfd = accept(sockfd, (SA*)&cli, &len);
    if (connfd < 0) {
        printf("server accept failed...\n");
        exit(0);
    }
    else
        printf("server accept the client...\n");

    // Function for chatting between client and server
    func(connfd);
    printf("close connection directly");

    // After chatting close the socket
    close(sockfd);
}

client.c

#include <arpa/inet.h> // inet_addr()
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> // bzero()
#include <sys/socket.h>
#include <unistd.h> // read(), write(), close()
#include <errno.h>
#define MAX 80
#define SA struct sockaddr

void func(int sockfd)
{
    char buff[MAX];
    int n;
    for (;;) {
        bzero(buff, sizeof(buff));
        printf("Enter the string : ");
        n = 0;
        while ((buff[n++] = getchar()) != '\n')
            ;
        long writeRes = write(sockfd, buff, sizeof(buff));
        printf("wrtie result : %d\n", writeRes);
        bzero(buff, sizeof(buff));

        long readRes = read(sockfd, buff, sizeof(buff));
        printf("read result : %d\n", readRes);

        printf("From Server : %s", buff);
        if ((strncmp(buff, "exit", 4)) == 0) {
            printf("Client Exit...\n");
            break;
        }
    }
}

int main(int argc, char **argv)
{
    int sockfd, connfd;
    struct sockaddr_in servaddr, cliaddr;

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");
    bzero(&servaddr, sizeof(servaddr));

    ////////////////////////////////////////
    // bind client socket to specific address
    bzero(&cliaddr, sizeof(cliaddr));

    // assign client IP, PORT
    int cliport = atoi(argv[2]);
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    cliaddr.sin_port = htons(cliport);

    // Binding client socket to given IP and verification
    if ((bind(sockfd, (SA*)&cliaddr, sizeof(cliaddr))) != 0) {
        printf("client socket bind failed...\n");
        printf("Error code: %d\n", errno);
        exit(0);
    }
    else
        printf("client socket successfully binded..\n");
    ////////////////////////////////////////

    // assign server IP, PORT
    int serverport = atoi(argv[1]);
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_port = htons(serverport);

    // connect the client socket to server socket
    if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
        printf("connection with the server failed...\n");
        exit(0);
    }
    else
        printf("connected to the server..\n");

    // function for chat
    func(sockfd);

    // close the socket
    close(sockfd);
}
obanadingyo
  • 317
  • 1
  • 2
  • 14
  • Code notwithstanding, the basic premise of the question is wrong. – Tangentially Perpendicular Apr 19 '23 at 03:47
  • I think Tangentially Perpendicular misunderstood TCP. At TCP word, multiple sockets has same IP address and port number. It's how a TCP based server (like HTTP) works. If each socket on the same IP should has different port, then how a TCP server serves more than 65535 connections simultaneously? – obanadingyo Apr 19 '23 at 04:06
  • @obanadingyo on the server side, every connected socket shares the server's listening IP/Port. So that is not a limiting factor. It is the outbound IP/Port on the client's side that distinguishes the individual TCP connections on the server. – Remy Lebeau Apr 19 '23 at 04:20
  • @RemyLebeau Hmm, I can't catch what you mean exactly. I'm sorry but would you mind to explain more if possible. BTW, The original reason why I test this and ask you is start from your comment written on here (https://stackoverflow.com/a/27182614/2552915) – obanadingyo Apr 19 '23 at 04:25
  • @obanadingyo if you have `N` number of clients connected to the same server, the connections will be identified as ``, ``, ... ``, thus `N` can be greater than 65535 since they are all using 1 `` – Remy Lebeau Apr 19 '23 at 04:39
  • I don't know what you want here. The machine you're testing on has already told you that this can't be done, and it's been backed up by people here trying to explain to you why, but you're not listening. – Tangentially Perpendicular Apr 19 '23 at 04:40
  • 2
    @TangentiallyPerpendicular but it can be done, if SO_REUSEADDR option is set. It's not *normally* done on the client, but it can. – Mark Tolonen Apr 19 '23 at 04:41
  • @RemyLebeau I means `N` number of clients with same IP address and port number with different server. I think it is theoretically possible but it seems that not supported in real world. That's my question. – obanadingyo Apr 19 '23 at 04:45
  • @obanadingyo I know what you are talking about. I was addressing [your question](https://stackoverflow.com/questions/76050339/?noredirect=1#comment134125929_76050339) of how a single server can handle more than 65535 clients simultaneously. Obviously, your main question is about a different scenario. – Remy Lebeau Apr 19 '23 at 05:03
  • @RemyLebeau Thank you for your explanation. :) Actually, It was not question from I didn't know it. My intension was "Since TCP server can hold sockets with same ip address and same port, at least theoretically, it is also possible in client-side, too" Anyway would you mind check main question? Actually this starts from you comment: ( https://stackoverflow.com/questions/11129212/tcp-can-two-different-sockets-share-a-port#comment69119215_27182614 ) I think it is theoretically possible, but not works in real world. – obanadingyo Apr 19 '23 at 05:13
  • @obanadingyo Mark Tolonen already [answered](https://stackoverflow.com/a/76050787/65863) your main question. There is nothing more I can add to it. – Remy Lebeau Apr 19 '23 at 05:19
  • @RemyLebeau Hmm, okay, thank you~ Then it was better to mention SO_REUSEADDR at that time. It may mislead. Anyway thank you for your comment – obanadingyo Apr 19 '23 at 05:34

3 Answers3

2

Yes, it is possible, but to reuse the same client address the SO_REUSEADDR socket option must be set on for a client to use the same port.

Because it is less code and a language wasn't specifically tagged, I'll demo in Python. Note that the s1 and s2 sockets have the same client IP/PORT, but the open sockets have unique SIP/SPORT/CIP/CPORT values, differing only in server port. s3 wouldn't have been unique since s2 was already open, but s4 was successful because it changed the client port.

server.py

# Two server threads on different ports
# clients are handled with threads as well

import socket
import threading

def client_handler(sock):
    with sock:
        while True:
            data = sock.recv(1024)
            if not data: break  # client closed
            print(f'{sock}: {data}')  # just print socket info and data received
        print(f'{sock}: disconnected')

def server(port):
    with socket.socket() as s:
        s.bind(('', port))
        s.listen()
        while True:
            c, a = s.accept()
            print(f'{c}: connected')
            threading.Thread(target=client_handler, args=(c,), daemon=True).start()

threading.Thread(target=server, args=(5000,)).start()
threading.Thread(target=server, args=(6000,)).start()

client.py

import socket
import sys

def connect(sport, cport):
    s = socket.socket()
    # must set to have two clients use the same port
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('', cport))  # only needed to force a specific client port
    s.connect(('localhost', sport))
    return s

s1 = connect(5000, 1234)  # same client port, different server ports
s2 = connect(6000, 1234)
s1.sendall(b'hello1')
s2.sendall(b'hello2')
try:
    s3 = connect(6000, 1234)  # a 6000/1234 connection already exists
except Exception as e:
    print(e)
s4 = connect(6000, 2345)  # a different port is OK.
s4.sendall(b'hello4')
s1.close()
s2.close()
s4.close()

Run the server, then the client in separate terminals.

Server output:

<socket.socket fd=396, family=2, type=1, proto=0, laddr=('127.0.0.1', 5000), raddr=('127.0.0.1', 1234)>: connected
<socket.socket fd=396, family=2, type=1, proto=0, laddr=('127.0.0.1', 5000), raddr=('127.0.0.1', 1234)>: b'hello1'
<socket.socket fd=420, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 1234)>: connected
<socket.socket fd=420, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 1234)>: b'hello2'
<socket.socket fd=444, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 2345)>: connected
<socket.socket fd=396, family=2, type=1, proto=0, laddr=('127.0.0.1', 5000), raddr=('127.0.0.1', 1234)>: disconnected
<socket.socket fd=420, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 1234)>: disconnected
<socket.socket fd=444, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 2345)>: b'hello4'
<socket.socket fd=444, family=2, type=1, proto=0, laddr=('127.0.0.1', 6000), raddr=('127.0.0.1', 2345)>: disconnected

client output (from failed s3 connection):

[WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
-1

I thought that two having TCP clients on same IP address with same port is possible if each of them connects to different servers.

Even if this was possible how then these two connections would be differentiated? What if to make 10 connections to 10 different hosts in a similar way?

Let's imagine this is possible,and everyone from those 10 servers just sends its data to a that single client socket (same IP:port). From which one server data would be received from the following call:

long readRes = read(sockfd, buff, sizeof(buff));

Yes, that would be a total mess. Even if that was possible, it is not responsibility of the client socket, so client wants just to connect and communicate. So, you kinda overcomplicate things here.

Other story is serverside socket, it works this way from its inception. OS-level socket data structure is a state machine. So, what happens (in short), when you bind your socket to a particular interface and begin listening on it:

  1. Socket data structure is created by OS. This socket then goes to a listening state. Check it out with any networking tools (you will see something like interface:port LISTEN)
  2. For every new connected client server-side OS-level network stack creates a copy of a LISTENING socket with its local IPAddress:port pair. This is absolutely other socket data structure from OS perspective. Networking tools will show you something like interface:port ESTABLISHED.
  3. But you can't, obviously, create and bind more than one socket to the same IP:port pair to listen on them.

So, there is no mess here - server-side does its job, that's how demulitplexing actually works (using a couple of pairs - source IP:port, dst IP:port). Yes, you are right here.

But not for client side, client side usually picks up any accessible so called ephemeral port, if not specified explicitly.

There is one exception in UDP, using SocketOption.ReuseAddress, it is used in multicasting, when OS hosts multiple processes belonging to the same multicast group (I am not sure exactly how this mechanics works).

Also there is a possibility to run multiple processes, which use the same socket. So, the socket is the only one here. Not the case you are asking for, but very similar. IIS Web Server works this way afaik.

Ryan
  • 609
  • 6
  • 13
  • I think you mis-red my question. I don't mean that a single client socket with multiple connections, but "client socket per connection" and "each socket is bounded to same IP address and port". So, theoretically, I guess it's possible that 10 servers (each has different IP or port) responds to 10 client sockets each of them is bounded to same IP address and port number on same machine. At the machine, if OS stores 'which socket sends to which remote socket', each packet can be properly directed to correct socket because each TCP socket is identified by . – obanadingyo Apr 19 '23 at 03:54
  • Okay, to be precise, socket is uniquely identified by a triple values - proto:interface:port. It means you can use the same socket instance only in one connection, for client side. If you are trying to use the same ip:port, it means you are trying to use the same socket. That's the answer above. – Ryan Apr 19 '23 at 04:10
  • I think it's better to differentiate TCP and UDP because TCP and UDP has different socket identification method. In the TCP world, socket is uniquely identified by 4 values . In UDP world, socket is uniquely identified by 2 values – obanadingyo Apr 19 '23 at 04:13
  • Socket is a socket, TCP connection is TCP connection - this part is unclear to you. – Ryan Apr 19 '23 at 04:18
  • 1
    Hmm.. I don't think so. TCP connection is on a unique fair of two sockets. Since each TCP connection should be identified uniquely, it is uniquely identified by the two sockets' address – obanadingyo Apr 19 '23 at 04:29
  • @obanadingyo, right. So, should client take responsibility to demultiplex connections as server side? – Ryan Apr 19 '23 at 04:30
  • 1
    I think this knowledge is important in this case. If I develop some backend application, and it receives many http requests, and if the application needs to serve each request by calling another http server API, how many connections it can opens at the same time? Is it limit to port range? – obanadingyo Apr 19 '23 at 04:40
  • Finally agreed, but these are non-trivial use cases. – Ryan Apr 19 '23 at 05:32
-1

Conclusion

My own answer.

In real OS implementation, it seems than TCP client-side can't be bound to same IP/port explicitly. (but SO_REUSEADDR or SO_REUSEPORT enable it)

Why I ask? (cause TCP socket address may NOT unique)

Normally socket address is composed of <protocol, ip address, port>

But because of the word address, which implies uniqueness, sometimes it misleads that a socket can be identified UNIQUELY by socket address.

But it's not correct in the TCP world.

TCP is connection-oriented.

So each TCP connection requires dedicated two sockets, and the TCP connection is identified by two sockets' addresses by <src IP, src port, dest IP, dest port>

Now, let's look at TCP server. Whenever TCP connection request comes to the server, TCP server must allocate new dedicated socket for the request because it is connection-oriented protocol. In this case, what port number should be assigned to the newly create socket?

If socket address should be unique always, then nobody-used port number should be assigned to new socket. And if it would work like that, then max # of connections TCP server can handles simultaneously is as much as number of available ports.

But real world is not like it. Actually, TCP server can serve more connections than number of available ports at the same time.

How it works? The answer is.. whenever new dedicated socket is created at server side, same IP/port as listening socket are used. That is, on server side, there can be multiple sockets with same IP/port, and it means that socket address is NOT UNIQUE address.

Then how each socket can be identified?

Since this is connection-oriented TCP world, each socket can be identified by both server-side socket address and client-side socket address. That is, by <src IP, src port, dest IP, dest port>

This is how TCP works at server-side.

Then, one thing popped up on my head. 'Then, is it still working in this way in client-side?'

I started to googling and met this comment( TCP: can two different sockets share a port?)

That's why I actually started to test, and finally got into this conclusion.

obanadingyo
  • 317
  • 1
  • 2
  • 14