我有一個單元測試,用於檢查阻塞和非阻塞套接字上的行爲 - 服務器寫入一個長響應,並且在某些時候它不應該能夠再寫入數據,寫入塊。套接字在寫操作時沒有被阻塞: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庫。
你肯定送不回部分完成?它不在你的示例代碼中。 – bazsi77
@ bazsi77部分完成首先是好的,第二不是它總是成功地寫出完整的塊 – Artyom
我知道它是好的,我只是想知道代碼是否正確處理了這種情況。但是,如果你可以發送這麼多的數據,它必須存儲在某個地方。在Linux上,netstat能夠顯示緩衝量。此外,系統內存使用必須增加。如果確實如此,那麼它確實是內核中的一個bug,在這種情況下,我會提交bugreport,或者嘗試在OpenSolaris內核代碼中找到問題。 – bazsi77