我正在尝试使用select函数在服务器与1个客户端(无更多)之间进行无阻塞的I/O通讯,该客户端的通信顺畅(可以随时发送,而其他无需等待发送即可接收)。我找到了一个包含一些代码的教程,并试图使其适应我的需求。这就是我所拥有的-

服务器

#define PORT "4950"
#define STDIN 0

struct sockaddr name;

void set_nonblock(int socket) {
    int flags;
    flags = fcntl(socket,F_GETFL,0);
    assert(flags != -1);
    fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}


// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
    if (sa->sa_family == AF_INET)
        return &(((struct sockaddr_in*)sa)->sin_addr);

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int agrc, char** argv) {
    int status, sock, adrlen, new_sd;

    struct addrinfo hints;
    struct addrinfo *servinfo;  //will point to the results

    //store the connecting address and size
    struct sockaddr_storage their_addr;
    socklen_t their_addr_size;

    fd_set read_flags,write_flags; // the flag sets to be used
    struct timeval waitd;          // the max wait time for an event
    int sel;                      // holds return value for select();

    //socket infoS
    memset(&hints, 0, sizeof hints); //make sure the struct is empty
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM; //tcp
    hints.ai_flags = AI_PASSIVE;     //use local-host address

    //get server info, put into servinfo
    if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
        exit(1);
    }

    //make socket
    sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
    if (sock < 0) {
        printf("\nserver socket failure %m", errno);
        exit(1);
    }

    //allow reuse of port
    int yes=1;
    if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    //unlink and bind
    unlink("127.0.0.1");
    if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
        printf("\nBind error %m", errno);
        exit(1);
    }

    freeaddrinfo(servinfo);

    //listen
    if(listen(sock, 5) < 0) {
        printf("\nListen error %m", errno);
        exit(1);
    }
    their_addr_size = sizeof(their_addr);

    //accept
    new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
    if( new_sd < 0) {
        printf("\nAccept error %m", errno);
        exit(1);
    }

    set_nonblock(new_sd);
    cout<<"\nSuccessful Connection!";

    char* in = new char[255];
    char* out = new char[255];
    int numSent;
    int numRead;


    while(1) {

        waitd.tv_sec = 10;
        FD_ZERO(&read_flags);
        FD_ZERO(&write_flags);
        FD_SET(new_sd, &read_flags);

        if(strlen(out) != 0)
            FD_SET(new_sd, &write_flags);

        sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
        if(sel < 0)
            continue;

        //socket ready for reading
        if(FD_ISSET(new_sd, &read_flags)) {
            FD_CLR(new_sd, &read_flags);

            memset(&in, 0, sizeof(in));

            if(recv(new_sd, in, sizeof(in), 0) <= 0) {
                close(new_sd);
                break;
            }
            else
                cout<<"\n"<<in;
        }   //end if ready for read

        //socket ready for writing
        if(FD_ISSET(new_sd, &write_flags)) {

            FD_CLR(new_sd, &write_flags);
            send(new_sd, out, strlen(out), 0);
            memset(&out, 0, sizeof(out));
        }
    }   //end while

    cout<<"\n\nExiting normally\n";
    return 0;
}

客户(基本上是相同的,只是减去接受调用)-
#define PORT "4950"

struct sockaddr name;

void set_nonblock(int socket) {
    int flags;
    flags = fcntl(socket,F_GETFL,0);
    assert(flags != -1);
    fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
    if (sa->sa_family == AF_INET)
        return &(((struct sockaddr_in*)sa)->sin_addr);

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int agrc, char** argv) {
    int status, sock, adrlen;

    struct addrinfo hints;
    struct addrinfo *servinfo;  //will point to the results

    fd_set read_flags,write_flags; // the flag sets to be used
    struct timeval waitd;          // the max wait time for an event
    int sel;                      // holds return value for select();

    memset(&hints, 0, sizeof hints); //make sure the struct is empty
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM; //tcp
    hints.ai_flags = AI_PASSIVE;     //use local-host address

    //get server info, put into servinfo
    if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
        exit(1);
    }

    //make socket
    sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
    if (sock < 0) {
        printf("\nserver socket failure %m", errno);
        exit(1);
    }

    if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
        printf("\nclient connection failure %m", errno);
        exit(1);
    }

    cout<<"\nSuccessful connection!";

    set_nonblock(sock);

    char* out = new char[255];
    char* in = new char[255];
    int numRead;
    int numSent;

    while(1) {

        waitd.tv_sec = 10;
        FD_ZERO(&read_flags);
        FD_ZERO(&write_flags);
        FD_SET(sock, &read_flags);

        if(strlen(out) != 0)
            FD_SET(sock, &write_flags);


        sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
        if(sel < 0)
            continue;

        //socket ready for reading
        if(FD_ISSET(sock, &read_flags)) {
            FD_CLR(sock, &read_flags);

            memset(&in, 0, sizeof(in));

            if(recv(sock, in, sizeof(in), 0) <= 0) {
                close(sock);
                break;
            }
            else
                cout<<"\n"<<in;
        }   //end if ready for read

        //socket ready for writing
        if(FD_ISSET(sock, &write_flags)) {
            FD_CLR(sock, &write_flags);
            send(sock, out, strlen(out), 0);
            memset(&out, 0, sizeof(out));
        }
    }   //end while

    cout<<"\n\nExiting normally\n";
    return 0;
}

问题是,当我运行它们时,什么也没发生。我可以输入一个,然后按Enter键,而另一个屏幕上什么也没有显示(反之亦然)。那不是我要调试的全部信息,这是我第一次真正使用select的尝试,所以我认为也许我只是不了解一些简单的东西。如果发现任何错误或怪异的东西,请指出来,我们将为您提供任何帮助。

最佳答案


真正的问题是,人们多年来一直在不了解Beej的情况下粘贴东西。这就是为什么我不太喜欢该指南的原因。它给出了大量的代码块,而没有真正详细地解释它们。
您什么也不阅读,也不发送任何信息。没有fgets,scanf,cin等。这就是我要做的:

FD_SET(sock, &read_flags);
FD_SET(STDIN_FILENO, &read_flags);

/* .. snip .. */

if(FD_ISSET(STDIN_FILENO, &read_flags)) {
    fgets(out, len, stdin);
}
这将监视stdin并在有可用输入时从中读取;然后,当套接字是可写的(FD_ISSET(sock, &write_flags))时,它将发送缓冲区。

关于c - 对非阻塞套接字使用select(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6715736/

10-10 21:24