c socket prog - select()问题

时间:2011-09-12 19:48:59

标签: c sockets select-function

我是网络编程的新手。我必须在C中编写一个简单的客户端/服务器程序。服务器将侦听连接,客户端将连接到服务器,发送消息,并从客户端接收回显。我们必须使用select()来更新它,以便从服务器进程同时处理到多个客户端的连接。我尝试在客户端实现select(),就像指示一样,但我认为我在if(FD_ISSET(clientSockfd, &readfds))部分的客户端有一个无限循环。

//client1.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <resolv.h>
#include <arpa/inet.h>


const int BUF_SIZE = 512;

int main(int argc, char *argv[]) {

    char buf[BUF_SIZE], buf2[BUF_SIZE];
    char *msg;
    struct sockaddr_in serverInfo;
    int clientSockfd, errorCheck, readVal, numfd;
    struct hostent *hostName;
    fd_set readfds;

    //make sure user entered correct arguments when starting client
    if(argc != 3)
    {
        printf("error: must enter 'programName portNumber hostname'\n");
        exit(errno);
    }

    //create socket and error check socket() call
    clientSockfd=socket(AF_INET, SOCK_STREAM, 0);
    if (clientSockfd == -1)
    {
        perror("error creating socket");
        exit(errno);
    }

    //assign sockaddr_in info for RemoteAddr
    bzero(&serverInfo, sizeof(serverInfo));
    serverInfo.sin_family=AF_INET;

    hostName=gethostbyname(argv[2]);
    if(hostName == NULL)
    {
        herror("Error when calling gethostbyname()");
        exit(errno);
    }

    memcpy((unsigned char *) &serverInfo.sin_addr, (unsigned char *)hostName->h_addr, hostName->h_length); //copy IP address to be used
    serverInfo.sin_port=htons(atoi(argv[1]));       //port number to be used, given in command line, must be converted to network byte order

    //connect to server side
    if(connect(clientSockfd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) == -1)
    {
        perror("error when connecting to server");
        exit(errno);
    }

    while(1)
    {
        FD_ZERO(&readfds);  //zero out set
        FD_SET(fileno(stdin), &readfds);
        FD_SET(clientSockfd, &readfds);

        int maxfd = fileno(stdin);
        if(maxfd < clientSockfd)  maxfd = clientSockfd;
            numfd = select(maxfd, &readfds, 0, 0, 0);   //call select()

        if(numfd > 0)
        {
            if(FD_ISSET(clientSockfd, &readfds))
            {
                //make sure buf is empty so it doesnt print extra chars
                bzero(buf2, BUF_SIZE);
                read(clientSockfd, buf2, BUF_SIZE);

            }
            if(FD_ISSET(fileno(stdin), &readfds))
            {
                bzero(buf, BUF_SIZE);
                fgets(buf, BUF_SIZE-1, stdin);
                printf("echo from server: %s\n", buf);
                errorCheck = write(clientSockfd, buf, strlen(buf)+1);
                if(errorCheck == -1)
                {
                    perror("error writing");
                }       
            }
        }
        else if(numfd == 0)
        {
            perror("Error using select()\n");
            exit(0);
        }
        else
            printf("no data\n");
    }
    //close connection to server
    errorCheck = close(clientSockfd);
    if(errorCheck == -1)
    {
        perror("Error closing connection.");
        exit(errno);
    }
    return 0;
}

这是服务器..

//server.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>


const int ASSIGNED_PORT = 17000;
const int BUF_SIZE = 512;

int main() {

    int serverfd, clientfd;
    struct sockaddr_in serverSock;      //NOTE: a pointer to sockaddr_in can be cast to a pointer to 
    //      a struct sockaddr - useful for connect()

    char buf[BUF_SIZE];
    int errorCheck, msgLength;

    //create socket with error checking (-1 ret on error)
    serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if(serverfd < 0 )
    {
        perror("socket failed.");
        exit(errno);
    }

    //assign sockaddr_in info for server
    bzero(&serverSock, sizeof(serverSock));     //set to all 0's
    serverSock.sin_family = AF_INET;                
    serverSock.sin_addr.s_addr = htonl(INADDR_ANY);
    serverSock.sin_port = htons(ASSIGNED_PORT);


    //bind a name to the socket with error checking (0 ret on success)
    errorCheck = bind(serverfd, (struct sockaddr*)&serverSock, sizeof(serverSock));
    if(errorCheck < 0 )
    {
        perror("bind failed.");
        exit(errno);
    }

    //listen for connections with error checking (0 ret on success)
    errorCheck = listen(serverfd, 10);
    if(errorCheck < 0 )
    {
        perror("listen failed.");
        exit(errno);
    }

    printf("Listening for connections.  Enter CNTRL-c to kill server.\n");

    //create infinite loop to accept, read, write, and close connections with error hecking 
    while(1)
    {

        //accept the connection from the client 
        clientfd = accept(serverfd, 0, 0);
        if(clientfd ==  -1)
        {
            perror("error accepting connection.");
            exit(errno);
        }

        //read data from the client
        bzero(buf, BUF_SIZE);
        msgLength = read(clientfd, buf, BUF_SIZE-1);
        if(msgLength == -1)
        {
            perror("error reading from client");
            close(clientfd);
            close(serverfd);
            exit(errno);
        }

        if(buf[0] '\0')
        {
            printf("connection closing");
            exit(0);
        }
        //print what the client sent
        printf("Message from client: %s\n", buf);

        //echo back what the client sent
        errorCheck = write(clientfd, buf, strlen(buf)+1);   

        if(errorCheck == -1 )
        {
            perror("error writing to client");
            exit(errno);
        }

        //close the connection
        errorCheck = close(clientfd);
        if(errorCheck == -1)
        {
            perror("error closing connection");
            exit(errno);
        }       
    }

    errorCheck = close(serverfd);
    if(errorCheck==-1)
    {
        perror("error closing server, exiting program now");
        sleep(6);
        exit(errno);
    }
    return 0;
}

2 个答案:

答案 0 :(得分:0)

您需要在服务器端使用select()来处理多个客户端,而不是客户端。

答案 1 :(得分:0)

我认为客户端代码中的问题(或者至少是问题)是您将幻数32传递给select()。那是不对的。你应该传递的是所有套接字号码的最大值加一。例如,像这样:

int maxfd = fileno(stdin);
if (maxfd < clientSockFD) maxfd = clientSockFD;
// further maximizations for other sockets would go here, if you had any other sockets...
numfd = select(maxfd+1, &readfds, 0, 0, 0);