0
votes

learning the socket programming in c use gdb tcpserv , select function always return 1 , i don`t kown why. not good at english, so i paste the code here. anyone help?

file: sockheader.h content :

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>


#define SERV_PORT 11211
#define SA  struct sockaddr
#define LISTENQ 5
#define MAXLINE 1024
typedef void Sigfun(int);

int Socket(int family, int type, int protocol);
int Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
int Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *chiaddr, socklen_t *addrlen);
int Close(int sockfd);
int Connect(int sockfd, const struct sockaddr *sa, socklen_t salen);
void Writen(int sockfd, char *writeline, int len);
int str_echo(int sockfd);
int str_echo2sum(int sockfd);
int str_cli(int sockfd);
void sig_chld(int signo);

file: sockheader.c content:

#include "sockheader.h"

int Socket(int family, int type, int protocol)
{
    int fd;
    if( (fd = socket(family, type, protocol)) < 0 )
    {
        perror("socket error!\n");
        exit(-1);
    }

    return fd;
}

int Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
    int bindfd;
    if( (bindfd = bind(sockfd, myaddr, addrlen)) < 0 )
    {
        perror("bind error");
        exit(-1);
    }

    return bindfd;
}


int Listen(int sockfd, int backlog)
{
    int res ;
    if( (res = listen(sockfd, backlog) ) < 0 )
    {
        perror("Listen error");
        exit(-1);
    }

    return res;
}


int Accept(int sockfd, struct sockaddr *chiaddr, socklen_t *addrlen)
{
    int res ;
    if( (res = accept(sockfd, chiaddr, addrlen)) < 0 )
    {
        perror("accept error");
        exit(-1);
    }

    return res;
}


int Close(int sockfd)
{
    close(sockfd);
}

int Connect(int sockfd, const struct sockaddr *sa, socklen_t salen)
{
    int res ;
    if ( (res = connect(sockfd, sa, salen)) < 0)
        perror("connect error");
    return res;
}


void Writen(int sockfd, char *writeline, int len)
{
    write(sockfd, writeline, len);
}

int str_echo(int sockfd)
{
    char readline[MAXLINE];
    char sendline[MAXLINE];
    int n;

    again:
    while( (n = read(sockfd, readline, MAXLINE)) > 0 )
    {   
        fputs("read str:\n", stdout);
        readline[n] = '\0';
        strcpy(sendline, "recive str:");
        strcat(sendline, readline);
        Writen(sockfd, sendline, strlen(sendline) + 1);
        if(fputs(readline, stdout) == EOF)
        {
            perror("fputs error");
        }
    }   

    fputs("out while\n", stdout);

    if (n < 0 )
        goto again;
}

int str_echo2sum(int sockfd)
{
    long arg1, arg2;
    char readline[MAXLINE];
    int n;

    again:
    while( (n = read(sockfd, readline, MAXLINE)) > 0 )
    {   
        if( sscanf(readline, "%ld%ld", &arg1, &arg2) == 2 )
        {
            snprintf(readline, sizeof(readline), "%ld\n", arg1 + arg2);
        }
        else
        {
            snprintf(readline, sizeof(readline), "input error\n");
        }

        n = strlen(readline);

        Writen(sockfd, readline, strlen(readline) + 1);
        if(fputs(readline, stdout) == EOF)
        {
            perror("fputs error");
        }
    }   

    fputs("out while\n", stdout);

    if (n < 0 )
        goto again;
}

int str_cli(int sockfd)
{
    char charline[MAXLINE], recvline[MAXLINE];

    while(fgets(charline, MAXLINE, stdin) != NULL)
    {
        fputs("write string\n", stdout);
        Writen(sockfd, charline, strlen(charline) + 1);

        if(read(sockfd, recvline, MAXLINE) == 0)
        {
            perror("str_cli:server terminated prematurely");
        }

        if(fputs(recvline, stdout) == EOF)
        {
            perror("fputs error");
        }
    }

    fputs("cli:out while\n", stdout);

}

int str_cli2(int sockfd)
{
    int maxfd1, stdineof;
    fd_set rset;
    char buf[MAXLINE];
    int n;

    stdineof = 0;
    FD_ZERO(&rset);
    for(;;)
    {
        if(stdineof == 0)
        {
            FD_SET(fileno(stdin), &rset);
        }

        FD_SET(sockfd, &rset);
        maxfd1 = fileno(stdin) > sockfd ? fileno(stdin) + 1 : sockfd + 1 ;
        select(maxfd1, &rset, NULL, NULL, NULL);
        if(FD_ISSET(sockfd, &rset))
        {
            if( ( n = read(sockfd, buf, MAXLINE) ) == 0)
            {
                if(stdineof == 1)
                {
                    return ;
                }
                else
                {
                    perror("str_cli2:server terminated ");
                    exit(-1);
                }
            }

            Writen(fileno(stdout), buf, n );


        }

        if( FD_ISSET(fileno(stdin), &rset) )
        {
            if( ( n = read(stdin, buf, MAXLINE) ) == 0)
            {
                stdineof = 1;
                shutdown(sockfd, SHUT_WR);
                FD_CLR(fileno(stdin), &rset);
                continue;
            }

            Writen(sockfd, buf, n);
        }
    }

}

void sig_chld(int signo)
{
    pid_t pid;
    int stat;
    while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
    {
        printf("child %d terminated\n", pid);
    }
    return; 
}

file:tcpcli05.c content:

#include "sockheader.h"

int main(int argc, char const *argv[])
{
    int sockfd, i;
    struct sockaddr_in cliaddr;

    for(i = 0; i < 5; i++)
    {
        sockfd = Socket(AF_INET, SOCK_STREAM, 0);

        bzero(&cliaddr, sizeof(cliaddr));
        cliaddr.sin_family      = AF_INET;
        cliaddr.sin_port        = htons(SERV_PORT);
        inet_pton(AF_INET, argv[1], &cliaddr.sin_addr.s_addr);

        Connect(sockfd, (SA *)&cliaddr, sizeof(cliaddr));

    }

    str_cli2(sockfd);

    return 0;
}

file:tcpserv05.c content:

#include "sockheader.h"

int main(int argc, char const *argv[])
{
    int i, maxi, maxfd, listenfd, sockfd, connfd;
    int nready, client[FD_SETSIZE];
    ssize_t n ;
    fd_set rset, allset;
    char buf[MAXLINE];
    struct sockaddr_in servaddr, chiladdr;
    socklen_t chlien;
    pid_t pid;

    sockfd              = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    // inet_pton(AF_INET, INADDR_ANY, &servaddr.sin_addr);
    Bind(sockfd, (SA *)&servaddr, sizeof(servaddr));

    Listen(sockfd, LISTENQ);
    // signal(SIGCHLD, sig_chld);

    maxfd = sockfd;
    maxi = -1;
    for(i = 0; i < FD_SETSIZE; i++)
    {
        client[i] = -1;
    }

    FD_ZERO(&allset);
    FD_SET(sockfd, &allset);

    for(;;)
    {
        rset = allset;
        printf("i walk here \n");
        nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
        printf("nready:%d\n", nready);

        if(FD_ISSET(sockfd, &rset))
        {
            chlien = sizeof(chiladdr);
            if(( connfd = Accept(sockfd, (SA *)&chiladdr, &chlien )) < 0)
            {
                perror("accept error");
            }

            printf("new client: %d\n", inet_ntoa(chiladdr.sin_addr));
            printf("new client port: %d\n", ntohs(chiladdr.sin_port));

            for(i = 0; i < FD_SETSIZE; i++)
            {
                if(client[i] < 0)
                {
                    client[i] = connfd;
                    break;
                }
            }

            if(i == FD_SETSIZE)
            {
                perror("too many clients");
            }

            printf("connfd: %d\n", connfd);
            FD_SET(connfd, &allset);

            if(connfd > maxfd)
            {
                maxfd = connfd;
            }

            if(i > maxi)
            {
                maxi = i;
            }

            if(--nready <= 0 )
            {
                continue;
            }
        }

        printf("i walk down here \n");
        for( i = 0 ; i <= maxi; i++)
        {
            if( (listenfd = client[i]) < 0)
            {
                continue;
            }

            if(FD_ISSET(listenfd, &rset))
            {
                if( (n = read(listenfd, buf, MAXLINE)) == 0 )
                {
                    Close(listenfd);
                    FD_CLR(listenfd, &allset);
                    client[i] = -1;
                }
                else
                {
                    Writen(listenfd, buf, n);
                }

                if( --nready < 0 )
                {
                    continue;
                }
            }
        }



    }

    return 0;
}

then

gcc -o tcpserv05 -g sockheader.c tcpserv05.c
gcc -o tcpcli05 -g sockheader.c tcpcli05.c

./tcpserv05

./tcpcli05 127.0.0.1

in the cli, i input some thing like "hi, test". the serv do not return anything . i gdb tcpserv05 then found the nready is always 1 . so --nready <= 0 is true, continue. program did not go to below.

i need some help, thank you first.

#

I find the problem.

I wrote the wrong code :

read(stdin, buf, MAXLINE)

stdin is FILE * , fread、fwrite、fclose will use stdin.

ssize_t read(int fd, void *buf, size_t count);

so i use fileno(stdin) instead, program worked.

2
My tip: Go read beej.us/guide/bgnet/output/html/singlepage/bgnet.html and structure your code better, it's a pain to read and follow, also prone to errors.Jite
@weizhao, instead of doing rset = allset; and then using rset in select(), try using allset directly in select() and see if that works?bytefire
i just code the same as a book <unix network programming> . in the book, they gives a demo tcpservselect01.c and strcliselect02.c . github.com/romen/unp/blob/master/unpv13e/tcpcliserv/… github.com/snaewe/books-code/blob/master/unpv13e/oob/…weizhao
select returns the number of descriptor that were ready. If you only have one client can only return 1. Why do you expect another return value?kmkaplan
tcpcli05.c for(i = 0; i < 5; i++) { Connect(sockfd, (SA *)&cliaddr, sizeof(cliaddr)); } , i think it will return 5. what i think is wrong?weizhao

2 Answers

1
votes

select returns 1, because that is the number of file descriptors that have events. If you had a timeout, it would return 0, if more file descriptors had events, it would return a higher number.

0
votes

You might want to use poll(2) instead of the older select(2). Read about the C10K problem.

Since select may modify its fd_set bitmasks, you should set them inside the loop (often, fd_set is just an array, so assigning rset = allset; don't do what you want).

Don't forget to call fflush(3) at appropriate places (e.g. fflush(NULL) before any select or poll)

Consider also using strace(1) for debugging.

Always test every syscalls(2) for failure (using perror)

See comments for this related question.

Always compile with gcc -Wall -Wextra -g and improve your source code till you get no warnings at all. BTW, bzero(3) is explicitly deprecated (i.e. obsolete) and you should not use it.