Search code examples
csocketsselect-function

c socket prog - select() problems


I'm new to network programming. I have to write a simple client/server program in C. The server will listen for a connection and the client will connect to the server, send a message, and receive an echo back from the client. We have to update this using select() to handle connections to multiple clients at the same time from the server process. I tried to implement select() on the client side like instructed,but I think I'm having an infinite loop on the client side in if(FD_ISSET(clientSockfd, &readfds)) part.

//client1.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <resolv.h>
#include <arpa/inet.h>


const int BUF_SIZE = 512;

int main(int argc, char *argv[]) {

    char buf[BUF_SIZE], buf2[BUF_SIZE];
    char *msg;
    struct sockaddr_in serverInfo;
    int clientSockfd, errorCheck, readVal, numfd;
    struct hostent *hostName;
    fd_set readfds;

    //make sure user entered correct arguments when starting client
    if(argc != 3)
    {
        printf("error: must enter 'programName portNumber hostname'\n");
        exit(errno);
    }

    //create socket and error check socket() call
    clientSockfd=socket(AF_INET, SOCK_STREAM, 0);
    if (clientSockfd == -1)
    {
        perror("error creating socket");
        exit(errno);
    }

    //assign sockaddr_in info for RemoteAddr
    bzero(&serverInfo, sizeof(serverInfo));
    serverInfo.sin_family=AF_INET;

    hostName=gethostbyname(argv[2]);
    if(hostName == NULL)
    {
        herror("Error when calling gethostbyname()");
        exit(errno);
    }

    memcpy((unsigned char *) &serverInfo.sin_addr, (unsigned char *)hostName->h_addr, hostName->h_length); //copy IP address to be used
    serverInfo.sin_port=htons(atoi(argv[1]));       //port number to be used, given in command line, must be converted to network byte order

    //connect to server side
    if(connect(clientSockfd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) == -1)
    {
        perror("error when connecting to server");
        exit(errno);
    }

    while(1)
    {
        FD_ZERO(&readfds);  //zero out set
        FD_SET(fileno(stdin), &readfds);
        FD_SET(clientSockfd, &readfds);

        int maxfd = fileno(stdin);
        if(maxfd < clientSockfd)  maxfd = clientSockfd;
            numfd = select(maxfd, &readfds, 0, 0, 0);   //call select()

        if(numfd > 0)
        {
            if(FD_ISSET(clientSockfd, &readfds))
            {
                //make sure buf is empty so it doesnt print extra chars
                bzero(buf2, BUF_SIZE);
                read(clientSockfd, buf2, BUF_SIZE);

            }
            if(FD_ISSET(fileno(stdin), &readfds))
            {
                bzero(buf, BUF_SIZE);
                fgets(buf, BUF_SIZE-1, stdin);
                printf("echo from server: %s\n", buf);
                errorCheck = write(clientSockfd, buf, strlen(buf)+1);
                if(errorCheck == -1)
                {
                    perror("error writing");
                }       
            }
        }
        else if(numfd == 0)
        {
            perror("Error using select()\n");
            exit(0);
        }
        else
            printf("no data\n");
    }
    //close connection to server
    errorCheck = close(clientSockfd);
    if(errorCheck == -1)
    {
        perror("Error closing connection.");
        exit(errno);
    }
    return 0;
}

here is the server..

//server.c

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


const int ASSIGNED_PORT = 17000;
const int BUF_SIZE = 512;

int main() {

    int serverfd, clientfd;
    struct sockaddr_in serverSock;      //NOTE: a pointer to sockaddr_in can be cast to a pointer to 
    //      a struct sockaddr - useful for connect()

    char buf[BUF_SIZE];
    int errorCheck, msgLength;

    //create socket with error checking (-1 ret on error)
    serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if(serverfd < 0 )
    {
        perror("socket failed.");
        exit(errno);
    }

    //assign sockaddr_in info for server
    bzero(&serverSock, sizeof(serverSock));     //set to all 0's
    serverSock.sin_family = AF_INET;                
    serverSock.sin_addr.s_addr = htonl(INADDR_ANY);
    serverSock.sin_port = htons(ASSIGNED_PORT);


    //bind a name to the socket with error checking (0 ret on success)
    errorCheck = bind(serverfd, (struct sockaddr*)&serverSock, sizeof(serverSock));
    if(errorCheck < 0 )
    {
        perror("bind failed.");
        exit(errno);
    }

    //listen for connections with error checking (0 ret on success)
    errorCheck = listen(serverfd, 10);
    if(errorCheck < 0 )
    {
        perror("listen failed.");
        exit(errno);
    }

    printf("Listening for connections.  Enter CNTRL-c to kill server.\n");

    //create infinite loop to accept, read, write, and close connections with error hecking 
    while(1)
    {

        //accept the connection from the client 
        clientfd = accept(serverfd, 0, 0);
        if(clientfd ==  -1)
        {
            perror("error accepting connection.");
            exit(errno);
        }

        //read data from the client
        bzero(buf, BUF_SIZE);
        msgLength = read(clientfd, buf, BUF_SIZE-1);
        if(msgLength == -1)
        {
            perror("error reading from client");
            close(clientfd);
            close(serverfd);
            exit(errno);
        }

        if(buf[0] '\0')
        {
            printf("connection closing");
            exit(0);
        }
        //print what the client sent
        printf("Message from client: %s\n", buf);

        //echo back what the client sent
        errorCheck = write(clientfd, buf, strlen(buf)+1);   

        if(errorCheck == -1 )
        {
            perror("error writing to client");
            exit(errno);
        }

        //close the connection
        errorCheck = close(clientfd);
        if(errorCheck == -1)
        {
            perror("error closing connection");
            exit(errno);
        }       
    }

    errorCheck = close(serverfd);
    if(errorCheck==-1)
    {
        perror("error closing server, exiting program now");
        sleep(6);
        exit(errno);
    }
    return 0;
}

Solution

  • I think the problem (or at least, a problem) in your client-side code is that you are passing the magic number 32 to select(). That's incorrect. What you should be passing is the maximum of all of the socket numbers, plus one. For example, something like this:

    int maxfd = fileno(stdin);
    if (maxfd < clientSockFD) maxfd = clientSockFD;
    // further maximizations for other sockets would go here, if you had any other sockets...
    numfd = select(maxfd+1, &readfds, 0, 0, 0);