0

我的任务是编写一个接受多个客户端的服务器程序。我正在用 C 语言编写并尝试使用 select() 语句来完成此操作。我能够编译,但每当我远程登录时,我都会收到“非套接字错误的套接字操作”。我试过研究这个错误,但找不到任何有用的东西。任何援助将不胜感激。

我的服务器的输出是:

$ ./assign2 33333
Waiting for connection...
fd is 0
EchoServ recv error: Socket operation on non-socket
fd is 1
EchoServ recv error: Socket operation on non-socket
EchoServ recv error: Socket operation on non-socket

telnet 的输出是:

$ telnet localhost 33333
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Welcome to EchoServ chat.

我的服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define PORT    50000

main( int argc, char *argv[] )
{
    char                buf[ BUFSIZ ],  /* buffer for incoming data */
                        *endptr,  /*  for strtol()  */
                        *message = "Welcome to EchoServ chat. \r\n"; /* welcome message */
    int                 masterSocket, /* main listening socket for server */
                        newSocket,  /* new sockets for connecting clients */
                        opt = 1,  /* for port reuse code */
                        nBytes,  /* # of incoming bytes */
                        addrlen;
    int                 i,j;  /* temp vars */
    short int           port;  /* port number */
    fd_set              master;  /* master file descriptor list */
    fd_set              temp_fds;  /* temp file descriptor list for select() */
    int                 fdmax;  /* maximum file descriptor number */
    struct sockaddr_in  sin;

    /*  Get port number from the command line, or
        set to default port if no arguments were supplied  */
    if ( argc == 2 ) {
        port = strtol(argv[1], &endptr, 0);
        if ( *endptr ) {
            fprintf(stderr, "EchoServ: Invalid port number.\n");
            exit(EXIT_FAILURE);
        }
    }
    else {
        port = PORT;
    }

    FD_ZERO(&master);    /* clear the master and temp sets */
    FD_ZERO(&temp_fds);

    /* Get an internet domain socket */
    if ( ( masterSocket = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
        perror( "EchoServ socket error" );
        exit( 1 );
    }

    /* Complete the socket structure */
    memset( &sin, 0, sizeof(sin) );
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);

    /* Bind the socket to the port number */
    if ( bind( masterSocket, ( struct sockaddr *) &sin, sizeof( sin ) ) == -1) {
        perror( "EchoServ bind failed" );
        exit( 1 );
    }

    /* Allow port reuse */
    if ( setsockopt( masterSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) ) == -1 ) { 
        perror( "EchoServ setsockopt error" );
        exit(1);
    } 

    /* Listen for clients that want to connect.         */
    if ( listen( masterSocket, 5 ) == -1 ) {
        perror( "EchoServ listen error" );
        exit( 1 );
    }

    /* add masterSocket to the master set */
    FD_SET(masterSocket, &master);

    /* track largest file descriptor, starting with masterSocket */
    fdmax = masterSocket;


    /* Wait for a client connection, then accept it. */

    puts ( "Waiting for connection..." );
    while(1){
        temp_fds = master;  /* copy master set to temp set */
        //addrlen = sizeof(sin); 
        /* wait for activity on a socket */
        if (select(fdmax+1, &temp_fds, NULL, NULL, NULL) == -1) {
            perror("EchoServ select error");
            exit(1);
        }

        for ( i = 0; i <= fdmax; i++ ){
            printf("fd is %d\n", i);  /*debug*/
            if ( FD_ISSET( i, &temp_fds ) ){  /* true if file descriptor is in set */

                /* accept new connection */               
                if ( i == masterSocket ){
                    addrlen = sizeof( sin );  
                    if ( (newSocket = accept( masterSocket, ( struct sockaddr *) &sin, &addrlen )) == -1 )
                        perror("EchoServ:  accept error");
                    else {
                        printf("New connection accepted\n"); /*debug*/
                        FD_SET( newSocket, &master ); /* add new connection to master set */
                        if ( newSocket > fdmax )  /* update max descriptor */
                            fdmax = newSocket;
                        //print details of new connection
                        printf("New connection on %s:%d, socket fd is %d \n", 
                        inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), newSocket );

                        //send new connection greeting message
                        if( send( newSocket, message, strlen( message ), 0) == -1 )
                        {
                             perror("EchoServ welcome message error");
                        }
                        puts("Welcome message sent successfully");
                    }
                }
            }

            /* handle incoming data */
            else{
                if ( ( nBytes = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ){ /* error or closed connection */
                    if ( nBytes == 0 )  /* connection closed */
                        printf( "EchoServ: socket %d closed by client\n", i );
                    else /* recv error */
                        perror("EchoServ recv error");
                    close( i );  /* close socket */
                    FD_CLR( i, &master );  /* remove from master set */
                }
                else { /* got some data */ 
                    for( j = 0; j <= fdmax; j++ ){
                        if ( FD_ISSET( j, &master ) ){  /* send data to all sockets */
                            if( j != i && j != masterSocket ){  /* except self and masterSocket */
                                if ( send( j, buf, nBytes, 0) == -1)
                                    perror("EchoServ send error");
                            }  
                        }
                    }
                }
            }
        }
    }

    return( 0 );
}

感谢您的帮助。

4

1 回答 1

0

因此,您在 else 分支if (FD_ISSET(i, &temp_fds))上进行测试并尝试在. 所以基本上你只是想接收如果无效或会阻塞。recvii

这当然源于对块和大括号的无限使用。您可能意味着 else 与if (i == masterSocket).

于 2012-04-09T20:47:38.210 回答