1

I need to re-create a customer scenario where-in the same ip:port pair is reused when we establish a new connection.

I want to create a program based on this scenario:
Client establishes connection with server using port XXXX.
Client terminates connection.
Client establishes another connection with server using the same port XXXX.

I have modified simple server/client code such as, I have called bind() before accept() on the client code. When I run the first round of the client program, it works, but on the second round, the connection is accepted by the server, but no message is being passed from client to server.

Can someone look at the code and help me in this ?

server.c

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int Create_Socket(void)
{
    int c_socket;
    printf("Creating Socket\n");

    c_socket = socket(AF_INET, SOCK_STREAM, 0);

    return c_socket;
}


int Bind_Socket(int socket)
{
    int bind_s = -1;
    int server_port = 7777;
    struct sockaddr_in server = {0};
    printf("Creating bind\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("22.0.0.1");
    server.sin_port = htons(server_port);

    bind_s = bind(socket, (struct sockaddr *)&server, sizeof(server));

    return bind_s;
}


int main(int argc, char *argv[])
{
    int socket_description, socket, client_length, read_size;

    struct sockaddr_in server_address, client_address;

    char client_message[200] = {0};

    char message[100] = {0};

    const char *pMessage = "Hello Vishnu Vijayan";


    //Create Socket
    socket_description = Create_Socket();
    if(socket_description == -1)
    {
        printf("Could not create socket\n");
        return 1;
    }
    printf("Socket Created\n");


    //Bind Socket
    if(Bind_Socket(socket_description) < 0)
    {
        perror("Bind failed");
        return 1;
    }
    printf("Bind done\n");

    listen(socket_description, 3);


    while(1)
    {
        printf("Waiting for incoming connections.... \n");

        client_length = sizeof(struct sockaddr_in);

        //accept connection from an incoming client
        socket = accept(socket_description, (struct sockaddr *)&client_address, (socklen_t*)&client_length);

        if(socket < 0)
        {
            perror("Accept failed");
            return 1;
        }
        printf("Connection accepted\n");


        memset(client_message, '\0', sizeof(client_message));
        memset(message, '\0', sizeof(message));

        //Receive a reply from client
        if(recv(socket, client_message, 200, 0) < 0)
        {
            printf("recv failed\n");
            break;
        }
        printf("Client reply : %s\n", client_message);

        strcpy(message, pMessage);


        //Send some data
        if(send(socket, message, strlen(message), 0) < 0)
        {
            printf("Send failed\n");
            return 1;
        }

        close(socket);
        sleep(1);
    }

    return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>


int Bind_Socket(int socket)
{
        int bind_s = -1;
        int client_port = 7777;
        struct sockaddr_in client = {0};
        printf("Creating bind\n");

        int reuse = 1;

        if(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
        {
                perror("SO_REUSEADDR failed");
                return -1;
        }

        if(setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
        {
                perror("SO_REUSEPORT failed");
                return -1;
        }

        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr("20.0.0.1");
        client.sin_port = htons(client_port);

        bind_s = bind(socket, (struct sockaddr *)&client, sizeof(client));

        return bind_s;
}



int Receive_Socket(int socket, char* from_server, int length)
{
    int receive_s = 1;

    receive_s = recv(socket, from_server, length, 0);

    printf("Response : %s\n", from_server);

    return receive_s;   
}


int Send_Socket(int socket, char *send_to_server, int length)
{
    int send_s = -1;

    send_s = send(socket, send_to_server, length, 0);

    return send_s;
}


int Connect_Socket(int socket)
{
    int connect_s = -1;
    int server_port = 7777;
    struct sockaddr_in server = {0};
    printf("Connecting socket\n");

    server.sin_addr.s_addr = inet_addr("22.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);

    connect_s = connect(socket, (struct sockaddr *)&server, sizeof(struct sockaddr_in));

    return connect_s;
}


int Create_Socket(void)
{
    int c_socket;
    printf("Creating Socket\n");

    c_socket = socket(AF_INET, SOCK_STREAM, 0);

    return c_socket;
}

int main(int argc, char *argv[])
{
    int socket, read_size;

    struct sockaddr_in server_address;

    char send_to_server[100] = {0};

    char server_reply[200] = {0};


    //Create Socket
    socket = Create_Socket();
    if(socket == -1)
    {
        printf("Could not create socket\n");
        return 1;
    }
    printf("Created Socket\n");


    //Bind Socket
   if(Bind_Socket(socket) < 0)
   {
        perror("Bind failed");
       return 1;
   }
   printf("Bind done\n");


    //Connect to server
    if(Connect_Socket(socket) < 0)
    {
        perror("Connect failed");
        return 1;
    }
    printf("Successfully connected with server\n");

    printf("Enter the message: ");
    gets(send_to_server);

    //Send data to server
    Send_Socket(socket, send_to_server, strlen(send_to_server));

    //Receive data from server
    read_size = Receive_Socket(socket, server_reply, 200);

    printf("Server Response : %s\n\n", server_reply);

    close(socket);

    return 0;
}
  • 1
    One major problem: You treat the data you send and receive as null-terminated strings, but you don't actually send the null-terminator! – Some programmer dude Oct 22 '18 at 08:48
  • 2
    Furthermore, ***never ever*** use the `gets` function. It's [a dangerous function](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) and have therefore been removed from the C specification. Use e.g. [`fgets`](https://en.cppreference.com/w/c/io/fgets) instead. – Some programmer dude Oct 22 '18 at 08:49
  • Finally, about the problem you ask about: Why do you bind the socket in the client? That's usually not needed unless you want to bind to a specific interface locally (which is rarely needed). Create the socket, connect to the server, send and receive. That's all. – Some programmer dude Oct 22 '18 at 08:52
  • How to send the null-terminator ? – Vishnu Vijayan Oct 22 '18 at 08:53
  • I used bind because I want to reuse the same port. – Vishnu Vijayan Oct 22 '18 at 08:53
  • On some squared paper, write a few letters in adjacent squares, ending with a `'\0'`. Then remember that [`strlen`](https://en.cppreference.com/w/c/string/byte/strlen) returns the length without the terminator. – Some programmer dude Oct 22 '18 at 08:55
  • Regarding the port reuse, *why*? What is the problem that's supposed to solve? Please edit your question and elaborate on the issue. – Some programmer dude Oct 22 '18 at 08:56
  • That is it. I want a connection to be established. When I create a new connection using the XXXX port immediately after I terminate the old connection with XXXX port. – Vishnu Vijayan Oct 22 '18 at 09:04
  • I think you have some mis-understandings about port reuse in socket programming. The `port` is something related to the server side. When your client connects to the server, it surely use the same port, otherwise you cannot connect to your server successfully. The `port` is not a kind of resource in your client side, so don't worry about it. Just get rid of the `bind` part in your client code, and you'll be fine. – colin Oct 22 '18 at 09:34
  • I understand. But I 'WANT' to reuse the port. I want the client to use the same 4-tuple to establish a new connection as the previous connection. – Vishnu Vijayan Oct 22 '18 at 10:02
  • I have modified the question. Can someone help ? – Vishnu Vijayan Oct 24 '18 at 06:28

1 Answers1

1

You may want to read the following answer:
https://stackoverflow.com/a/14388707/15809

Especially the notes about closing TCP sockets in TIME_WAIT state as well as how SO_REUSEPORT can lead to a kind of load balancing under Linux. I think either one of these two effects could play a role here.

Mecki
  • 125,244
  • 33
  • 244
  • 253