2015-11-21 64 views
-1

程序創建n個線程來模擬分佈式系統中的n個節點,每個線程有一個偵聽的套接字,每個線程可以通過連接與n-1個其他線程通信調用。AF_UNIX套接字:select()在沒有東西可讀時觸發

  1. 每個線程都會調用select()來查看是否有可用的內容,如果有,則接受並保存數據。

  2. 我使用帶有標誌FIONREAD的ioctl來檢查可讀取的字節數並進行適當的讀取調用。之後,新的fd(來自accept())被關閉。

  3. 監聽套接字阻塞。 O_NONBLOCK未設置。

  4. 所有n個線程運行相同的功能。在函數中聲明的所有變量都使用線程本地存儲。

  5. 我沒有明確的同步。多個線程可以嘗試一次連接到同一個套接字。現在

,問題是,過一段時間,在接收側的線程的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 {...} 
+0

即使您的所有代碼都是正確的,但絕對沒有禁止這種情況發生的規則。確保套接字不會阻塞的唯一方法是將其設置爲非阻塞。否則,您正在做相當於檢查磁盤上是否有可用空間,然後追加到文件的情況 - 那裏有*空閒空間並不能保證您追加時會有*空閒空間。 socket *是*可讀的,並不能保證它*將* *在以後可讀*。 –

回答

3

您的代碼是沒有意義的。 select()開火的原因是有一些東西接受。在您剛剛接受的套接字上檢查FIONREAD可能會導致或不會導致數據可用。這完全取決於客戶是否發送了任何信息。不在select()的合同上。

如果您需要知道是否有東西需要讀取,您應該將已接受的套接字添加到read-FD套件中,並在循環中處理它:如果套接字可讀,請調用accept(),否則是一個可接受的套接字,你應該打電話給read()

在大多數情況下檢查FIONREAD只是浪費時間。

+0

好的,我明白我做錯了什麼。 雖然線程應該在連接後立即發送數據,但ioctl()可能在任何實際可用之前已經執行完畢。我用經典while循環改變了這個讀取調用。 謝謝! – DebD

相關問題