简体   繁体   English

AF_UNIX套接字:没有任何要读取的内容时会触发select()

[英]AF_UNIX socket: select() firing when there is nothing to read

The program creates n threads for simulating n nodes in a distributed system, each has one socket it listens to and each thread can communicate to n-1 other threads through connect calls. 该程序创建了n个线程来模拟分布式系统中的n个节点,每个线程都有一个侦听的套接字,并且每个线程可以通过connect调用与n-1个其他线程进行通信。

  1. Each thread makes a call to select() to see if anything's available and if so accepts and saves the data. 每个线程都会调用select()来查看是否有可用的东西,如果有的话,它接受并保存数据。

  2. I use ioctl with the flag FIONREAD to check the number of bytes available to be read and do an appropriate read call. 我将ioctl与FIONREAD标志一起使用,以检查可读取的字节数并进行适当的读取调用。 Afterwards the new fd (from accept()) is closed. 然后,关闭新的fd(来自accept())。

  3. The listening sockets are blocking. 监听套接字正在阻塞。 O_NONBLOCK is NOT set. 未设置O_NONBLOCK。

  4. All n threads run the same function. 所有n个线程运行相同的功能。 All variables declared within the function use thread local storage. 在函数中声明的所有变量都使用线程本地存储。

  5. There's no explicit synchronization done on my part. 我没有进行任何明确的同步。 More than one thread can try to connect to the same socket at once. 多个线程可以尝试一次连接到同一套接字。

Now, the problem is, once in a while, the select() in a thread on the receiving side notes something new but the amount of bytes available is 0 which it shouldn't be. 现在,问题是,偶尔,接收方线程中的select()会记录一些新内容,但可用字节数为0,这是不应该的。 This happens inconsistently. 这不一致地发生。

Would be great if someone can point where I should look into. 如果有人可以指出我应该研究的地方,那就太好了。 Thanks! 谢谢!

creating the sock 制作袜子

  if ( (nptr->sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
                perror("socket");
                exit(1);
            }
            fd_max = nptr->sock > fd_max ? nptr->sock : fd_max;

            int ok=1;
            setsockopt(nptr->sock, SOL_SOCKET, SO_REUSEADDR, &ok, sizeof(int));

            nptr->addr.sun_family = AF_UNIX;
            snprintf(nptr->addr.sun_path, 20, "%d", nptr->id);
            //strncpy(nptr->addr.sun_path, sock_path, 20);

            if ( bind(nptr->sock, (struct sockaddr*)&(nptr->addr), sizeof(struct sockaddr_un)) < 0 ) {
                perror("bind");
                exit(1);
            }
            /* socket,  max connections */
            if ( listen(nptr->sock, 2*tot_node) < 0 ) {
                perror("listen");
                exit(1);
            }

sending stuff 寄东西

for (t=0; t<tot_node; t++) {
            ...

            if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
                perror("socket");
                exit(1);
            }

            printf("Node %d: trying to req node %d... ", self->id, node_catalog[t]->id);
            if ( connect(fd, (struct sockaddr*)&(node_catalog[t]->addr), sizeof(struct sockaddr_un)) == -1 ) {
                perror("connect");
                exit(1);
            }

            buf[0] = TYPE_REQ;
            buf[1] = self->id;
            buf[2] = ts;
            buf[3] = rsc;

            write (fd, buf, 4*sizeof(int));

            //close(fd);

            printf("Node %d: sent req for resource %d to %d\n", self->id, rsc, node_catalog[t]->id);
        }
        usleep(TS_UPDATE_ITV);

receiving stuff 接收东西

    FD_ZERO(&readset);
            FD_SET(self->sock, &readset);
            t = pselect(self->sock+1, &readset, NULL, NULL, &tout, NULL);
            if (t > 0 && FD_ISSET(self->sock, &readset)) {

                com_fd = accept(self->sock, NULL, NULL);

                ioctl(com_fd, FIONREAD, &t);
    #ifdef DEBUG
                printf("   Node %d: received %d bytes of data\n", self->id, t);
    #endif

                read(com_fd, buf, t);
                close(com_fd);

                dptr = (int *)buf;
                rsc = t / (sizeof(int)); /* var reuse. this is the count of ints to read */

                for (t=0; t<rsc; ) {
                    static __thread int nid, nts, nrsc;
    #ifdef DEBUG
                    printf("   Node %d: data rcvd: %d %d %d %d", self->id, *dptr, *(dptr+1), *(dptr+2), *(dptr+3));
    #endif

                   if (*dptr == TYPE_REQ) {
... } else {...}

Your code doesn't make sense. 您的代码没有意义。 The reason that select() fired was that there was something to accept . select()被解雇的原因是有些东西要接受 Checking FIONREAD on a socket you've just accepted may or may not result in data being available. 在刚刚接受的套接字上检查FIONREAD可能会或可能不会导致数据可用。 It depends entirely on whether the client has sent any. 这完全取决于客户端是否发送了任何内容。 Not on the contract of select() . 不在select()的合同上。

If you need to know whether there is something to read, you should add the accepted socket to the read-FD set, and process it in a loop: if the listening socket is readable, call accept() on it, otherwise it is an accepted socket and you should call read() on it. 如果需要知道是否有要读取的内容,则应将已接受的套接字添加到read-FD集中,并以循环方式进行处理:如果侦听套接字是可读的,则对其调用accept() ,否则为接受的套接字,则应在其上调用read()

Checking FIONREAD is really just a waste of time in most circumstances. 在大多数情况下,检查FIONREAD实际上只是浪费时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM