c++ - poll() socket编程tcp linux多连接问题

标签 c++ linux sockets

我是套接字编程的新手,但我已经在 https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/poll.htm 关注了 ibm 示例并更改了一些代码以使其更好,但是当我通过 telnet ip 端口连接到服务器并使其回显消息时,它适用于第一个连接的客户端,但在第二个客户端上它不回显消息?

#include <netinet/in.h> // sockaddr_in struct
#include <arpa/inet.h> //inet_addr()
#include <sys/socket.h>
#include <errno.h> //errors
#include <stdio.h> //perror()
#include <cstdlib> //EXIT_FAILURE
#include <sys/ioctl.h> //FIONBIO
#include <unistd.h> //close file descriptor
#include <fcntl.h> //make non blocking
#include <poll.h> //poll stuff
#include <string.h> //memset
int main()
{
    int s = -1;
    int rc;
    int optval = 1;
    int timeout;
    bool end_server = false; //because we need to log if EWOULDBLOCK is true...

    struct pollfd fds[200]; //initialize pollfd struct
    int nfds = 1; // nfds_t really set to 1 else it will be 199 once we pass it to poll....

    int current_size = 0;

    int new_s = -1;

    int close_conn;

    char *buff;

    int len;

    bool compress_array;

    s = socket(AF_INET, SOCK_STREAM, 0);

    //make socket description reusable with SO_REUSEADDR
    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&optval), sizeof(optval));
    if(rc < 0){
        perror("setsockopt()");
        close(s);
        exit(EXIT_FAILURE);
    }

    //make socket non-blocking
    //rc = ioctl(s, FIONBIO, reinterpret_cast<char*>(&optval));
    //if(rc < 0)
    //{
    //    perror("ioctl()");
    //    close(s);
    //    exit(EXIT_FAILURE);
    //}
    fcntl(s, F_SETFL, O_NONBLOCK);

    struct sockaddr_in saddr;
    //initialize sockaddr_in struct
    memset(&saddr, 0, sizeof(saddr));

    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(80);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    rc = bind(s, reinterpret_cast<struct sockaddr *>(&saddr), sizeof(saddr));

    if(rc < 0){
        perror("bind()");
        exit(EXIT_FAILURE);
    }

    rc = listen(s, 32);
    if(rc < 0){
        perror("listen() failed");
        close(s);
        exit(EXIT_FAILURE);
    }

    //initialize fds struct
    memset(&fds, 0, sizeof(fds));

    fds[0].fd = s;
    fds[0].events = POLLIN; //check if data to read

    //initialize timeout value to 3 mins based on millisecs
    //timeout = (3 * 60 * 1000); // because function will be like sleep() that uses millisecs
    timeout = 10000;

    do{
        //call poll() and wait 3 mins to complete because of timeout
        printf("Waiting on poll()...\n");
        rc = poll(fds, nfds, timeout);

        if(rc < 0){
            perror("poll() failed");
            exit(EXIT_FAILURE);
        }

        //check if 3 minutes timeout expired
        if(rc == 0){
            printf("poll() timed out ending program...\n");
            exit(EXIT_FAILURE);
        }

        current_size = nfds;
        for(int i = 0; i < current_size; i++)
        {
            //loop thru fds and check if revents returns POLLIN, means the fd have data to read...
            if(fds[i].revents == 0)
                continue;


            //if revents is not POLLIN then exit program and log
            if(fds[i].revents != POLLIN){
                printf("revents != POLLIN, revents = %d\n", fds[i].revents);
                //end_server = true;
                //break;
                //perror("revents unknown");
                //exit(EXIT_FAILURE);
                close(fds[i].fd);
                fds[i].fd = -1;
                break;
            }

            if(fds[i].fd == s){
                printf("Listening socket available\n");

                do{
                    //accept each new incoming connections
                    new_s = accept(s, NULL, NULL);
                    if(new_s < 0){
                        if(errno != EWOULDBLOCK){
                            perror("accept() failed because of socket would block");
                            end_server = true;
                        }
                        //printf("something else wrong with accept()\n");
                        break;
                    }

                    //add new incoming connection
                    printf("new incoming connection - nfds: %d\n", new_s);
                    fds[nfds].fd = new_s;
                    fds[nfds].events = POLLIN;
                    nfds++;
                    //continue;
                    //loop back up and accept another connection

                } while(new_s != -1);
            }
            // file descriptor is readable because its now new_s instead of s
            else {
                printf("descriptor %d is readable\n", fds[i].fd);
                close_conn = false;
                //receive all data on this connection till we go back and poll again
                do {

                    rc = recv(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0);
                    if(rc < 0){
                        if(errno != EWOULDBLOCK){
                            perror("recv() failed");
                            close_conn = true;
                        }
                        break;
                    }

                    //check if conn was closed by client
                    if(rc == 0){
                        printf("connection closed");
                        close_conn = true;
                        break;
                    }

                    //data was received
                    len = rc;
                    printf("%d bytes received", len);

                    //process stuff or echo data back to client
                    rc = send(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0);
                    if(rc < 0){
                        perror("send() failed");
                        close_conn = true;
                        break;
                    }
                    memset(&buff, 0, sizeof(buff));

                } while (true);
                if(close_conn){
                    close(fds[i].fd);
                    fds[i].fd = -1;
                    compress_array = true;
                }

            }


        }
        if(compress_array){
            compress_array = false;
            int i = 0;
            for(i = 0; i < nfds; i++){
                if(fds[i].fd == -1){
                    for(int j = i; j < nfds; j++){
                        fds[j].fd = fds[j+1].fd;
                    }
                    i--;
                    nfds--;
                }
            }
        }

    } while (end_server == false);

    //clean all sockets that are open
    for(int i = 0; i < nfds; i++){
        if(fds[i].fd > 0){ // if already -1 don't need to close socket
            close(fds[i].fd);
            fds[i].fd = -1;
        }
    }



    return 0;
}

最佳答案

啊这是因为我用 while(true) 循环所以它一直循环尝试接收数据而不是返回并向列表添加新连接。

关于c++ - poll() socket编程tcp linux多连接问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36950681/

相关文章:

c++ - 为什么从桌面运行程序时找不到我的声音文件?

c - 进程相互跟踪

c++ - Services.msc 中未显示 ATL 服务

c++ - 通过 id 并返回名称在 vector 中搜索结构元素

c++ - 如何在 VS 代码中为 Bazel 项目启用 C++ 智能感知?

linux - 我们在使用套接字时应该处理什么错误

c - 在 UDP 非阻塞客户端/服务器对中生成的随机 EWOULDBLOCK 与 SIGIO 生成的 recvfrom

linux - Chrome Linux --kiosk 打印

c - 用于检查超出的任何数据类型的最大值的 API

php - 警告 : mysqli_connect(): (HY000/2002): An attempt was made to access a socket in a way forbidden by its access permissions