1

Firstly I'm coding in c++ and running in Linux/CentOS 6.4

So after a really long time and reading a lot of different books on sockets, I finally have at least my client and my server partially working.

First I want to continuously accept messages from different clients, I have already setup the client, and it finally successfully compiled at least. Now I need to set up my server so that I can properly test.

What I'm doing is implementing the dining philosopher problem with sockets, with each client/philosopher representing a different process. I was going to go through this whole thing, where the server was going to keep track of everything, like the states of all the client. That was too difficult, I have now just created the client just to send their status to the server and the server prints it out.

I was thinking of putting a do/while loop to continuously accept messages, but not sure what I should use to stop the loop. Note that I will have a while loop set up in my client, which is signaled to stop after an elapsed amount of time. It should then close that particular client. I do have a signal in my serve, but I am not sure it works.

#include "helper.h"
  char buffer[4096];
void sigchld_handler(int signo)
{
  while (waitpid(-1, NULL, WNOHANG) > 0);
}
void client(int &newsock, int nread)
{
do
            {

                int nread = recv(newsock, buffer,sizeof(buffer), 0);
                     puts(buffer);


            }while(nread!=0);
} 


int main(int argc, char *argv[])
{
    struct sockaddr_in sAddr, cli_addr;
    socklen_t client_len;
    int listensock;
    int newsock;

    int result;
    int nread=1;
     pid_t childid; ;
    int status;

    if((listensock = socket(AF_INET, SOCK_STREAM, 0))<0)
    {
        perror("Problem in creating socket");
        exit(2);
    }


    sAddr.sin_family = AF_INET;
    sAddr.sin_port = htons(3333);
    sAddr.sin_addr.s_addr = htonl(INADDR_ANY);

  bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
    if (result < 0) {
        perror("exserver2");
        return 0;
    }

    result = listen(listensock, 5);
    if (result < 0) {
        perror("exserver2");
        return 0;
    }

    signal(SIGCHLD, sigchld_handler);

    while (1) {
    client_len = sizeof(cli_addr);
        newsock = accept(listensock,(struct sockaddr *)&cli_addr, &client_len);
        if ((childid = fork()) == 0) {
            printf("child process %i created.\n", getpid());
            close(listensock);
            client(newsock, nread);


            }
            if(status<0)
            {
            printf("%s\n" "Read error");
            exit(1);
            }

            close(newsock);

    }
}
user2644360
  • 71
  • 1
  • 2
  • 9
  • You need to exit your read loop if `recv()` returns zero, and you need to use the length it returns instead of passing the entire buffer to `puts()`. – user207421 Aug 06 '13 at 06:37
  • 1
    maybe you should take a look at select instead of forking for each client – Alexis Aug 06 '13 at 06:39
  • Well the project requires separate processes, and from what I've been reading from all the books, select doesn't really do that. – user2644360 Aug 06 '13 at 06:51
  • I'm not at all clear what the actual question is here. – user207421 Aug 06 '13 at 08:33
  • @EJP The question was will a do while loop suffice to accept multiple client info that is being sent to the server?The two last minute questions were, why is my server now refuse connection, when it was working previously. and does my server currently look capable of outputting the client messages concurrently? – user2644360 Aug 06 '13 at 09:29
  • @EJP Actually it's working again, I did make the changes you suggested, it is outputting states for the clients, but their out of order and not coming out at the same time like I want. How do I get that to happen? – user2644360 Aug 06 '13 at 09:41
  • There isn't such a thing as 'out of order' among different processes unless you're taking explicit steps to ensure ordering and they aren't working as expected. – user207421 Aug 06 '13 at 09:45
  • @EJP well I don't really care about the order, but it seems my server may be skipping some of the messages sent entirely. Also I got the program to run, but the server is still stuck in this infinite loop outputting states while the client has closed already. I did what you told me and put the `while(nread !=0)` but it seems to just continue – user2644360 Aug 06 '13 at 10:06
  • So I added a log, and the program is actually working properly now, it was just outputting so fast I couldn't see the beginning, but I'm still having the problem with the infinite loop – user2644360 Aug 06 '13 at 10:18
  • I didn't say anything about 'while (nread != 0).' That's your interpretation. Are you checking for errors? You keep changing the question ... – user207421 Aug 06 '13 at 10:24
  • Where's your loop? You need a select loop in every sockets programme, right! (Or kqueue/other equivalent...) – Nicholas Wilson Aug 06 '13 at 10:31
  • @EJP well my recv() is nread, so... Also the problem I'm still having is stopping the do while loop. My server program pretty much still looks identical to the one I posted, with the exception of the while part – user2644360 Aug 06 '13 at 10:33
  • 1
    @NicholasWilson Please read the question. He is forking a new process per accepted connection; in any case you most certainly do not 'need a select() loop in every sockets program'. – user207421 Aug 06 '13 at 10:45
  • @user2644360 This is getting worse and worse. You mentioned a while loop; now you're still asking about the original do/while loop. I don't see how you can expect anybody to answer this question as stated and developed in your comments. I suggest you edit your current code into the question, or start a new one. – user207421 Aug 06 '13 at 10:47
  • @EJP sorry for the confusion, but when I say while loop, I just mean the while part of the do/while. I did edit the code to look exactly how I have it. – user2644360 Aug 06 '13 at 10:52
  • You still aren't checking for errors, and you're still passing the entire buffer to puts() regardless of the length returned by read(). – user207421 Aug 06 '13 at 10:56
  • First of all, put '\0' in the `buffer[nread+1]`, so you can get your logs right, secondly check if `recv` does not return -1. And you should pass `sizeof(buffer)-1` to your recv so you can fit in '\0' on the end. – zoska Aug 07 '13 at 19:38
  • Oh, and you will get an infinite working server, because it will block on accept after all clients stop working and no other connection will be requested (accept is a blocking function). And start reading manuals on functions you are using. – zoska Aug 07 '13 at 19:41

2 Answers2

1

You need a multiplexing syscall like poll(2) (or the old, nearly obsolete, select(2)syscall). You may want to use some (or implement your own) event loop. See this & that answer. Read about the C10K problem.

Every server needs an event loop.

Read Advanced Linux Programming (or some Posix network programming book).

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

You may want to simply run your server program under tcpserver (see http://cr.yp.to/ucspi-tcp.html). This will spawn a new instance of your program each time a client connects to your program (on the port that you specify). This way, you can focus on the core logic of your program, and let tcpserver handle all of the heavy lifting as far as the socket programming, etc. tcpserver will pass input from the client to your program's stdin, and output from your programs stdout will be sent back to the client.

mti2935
  • 11,465
  • 3
  • 29
  • 33