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れます。ECONNRESETfork を使用するために、(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);
}

また、メイン関数はループに入って、新しい接続を待機する必要があります。

注意: このコードはテストしていないため、動作しない可能性があります。しかし、man ページを読めfork(3)recv(3)動作するはずです。

于 2013-01-25T10:31:25.073 に答える
0

Apache などの既製品を使用して、必要に応じてカスタマイズした方がよいのではないでしょうか。

于 2013-01-25T11:14:31.273 に答える