AF_UNIX套接字:当没有任何内容可以读取

时间:2015-11-21 14:13:20

标签: c sockets select

该程序创建n个线程,用于模拟分布式系统中的n个节点,每个线程都有一个它监听的套接字,每个线程可以通过连接调用与n-1个其他线程通信。

  1. 每个帖子调用select()来查看是否有可用的东西,如果有的话,接受并保存数据。

  2. 我使用带有标志FIONREAD的ioctl来检查可读取的字节数并进行适当的读取调用。然后关闭新的fd(来自accept())。

  3. 侦听套接字阻塞。 O_NONBLOCK未设置。

  4. 所有n个线程都运行相同的功能。函数内声明的所有变量都使用线程本地存储。

  5. 我没有明确同步。多个线程可以尝试一次连接到同一个套接字。

  6. 现在,问题是,偶尔,接收端线程中的select()会注意到一些新内容,但可用的字节数为0,这是不应该的。这种情况不一致。

    如果有人可以指出我应该调查的地方,那会很棒。谢谢!

    创建袜子

      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);
                }
    

    发送内容

    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);
    

    收到东西

        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 {...}
    

1 个答案:

答案 0 :(得分:3)

您的代码没有意义。 select()解雇的原因是接受。在您刚刚接受的套接字上检查FIONREAD可能会也可能不会导致数据可用。这完全取决于客户是否已发送任何。不在select()的合同上。

如果你需要知道是否有东西要读,你应该将接受的套接字添加到read-FD集,并在循环中处理它:如果监听套接字是可读的,请在其上调用accept() ,否则它是一个被接受的套接字,您应该在其上调用read()

在大多数情况下检查FIONREAD实际上只是浪费时间。