Search code examples
csocketstcpconnection-refused

Trying, without success, to use a new socket after closing the old one


for a classwork i've to close all opened sockets after client sends "NEWPORT " and assign the "n-port" to a new socket, and from that moment i've to use the socket created for the new incoming connections, but when i try to connect to new one the perror function on client side says me "Connection refused".

Server code

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

#define MAX_SIZE 512

void manage_connections(int fds,struct sockaddr_in serv_addr, struct sockaddr_in cl_addr, socklen_t cl_len);

int main(int argc, char* argv[]){
    struct sockaddr_in serv_addr, cl_addr;
    socklen_t cl_len;
    int fds=0;

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_port = htons(5200);

    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    fds = socket(AF_INET, SOCK_STREAM, 0);

    if(fds<0){

        perror("Socket error");

        exit(-1);

    }

    if(bind(fds,(struct sockaddr*)&serv_addr, sizeof(serv_addr))<0){

        perror("Bind error");

        exit(-1);

    }

    if((listen(fds,5))<0){

        perror("Listen error");

        exit(-1);

    }

    manage_connections(fds,serv_addr, cl_addr, cl_len);

    close(fds);

    return 0;

}

void manage_connections(int fds,struct sockaddr_in serv_addr, struct sockaddr_in cl_addr, socklen_t cl_len){

    char buffer[MAX_SIZE], cl_ip[MAX_SIZE], cl_port[MAX_SIZE], cmd_np[MAX_SIZE], cmd_np_n[MAX_SIZE], cmd_np_str[MAX_SIZE], nport[MAX_SIZE];

    int i=0, port=0,fdc=0, nfds;

    struct sockaddr_in nserv_addr;

    while(1){

        cl_len = sizeof(cl_addr);

        fdc = accept(fds, (struct sockaddr*)&cl_addr, &cl_len);

        if(fdc<0){

            perror("Accept error");

            exit(-1);

        }

        do{

            for(i=0;i<MAX_SIZE;i++){

                buffer[i]=0;

                cl_ip[i]=0;

                cl_port[i]=0;

                cmd_np[i]=0;

                cmd_np_n[i]=0;

                cmd_np_str[i]=0;

                nport[i]=0;

            }

            read(fdc,buffer, MAX_SIZE);

            if(strcmp(buffer,"MYIP")==0){

                strcat(cl_ip,inet_ntoa(cl_addr.sin_addr));

                write(fdc,cl_ip,strlen(cl_ip));

            } else if(strcmp(buffer,"MYPORT")==0){

                sprintf(cl_port,"%d", (int)htons(cl_addr.sin_port));

                write(fdc, cl_port, strlen(cl_port));

            }else{

                sscanf(buffer, "%s %d", cmd_np, &port);

                sprintf(nport, "%d", port);

                if(strcmp(cmd_np,"NEWPORT")==0){

                    strcat(cmd_np_str, "ACK ");

                    strcat(cmd_np_str, nport);

                    write(fdc, cmd_np_str,strlen(cmd_np_str));

                    close(fds);

                    close(fdc);

                    nserv_addr.sin_family=AF_INET;

                    nserv_addr.sin_port = htons(port);

                    nserv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

                    nfds = socket(AF_INET, SOCK_STREAM,0);

                    if(nfds<0){

                        perror("New socket error");

                        exit(-1);

                    }

                    if((bind(nfds,(struct sockaddr*)&nserv_addr,sizeof(nserv_addr)))<0){

                        perror("New bind error");

                        exit(-1);

                    }

                    if((listen(nfds,5))<0){

                        perror("New listen error");

                        exit(-1);

                    }

                    manage_connections(nfds,nserv_addr, cl_addr, cl_len);

                }

            }

        }while(strcmp(cmd_np,"NEWPORT")!=0);

        close(fdc);

    }


}

Client code

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

#define MAX_SIZE 512

int main(int argc, char* argv[]){
    struct sockaddr_in cl_addr;
    int fdc=0,len=0, res_len=0,i=0;
    char buffer[MAX_SIZE];

    cl_addr.sin_family = AF_INET;

    cl_addr.sin_port = htons(5200);

    inet_aton("192.168.10.128",&cl_addr.sin_addr);

    fdc = socket(AF_INET, SOCK_STREAM,0);

    if(fdc<0){

        perror("Accept error");

        exit(-1);

    }

    if((connect(fdc, (struct sockaddr*)&cl_addr, sizeof(cl_addr)))<0){

        perror("Connect error");

        exit(-1);

    }

    while(1){

        write(1, "Inserire uno tra i comandi MYIP, MYPORT, NEWPORT:\n", strlen("Inserire uno tra i comandi MYIP, MYPORT, NEWPORT:\n"));

        len = read(1, buffer, MAX_SIZE);

        buffer[len-1] = '\0';

        write(fdc, buffer, strlen(buffer)+1);

        for(i=0;i<MAX_SIZE;i++)

            buffer[i]=0;

        res_len = read(fdc,buffer,MAX_SIZE);

        write(1,"\nResponso: ",strlen("\nResponso: "));

        write(1, buffer, res_len);

        write(1,"\n",strlen("\n"));

    }

    close(fdc);

    return 0;
}

Solution

  • Your client is hard-coded to the 5200 port number. If you use NEWPORT to switch the server to a new one, the server will no longer be listening on 5200 since you're closing the original listening socket and opening a new one.

    Hence when you run your client again, it gets Connection Refused because there's now nobody listening on the socket you're connecting to.

    The best fix I see is to add the ability to specify a port number as a command line argument on the client side.

    Other issues with your code:

    1. You're assuming that you will send the entire buffer content on each call to write and that you will receive the entire buffer content on every read. In a toy program like this, that will work, but is not guaranteed by TCP.

    2. Your manage_connections function is recursive which seems a poor structure. Enough invocations and you would run out of stack.

    3. There's no built-in way to exit your client program. You can press Ctrl-C to abort, but it doesn't detect that the server just closed the connection (because it's reading from the terminal) in the NEWPORT case.

    4. You're actually reading from the standard output file. That typically works if you're connected to a terminal, but would not work in other scenarios and is not a good thing to rely on.

    5. You're passing the cl_addr and cl_len variables into manage_connections but that's pointless. The caller doesn't initialize them before or use them after the call. They should just be declared inside the function.