0

I have a server and a client talking. My server handles each client with a thread. The server code looks like this:

Server::Server(int port)throw (const char*) {
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd<0) {
        throw "socket failed";
    }
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(port);

    if ((::bind(fd, (struct sockaddr*) &server, sizeof(server))) < 0) {
        throw "bind failed";
    }

    if(listen(fd,3)<0) {
        throw "linsten failed";
    }
}

void Server::start(ClientHandler& ch)throw(const char*){
    t = new thread([&ch,this]() {
        while (!stopAccept) {
            cout<<"waiting for a client\n";
            socklen_t clientSize = sizeof(client);
            int aClient = ::accept(fd,(struct sockaddr *)&client, &clientSize);
            if (aClient<0) {
                throw "except failure";
            }
            cout<<"client connected\n";
            ch.handle(aClient);
            close(aClient);
            cout<<"client closed\n";
        }
        close(fd);
    });
}

void Server::stop(){
    stopAccept = true;
    t->join(); // do not delete this!
}

What happens is that after it finished dealing with 2 clients, I call the stop function. But it right away prints "waiting for a client\n", before stopping.

Then, it of course will never stop, because it won't get any other message.

How can I end this program after the second client? A tip from my professor was to "implement a timeout on accept (for ex with alarm)". I have looked online a lot but can't seem to find a way to do this.

Advice?

Iam Spano
  • 31
  • 6
  • 1
    1. Use select and non-block: https://stackoverflow.com/questions/3444729/using-accept-and-select-at-the-same-time 2. the professor's suggestion is: use the alarm(3) function to timeout, which will cause you to get an EINTR (you'll also need a SIGALRM handler) – Halt State Jan 04 '21 at 20:15
  • [Here's a decent `select`-based server](https://beej.us/guide/bgnet/html/#select). You just need to replace the last parameter with a pointer to a meaningful timeout. Note that Beej calls this old school for good reasons. It's simple, it's supported pretty much everywhere sockets are available, but just about every system offers a solution that better fits their system (overlapped IO and `epoll` being the most notable because they're the Windows and Linux solutions) – user4581301 Jan 04 '21 at 20:23
  • 2
    The reason for this appears to be a complete failure of proper inter-thread synchronization, unfortunately the shown code fails to meet the requirements for a [mre], as explained in the [help], so this cannot be stated with 100% confidence. Until you [edit] your question accordingly, it's unlikely anyone's going to bother giving a complete explanation of a problem, due to a possibility that the problem turning out to be something else entirely, and so it would turn out to be a waste of time. See [ask] questions for more information. – Sam Varshavchik Jan 04 '21 at 20:43
  • Unrelated: `throw "except failure";` surprises a lot of people because it doesn't throw what they expected. See [What type should I catch if I throw a string literal?](https://stackoverflow.com/questions/4831523/what-type-should-i-catch-if-i-throw-a-string-literal) for details. – user4581301 Jan 04 '21 at 20:57
  • I edited my code adding a timeout of 3 seconds like described in the link by @HaltState. Now the program works perfeclty. – Iam Spano Jan 04 '21 at 21:38
  • Don't forget to `delete t;` after you're done with it. – user4581301 Jan 04 '21 at 21:56
  • Closing the socket is the normal way to interrupt a pending accept – Alan Birtles Jan 04 '21 at 23:11

0 Answers0