2011-08-27 60 views
1

我有一個單元測試,用於檢查阻塞和非阻塞套接字上的行爲 - 服務器寫入一個長響應,並且在某些時候它不應該能夠再寫入數據,寫入塊。套接字在寫操作時沒有被阻塞:OpenSolaris

基本上一邊寫道​​,另一邊不讀。

在Solaris下,在某些時候,我得到一個錯誤「沒有足夠的空間」(寫入75MB後),而不是阻塞寫:

計劃能重現問題:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <signal.h> 
#include <arpa/inet.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <netinet/in.h> 

char const *address = "127.0.0.1"; 
#define check(x) do { if((x) < 0) { perror(#x) ; exit(1); } } while(0) 

int main() 
{ 
    signal(SIGPIPE,SIG_IGN); 
    struct sockaddr_in inaddr = {}; 
    inaddr.sin_family = AF_INET; 
    inaddr.sin_addr.s_addr = inet_addr(address); 
    inaddr.sin_port = htons(8080); 

    int res = fork(); 
    if(res < 0) { 
     perror("fork"); 
     exit(1); 
    } 
    if(res > 0) { 
     int fd = -1; 
     int status; 
     sleep(1); 
     check(fd = socket(AF_INET,SOCK_STREAM,0)); 
     check(connect(fd,(sockaddr*)&inaddr,sizeof(inaddr))); 
     sleep(5); 
     close(fd); 

     wait(&status); 
     return 0; 
    } 
    else { 
     int acc,fd; 
     check(acc = socket(AF_INET,SOCK_STREAM,0)); 
     int yes = 1; 
     check(setsockopt(acc,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); 
     check(bind(acc,(sockaddr*)&inaddr,sizeof(inaddr))); 
     check(listen(acc,10)); 
     check(fd = accept(acc,0,0)); 

     char buf[1000]; 
     long long total= 0; 
     do { 
      int r = send(fd,buf,sizeof(buf),0); 
      if(r < 0) { 
       printf("write %s\n",strerror(errno)); 
       return 0; 
      } 
      else if(r==0) { 
       printf("Got eof\n"); 
       return 0; 
      } 
      total += r; 
      if(total > 100*1024*1024) { 
       printf("Too much!!!!\n"); 
       return 0; 
      } 
      printf("%lld\n",total); 
     }while(1); 
    } 
    return 0; 
} 

的輸出在Solaris上(最後兩行)

75768000 
write Not enough space 

Linux上的預期輸出(最後兩行)

271760 
write Connection reset by peer 

只有當另一側關閉套接字時纔會發生這種情況。

任何想法爲什麼以及如何修復它,設置什麼選項?

PS:是的OpenSolaris 2009.06,86

編輯

  • 增加能重現問題完整的C代碼

答:

這似乎是Solaris特定版本中的錯誤nel,libc庫。

+0

你肯定送不回部分完成?它不在你的示例代碼中。 – bazsi77

+0

@ bazsi77部分完成首先是好的,第二不是它總是成功地寫出完整的塊 – Artyom

+0

我知道它是好的,我只是想知道代碼是否正確處理了這種情況。但是,如果你可以發送這麼多的數據,它必須存儲在某個地方。在Linux上,netstat能夠顯示緩衝量。此外,系統內存使用必須增加。如果確實如此,那麼它確實是內核中的一個bug,在這種情況下,我會提交bugreport,或者嘗試在OpenSolaris內核代碼中找到問題。 – bazsi77

回答

1

從OpenSolaris的源代碼,恐怕SO_SNDTIMEO選項是不支持的:https://hg.java.net/hg/solaris~on-src/file/tip/usr/src/uts/common/inet/sockmods/socksctp.c#l1233

+0

奇怪,因爲setsockopt成功,並根據您鏈接它的代碼應該失敗。另外它似乎不支持getsockopt而不是setsockopt。此外,在不使用此選項的異步代碼中,它也失敗。 – Artyom

+0

setsockopt「支持」SO_SNDTIMEO,它接受任何傳遞的值,但它對此無能爲力。我剛剛在Solaris 11 Express上測試了更新後的代碼,並在140kBytes之後寫入了寫入過程塊。在監聽過程關閉套接字並且下一次寫入完成後,它終於得到了一個壞的管道錯誤(但你忽略了它)。上面示例中的 – jlliagre

+0

現在我根本不使用'SO_SNDTIMEO'。順便說一句,我不會忽視破碎的管道,我會阻止它,否則這個過程就會退出。我在套接字上遇到錯誤。 – Artyom