0

我正在尝试使用 C 实现多客户端服务器。我为服务器编写了代码,客户端是一个软件,它会不断地向服务器发送一些数据包。服务器将读取数据包并进行处理。我正在尝试一次与服务器建立 5 个连接。但是我编写的服务器代码存在一些问题,因此我无法将 5 个客户端连接到服务器。确切的问题是,当客户端尝试与服务器连接时,它会获得连接,但是当我关闭客户端软件并尝试重新启动时,它没有获得连接。以下是我的服务器端代码。任何人都可以帮助我解决这个问题。

#include <ctype.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>


int sock;                       /* The socket file descriptor for our "listening"socket */
int connectlist[15];            /* Array of connected sockets so we know who we are talking to */
fd_set socks;                   /* Socket file descriptors we want to wake up for, using select() */
int highsock = 1;               /* Highest #'d file descriptor, needed for select() */
struct sockaddr_in client_address[5];
unsigned int clientLength = sizeof(client_address) ;
#define PORTNO      (int)49153
int port;                       /* The port number after conversion from ascport */
struct sockaddr_in server_address; /* bind info structure */
int reuse_addr = 1;  
struct timeval timeout;         /* Timeout for select */
int readsocks;                  /* Number of sockets ready for reading */
int err = 0 ;

#define BACKLOG         (int)10

void deal_with_data(int listnum /* Current item in connectlist for for loops */)
{
    //Here I am trying to read packet from client s/w and process it
}

void setnonblocking(int sock)
{
    int opts;
    opts = fcntl(sock,F_GETFL);
    if (opts < 0) 
    {
        printf("fcntl(F_GETFL)_error");
        exit(0);
    }
    opts = (opts | O_NONBLOCK);
    if (fcntl(sock,F_SETFL,opts) < 0) 
    {
        printf("fcntl(F_SETFL)_error");
        exit(0);
    }
    return;
}

void build_select_list() 
{
    int listnum;         /* Current item in connectlist for for loops */
    FD_ZERO(&socks);
    FD_SET(sock,&socks);
    for (listnum = 0; listnum < 5; listnum++) 
    {
        if (connectlist[listnum] != 0) 
        {
            FD_SET(connectlist[listnum],&socks);
            if (connectlist[listnum] > highsock)
                highsock = connectlist[listnum];
        }
    }
}

void handle_new_connection() {
    int listnum;         /* Current item in connectlist for for loops */
    int connection; /* Socket file descriptor for incoming connections */
    connection = accept(sock, (struct sockaddr *)&client_address[highsock], &clientLength);
    if (connection < 0) 
    {
        printf("accept_error");
        exit(0);
    }
    setnonblocking(connection);
    for (listnum = 0; (listnum < 5) && (connection != -1); listnum ++)
        if (connectlist[listnum] == 0) 
        {
            printf("\nConnection accepted:   FD=%d; Slot=%d\n",
                connection,listnum);
            printf("Connection accepted from %s\n",inet_ntoa(client_address[highsock].sin_addr));
            connectlist[listnum] = connection;
            connection = -1;

        }
    if (connection != -1) 
    {
        printf("\nNo room left for new client.\n");
        write(connection,"Sorry, this server is too busy.Try again later!\r\n",80);
        close(connection);
    }
    printf("return from handle_new_connection\n");
}

void read_socks(void)
{
    int listnum;         /* Current item in connectlist for for loops */
    if (FD_ISSET(sock,&socks))
        handle_new_connection();
    for (listnum = 0; listnum < 5; listnum++) 
    {
        if (FD_ISSET(connectlist[listnum],&socks))
        {
            //printf("read_socks2\n");
            deal_with_data(listnum);
        }
    }
}

int main (/*int argc, char *argv[]*/)
{
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0) 
    {
        printf("socket_error");
        exit(EXIT_FAILURE);
    }
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));
    setnonblocking(sock);

    memset((char *) &server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(port);

    if (bind(sock, (struct sockaddr *) &server_address,sizeof(server_address)) < 0 ) 
    {
        printf("bind_error");
        close(sock);
        exit(EXIT_FAILURE);
    }

    if((err = listen(sock,10)) == -1)
    {
        printf("listen_error");
    }

    highsock = sock;
    memset((char *) &connectlist, 0, sizeof(connectlist));

    while (1) 
    { /* Main server loop - forever */
        build_select_list();
        timeout.tv_sec = 2;
        timeout.tv_usec = 0;

        readsocks = select(highsock+2, &socks, (fd_set *) 0,(fd_set *) 0, &timeout);
        if (readsocks < 0) 
        {
            printf("select_error");
            exit(EXIT_FAILURE);
        }
        if (readsocks == 0) 
        {
            printf(".");
            fflush(stdout);
        } 
        else
        {   
            read_socks();
        }
    } /* while(1) */
} /* main */
4

2 回答 2

2

您的问题是,当客户端关闭套接字时,您的主循环不会退出。这意味着它不能接受新的连接。我会用来fork()处理来自套接字的数据,以及main()接受连接和fork()进程的函数。此外,您需要有一些代码会杀死fork()ed(即检查客户端是否在fork()ed 进程中断开连接)进程(因为它不会自行关闭并且会占用内存)。

编辑:

recv()好的,我在你的程序中找不到调用。根据recv(3)手册页return 0如果客户端“优雅地”断开连接,return -1并且如果客户端强制断开连接,它将设置errno为。ECONNRESET为了使用fork,我会(在main()函数中)将你的while循环包装在这个:

int childpid = fork();
if(childpid == -1) {
       printf("Could not fork process");
       exit(EXIT_FAILURE);
}
else if(childpid == 0) { /* in child process*/
       while(/* check if the socket has been closed */) {
               /* While loop stuff */
       }
       /* free up memory */
       exit(EXIT_SUCCESS);
}

你的主要功能应该在一个循环中,等待新的连接。

注意我没有测试过任何这段代码,所以它可能不起作用。但是,如果您阅读手册页fork(3)recv(3)它应该可以工作。

于 2013-01-25T10:31:25.073 回答
0

使用像 Apache 这样现成的东西并根据需要对其进行自定义不是更好吗?

于 2013-01-25T11:14:31.273 回答