使用Select for Multiple Socket Connections C

时间:2016-03-30 23:49:59

标签: c sockets select file-descriptor

我正在尝试使用套接字为聊天服务器构建服务器和客户端。我知道我应该使用select()从多个套接字获取输入,但我不知道如何做,仍然正确地读取它们。正如我的代码所在,它从一个客户端读取完全正常,但当两个客户端打开时,它会忽略第二个客户端执行的所有操作,直到第一个客户端关闭。

我想知道如何正确实现select以确保我可以从多个套接字中获取输入。提前谢谢。

#include "../../include/my.h"

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

void interrupt();

void interrupt()
{
    my_str("Server exiting.\n");
    exit(0);
}

int str_to_num(char* str)      
{
        int i = 0;
        int numDigits = 0;
        int ret = 0;

        while (str[numDigits] != '\0')
        {
                numDigits++;
        }

        while (i < numDigits)
        {
                int digit = str[i];

                if (digit < 48 && digit > 57)
                        return -1;

                digit -= 48;

                ret += digit * my_pow(10, numDigits - i - 1);
                i++;
        }

        return ret;
}

char* add_null_term(char* str)
{
    int i = 0;

    while (str[i] != '\0')
        i++;

    str[i] = '\0';

    return str;
}
int main(int argc, char **argv)
{
    int sockfd, newsockfd, portnum;
    int len;
    char buffer[256];
    /*char *username = (char*)malloc(256*sizeof(char));*/
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    /*check args*/
    if (argc < 2)
    {
        my_str("Usage: ./server <port_number>\n");
        exit(0);
    }

    portnum = str_to_num(argv[1]);

    if (portnum < 1024)
    {
        perror("Ports below 1024 are reserved for root access.\n");
        exit(0);
    }

    if (portnum < 1 || portnum > 65535)
    {
        my_str("Port must be between 1 and 65535\n");
        exit(0);
    }

    signal(SIGINT, interrupt);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero((char*)&serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_port = htons(portnum);

    serv_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
    {
        perror("bind");
        exit(0);
    }

    listen(sockfd, 5);

    clilen = sizeof(cli_addr);

    while(1)
    {
        if ((newsockfd=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen)) < 0)
        {
            perror("accept");
            exit(0);
        }

        usleep(2000);

        my_str("Server received: ");

        while ((len = read(newsockfd, &buffer, 256)) > 0)
        {
            buffer[my_strlen(buffer)] = '\0';

            if (my_strcmp(buffer, "/") == 0)
            {
                my_str("Error: command ");
                my_str(buffer);
                my_str("not found.\n");
                bzero((char*)&buffer, sizeof(buffer));
            }

            /*if (count == 0)
            {
                my_strcpy(username, buffer);
                my_str("setting nickname to: ");
                my_str(username);
                bzero((char*)&buffer, sizeof(buffer));
                my_str(buffer);
                count++;
                my_str("\n");
            }*/

            /*else if (my_strncmp(buffer, "/me", 3) == 0)
            {
                my_str(username);
                my_str(" ");
                my_str(&buffer[4]);
                bzero((char*)&buffer, sizeof(buffer));
                my_str("\n");
            }

            else if (my_strncmp(buffer, "/nick", 5) == 0)
            {
                my_str("Changing nickname of ");
                my_str(username);
                my_strcpy(username, &buffer[6]);
                my_str(" to ");
                my_str(username);
                bzero((char*)&buffer, sizeof(buffer));
                my_str("\n");
            }*/

            /*else
            {*/
                /*my_str(username);
                my_str(": ");*/
                my_str(buffer);
                bzero((char*)&buffer, sizeof(buffer));
                my_str(buffer);
                my_str("\n");
            /*}*/
        }

        my_str("\nServer: Message end. Waiting for next connection.\n");
    }

    return 0;
}

1 个答案:

答案 0 :(得分:0)

如果您的问题是如何在服务器中使用select()... 这是一个技巧的顶部片段 让你开始...记住所有错误检查不是 目前,并没有优化以循环功能 基础...

listen(sockfd, SOMAXCONN)

fd_set my_set;
fd_set wk_set;

FD_ZERO(&my_set);         /* initialize  fd_set */
FD_SET(sock_fd, &my_set)  /* put listener into fd_set */
max_fd = sockfd;

while( TRUE )
{
    memcpy(&wk_set, &my_set, sizeof(my_set));

    rc = select(max_fd + 1, &wk_set, NULL, NULL, NULL )
    if ( rc == -1 )
    {
        if ( errno == EINTR )
            continue;
        printf("select failed: errno = %d\n", errno);
        exit(1);
    }
    for(i = 0; i < max_fd; i++) /* check everything in wk_set */
    {
        if ( FD_ISSET(i, &wk_set)
        {
            if ( i == sockfd )  /* is it the listener socket?? */
            {
                wk_sock=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
                if ( wk_sock == -1 )
                {
                    printf("accept failed: errno=%d\n", errno);
                    exit(1);
                }
                FD_SET(wk_sock, &my_set);  /* put into fd_set */
                if ( wk_sock > max_sock )
                    max_sock = wk_sock;
            }else{
                /* ready to read from this socket */
                recv_len = recv(i, .... )
                if ( recv_len == 0 ) /* client disconnected */
                {
                    close(i);
                    FD_CLR(i, &my_set);
                    if (i == max_fd )
                    {
                        for(x=0;x<max_fd;x++)  /* find new max_fd */
                        {
                            if ( FD_ISSET(x, &my_set )
                                max_fd = x;
                        }
                    }
                } else { 
                handle message from client
                }
            }
        }
    }
}