0

I'm actually having troubles with a client-client application. Everything, in this question, is related to a Unix network programming environment.

This is my situation:

  • I have a client (called C1 from now on) that calls a listen() on a socket.
  • C1 puts the listenfd socket associated with the previous listen() call in an appropriate fd_set variable and calls a select() on it.
  • Once it receives a new incoming connection from another client (called C2 from now on), the select() procs, the connection is successfully created with accept() and the clients C1-C2 start communicating.
  • Let's call the accept() returned int accfd and the connect()returned int connfd.
  • Once they are done, both C1-C2 close the relative sockets with close(connfd),close (accfd).

Once done, both clients have the opportunity whether to send/receive data again or not. If C1 choose to restart its send/receive routine, the fd_set is zeroed (using the FD_ZERO() macro) and the listenfd is put again in the fd_set variable associated with the previously calledselect(). The thing is, if C2 tries to establish a new connection with C1, the second connect() doesn't make theselect() proc in C1,even if the connect() call made by C1 succeeds. This doesn't happen, if a third client (C3) tries to connect() to C1.

What I'm trying to understand, is how can I close a connection with a client and open a new connection with the same client at a different time. Note that I don't want the clients to keep the firstly created connection after their send/receive routine is done. I want to create a new connection with both clients.

Here's the client code, note that I omitted obvious or useless parts of the code:

int nwrite,nread,servsock,listenfd,clsock[10],mastfd,maxfd,s=0,t=0,i=0,j=0;
int act,count=0;
for (i=0;i<10;i++)
    clsock[i]=socket(PF_INET,SOCK_STREAM,0); //clsock is an array of sockets. Each time C2 tries to connect to a generic C1 client, it uses the clsock[count] int. count is incremented everytime a connection is closed.
for (i=0;i<10;i++)
    if(setsockopt(clsock[i],SOL_SOCKET,SO_REUSEADDR,(char *)&opt2,sizeof(opt2))<0)
    {
        perror("setsockopt");
        exit(-1);
    }
listenfd=socket(PF_INET,SOCK_STREAM,0); //this is the listening socket 
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt))<0)
{
    perror("setsockopt");
    exit(-1);
}
if (listenfd<0)
{
    perror("Listenfd: ");
    exit(-1);
}

if (bind(listenfd,(struct sockaddr*)&cl2addr,sizeof(cl2addr))<0)
{
    perror("Binding: ");
    exit(-1);
 }
if (listen(listenfd,100)<0)
{
    perror("Listening: ");
    exit(-1);
}
do
{
    do
    {
        FD_ZERO(&readfd);
        FD_SET(STDIN_FILENO,&readfd);
        FD_SET(listenfd,&readfd); //the listenfd socket is added
        FD_SET(servsock,&readfd);
[... Maxfd and the elaps structure are set....] 
        act=select(maxfd,&readfd,NULL,NULL,&elaps); //maxfd is calculated in another piece of code. I'm sure it is right.
        system("reset");
            if (FD_ISSET(listenfd,&readfd)) //when the listen procs, the loop ends for C1.
            {
            [...exits from the first  do-while loop...]
        }
        if (FD_ISSET(STDIN_FILENO,&readfd)) //this is where c2 exits from the loop
        {
          s=1;
          do some things here.
        }
    [.....some useless code here .....]
    }
    while (s!=1); //this is the condition used by c1/c2 to exit the loop
if (t==1) //this is what C1 runs, having t=1.
    {
        if ((mastfd=accept(listenfd,(struct sockaddr *) &cl2addr,&cllen))<0) //C1 accepts a generic connection
        {
            perror("Accept: ");
            exit(-1);
        }
[....do some things...]
        if (close(mastfd)<0) //Once done, it closes the actually connected socket
            {
                perror("Error closing mastfd");
                _exit(-1);

            }
    }
else //this is what C2 runs
    {   
        claddr.sin_addr.s_addr=inet_addr(ipbuff); // ipbuff is C1 port
        claddr.sin_port=htons(sprt); //sprt is C1 port
        if (connect(clsock[count],(struct sockaddr *) &claddr,sizeof(claddr))<0) //create a connection between C1 and C2
        {
            perror("Connect: ");
            printf("ERROR: %s",strerror(errno));
            exit(-1);   
        }
[....do some things...]
        if (close(clsock[count])<0)
        {
            perror("Error closing socket!");
            _exit(-1);
        }
count++; //increment count to be able to create a new connection and not to re-use the same socket in the clsock[count] array.
    }
if (menu==1)
    {           
        memset(&claddr,0,sizeof(claddr)); //this was when my brain was about to pop off
        fflush(stdin);
        fflush(stdout); 
        t=0;
        s=0;
        num_usr=0;
        system("reset");
        FD_ZERO(&readfd); //this is when my brain totally popped off
        FD_CLR(listenfd,&readfd);
        FD_CLR(servsock,&readfd);
        FD_CLR(STDIN_FILENO,&readfd);
        FD_SET(listenfd,&readfd);
        FD_SET(servsock,&readfd);
        FD_SET(STDIN_FILENO,&readfd);
    }
} while (menu==1)

Thank you all, if the question isn't well proposed or written, please let me know that. I'm sorry for my inexperience and for my English, I'm just getting started with network programming. Thank you so much, in advance, for your help.

  • 5
    Most likely seeing the proper parts of the code would help to understand the problem, or even a [mcve] – Sami Kuhmonen May 08 '17 at 12:24
  • I always make the same mistakes, I try to format the code in the proper way, I end up failing. I try to describe my problem, I end up failing. I try to put some code in it, I end up failing. I'm actually having great thoughts about my life and what I'm doing here. Just kidding, I will provide some code. Thank you. – Giulio Paoli May 08 '17 at 12:36
  • 2
    Be wary of [using `fflush(stdin)`](http://stackoverflow.com/questions/2979209/using-fflushstdin) — if you're on Unix, it's basically wrong. Nested `do … while` loops are worrying. The huge blocks of code in a single function are very worrying. It is hard to see what's going on where — which makes it hard to work out what might be going wrong. What does `system("reset")` do on your machine? It jiggers the terminal into a known state on macOS. You need to reduce your code so it is simpler, and compilable — the MCVE already requested. – Jonathan Leffler May 08 '17 at 13:57
  • I'm trying my best, I swear. I will shrink the code as possible. I'm sorry. – Giulio Paoli May 08 '17 at 14:10
  • Why did you remove the listenfd from the fdset in the first place? Just leave it there. You should always be interested in new connections, not just when the old one has gone. – user207421 May 08 '17 at 18:59
  • Trying to make it work, I thought maybe that it could have been a select issue. So I removed listenfd from the fdset at the end of the loop and re-added it at the beginning of the loop. That should not 'cause troubles. By the way, without removing the listenfd from the fd_set, the program still doesn't work. I am having serious thoughts about my programming skills. Please, tell me everything that's wrong in this code, I really appreciate it. Thank you so much, in advance. – Giulio Paoli May 09 '17 at 09:21
  • It's impossible to help you if you don't add more code in your snippet. Because of the problem you are having, it is necessary to see what you do inside the loop that accept connections and what you do with the sockets. The problem you are describing is related to something you do during the lifecycle of the listening sockets. – rodolk May 09 '17 at 15:29
  • I removed all the functions or blocks of code that deal with the sockets. Whenever you read ` do something here` etc., that means that the code in that piece is useless for debugging purposes (for example, it does something with variables, without influencing the connection etc). That's why I omitted some code. By the way, the problem has been solved as I wrote in my own answer. I don't know if you have or have not enough info to explain why that made it run. Thank you so much for your efforts, by the way. I appreciate all of it. – Giulio Paoli May 09 '17 at 15:44

2 Answers2

1

I don't see any code calculating a new maxfd value when preparing readfd for select(). When calling select(), maxfd must be the value of the highest descriptor + 1 of all the provided fd_sets. There is no code shown that calculates maxfd each time readfd is reset. You need to do something like this:

FD_ZERO(&readfd);
FD_SET(STDIN_FILENO, &readfd);
maxfd = STDIN_FILENO;
FD_SET(listenfd, &readfd);
maxfd = max(listenfd, maxfd);
FD_SET(servsock, &readfd);
maxfd = max(servsock, maxfd);

act = select(maxfd+1, &readfd, NULL, NULL, &elaps);

Also keep in mind that on some systems, select() modifies the timeval structure to report the amount of time remaining after select() exits, so you should reset elaps every time you call select().

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
  • Thank you for your answer. As it is stated in the comments in my code, maxfd is calculated at each iteration of the do-while loop. The timeval structure is also reset at the beginning of each iteration. (forgot to write it.) – Giulio Paoli May 09 '17 at 07:12
0

I solved my issue removing the line at the end of the code memset(&claddr,0,sizeof(claddr)); Even though it solved my problem, I don't really know why this wasn't making the code work. If someone could explain that, it would be great.