Jules
Jules

Reputation: 423

How can I send send() and recv() on the same socket in a loop?

I am trying to create an IRC client for Freenode

My code is as such:

 while ((numbytes = recv(sockfd, buf, BUFFSIZE -1, 0)) != -1) {

        buf[numbytes] = '\0';
        printf("client: %s\n", buf);

        if (strstr(buf, "Nickname is already in use"))
            exit(EXIT_FAILURE);

        if (strstr(buf, "PING")) {
            num_bytes_sent = send(sockfd, "PONG", 5, 0);
            printf("%d PONG\n", num_bytes_sent);
        }        
}

I want to be able to use send() for user input using scanf(), but I cannot use scanf() inside the loop because it stops the socket from receiving data until scanf() receives input. Is there any way the loop can continue to receive data without stopping to wait for user input?

Upvotes: 0

Views: 854

Answers (1)

Saucy Goat
Saucy Goat

Reputation: 1675

What you're looking for is the select system call. Here is an example of its use (using write and read instead of send and recv though):

fd_set fds_receive;    // set of file descriptors
char buffer[BUFSIZE];

FD_ZERO(&fds_receive); // initialize the set

while (1) {

        FD_SET(socket_fd, fds_receive);  // monitor the socket
        FD_SET(STDIN_FD, fds_receive);   // monitor stdin

        /* the select system call will return when one of the file
        descriptors that it is monitoring is ready for an I/O operation */
        if (select(FD_SETSIZE, &fds_receive, NULL, NULL, NULL) < 0) {
            perror("select");
            exit(-1);
        }

        // if new data arrives from stdin
        if (FD_ISSET(STDIN_FD, &fds_receive)) {
            num_bytes = read(STDIN_FD, buffer, sizeof(buffer));

            if (num_bytes < 0) {          // error in the "read" system call
                perror("read");
                exit(-1);
            } else if (num_bytes == 0) {  // "Ctrl+D" pressed, stdin receives 0 bytes
                if (close(socket_fd) < 0) {
                    perror("close");
                    exit(-1);
                }

                exit(0);
            }

            // send data received in stdin to socket
            buffer[num_bytes] = '\0';
            if (write(socket_fd, buffer, strlen(buffer)+1) < 0) {
                perror("write");
                exit(-1);
            }

        } 

        // if new data arrives from the socket
        if (FD_ISSET(socket_fd, &fds_receive)) {
            num_bytes = read(socket_fd, buffer, sizeof(buffer));

            if (num_bytes < 0) {         // error in the "write" system call
                perror("read");
                exit(-1);
            } else if (num_bytes == 0) { // connection terminated, no problem
                close(socket_fd);
                exit(0);
            }

            // do stuff with data that arrived from the socket
        }
    }

The select system call allows you to monitor multiple file descriptors. In this case, if you want to monitor both stdin and a socket, you put them on a set of file descriptors. The comments in the code should be helpful in understanding how it works. Cheers!

Upvotes: 1

Related Questions