user1690595
user1690595

Reputation:

c++ select only checks last client socket

i am writing a server for a chat client i am making the problem is the following Select only lifts its block if a net client connects and if the last connected client is writing. example: i have 4 clients connected the server will keep blocking until client no. 4 writes if client 1-3 writes it keeps blocking what am i doing wrong? for analysing here is my code might contain ugly and useless code but that's just analysing its behaviour

Server.c++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <boost/thread/thread.hpp>
#include <sys/time.h>
#include <sys/ioctl.h>

using namespace std;

void error(char *msg, int socket) {
    perror(msg);
    close(socket);
    exit(1);
}

int main(int argc, char** argv) {
    int sockfd, newsockfd, portno, n, highsock;
    socklen_t clilen;
    fd_set readfds;
    list<int> CliSocks;
    FD_ZERO(&readfds);
    /*
     * Sockfd, newsockfd contain values returned by the socket
     * portno stores the port number on which the server accepts connections
     * clilen stores the size of the address of the client
     * n contains the amount of character written of read
     */
    char buffer[256];
    /* buffer contains the characters read from the socket*/

    struct sockaddr_in serv_addr, cli_addr;
    /* 
     * sockaddr_in contains an internet address
     * serv_addr contains the servers address
     * cli addr contains the clients address
     */
    if (argc < 2) {
        fprintf(stderr, "ERROR no port provided");
        exit(1);
    }
    /*
     * error if no argument
     */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    highsock = sockfd;
    FD_SET(sockfd, &readfds);
    int opt = 1;
    ioctl(sockfd, FIONBIO, &opt);

    if (sockfd < 0) {
        error("ERROR opening socket", sockfd);
    }
    /*
     * socket() creates a new socket
     * argument 1 contains the address domain
     * argument 2 contains the socket type
     * argument 3 contains the protocol should be 0
     * socket() returns a reference for itself
     */
    bzero((char*) &serv_addr, sizeof (serv_addr));
    /* empty the serv_addr variable*/
    portno = atoi(argv[1]);
    /*converts the port argument from string  to int*/
    serv_addr.sin_family = AF_INET;
    /*set the code for the address family*/
    serv_addr.sin_port = htons(portno);
    /*htons converts the portno to network bytes and gives it to the server address*/
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    /*set the server ip to the ip of the running machine*/
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
        error("ERROR on binding", sockfd);
    /*
     * bind() binds a socket to an address, in this case the
     * addess of the current host
     */
    listen(sockfd, 5);

    /*the listen system call allows the process to listen on the socket for connections*/


    while (1) {
        int sockcount = select(highsock + 1, &readfds, NULL, NULL, NULL);

        clilen = sizeof (cli_addr);
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        /*
         * accept() lets the system wait until a client connects to the server
         */

        if (newsockfd > 0) {
            ioctl(newsockfd, FIONBIO, &opt);
            FD_SET(newsockfd, &readfds);
            highsock = newsockfd;
            CliSocks.push_back(newsockfd);
        }


        for (list<int>::iterator it = CliSocks.begin(); it != CliSocks.end(); it++) {
            bzero(buffer, 256);
            n = read(*it, buffer, 255);
            if(buffer[0] != 0){
            printf("Here is the message: %s", buffer);

            /*
             * bzero empties the buffer
             * read obviously reads data from the new socket descriptor
             */
            n = write(*it, "I got your message", 18);
            if (n < 0) error("ERROR writing to socket", sockfd);
                        }
        }
    }
    close(sockfd);
    return 0;
}

Upvotes: 1

Views: 296

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409136

The problem is that you must reset readfds every time in the loop before the call to select. This is because the call to select modifies its parameters.

while (1) {
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);
    highsock = sockfd;
    for (list<int>::iterator it = CliSocks.begin(); it != CliSocks.end(); it++) {
        FD_SET(*it, &readfds);
        highsock = *it > highsock ? *it : highsock;
    }
    int sockcount = select(highsock + 1, &readfds, NULL, NULL, NULL);

    ...
}

Upvotes: 2

Related Questions