Unix网络编程select函数总是返回1(已解决)

问题描述 投票:0回答:2

学习C语言的socket编程。 使用gdb tcpserv,select函数总是返回1;我不知道为什么。 我把代码粘贴到这里。有人可以帮忙吗?

文件:sockheader.h

#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);

文件:sockheader.c

#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; 
}

文件:tcpcli05.c

#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;
}

文件:tcpserv05.c

#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;
}

然后

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

./tcpserv05

./tcpcli05 127.0.0.1

在 cli 中,我输入了诸如“hi, test”之类的内容。服务器不返回任何内容。 我 gdb tcpserv05 然后发现

nready
始终为 1。所以
--nready <= 0
为 true,继续。 程序没有转到下面。

怎么了?

############# 我发现问题了。

我写错了代码:

read(stdin, buf, MAXLINE)

stdin 是 FILE * ,fread、fwrite、fclose 将使用 stdin。

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

所以我使用

fileno(stdin)
来代替,程序就成功了。

c linux sockets posix-select
2个回答
1
投票

select
返回 1,因为这是具有事件的文件描述符的数量。如果超时,它将返回 0,如果更多文件描述符有事件,它将返回更高的数字。


0
投票

您可能想使用 poll(2) 而不是旧的 select(2)。了解C10K 问题

由于

select
可能会修改其
fd_set
位掩码,因此您应该将它们设置为 inside 循环(通常,
fd_set
只是一个数组,因此分配
rset = allset;
不会执行您想要的操作)。

不要忘记在适当的地方调用 fflush(3)(例如,在任何

fflush(NULL)
select
之前
poll

还可以考虑使用 strace(1) 进行调试。

始终测试 every syscalls(2) 是否失败(使用

perror

查看评论此相关问题

始终使用

gcc -Wall -Wextra -g
进行编译并改进源代码,直到完全没有警告为止。顺便说一句,bzero(3) 明确已弃用(即已过时),您不应该使用它。

© www.soinside.com 2019 - 2024. All rights reserved.