- 论坛徽章:
- 0
|
最近在使用lighttpd实现RPC远程调用时,发现大报文会导致数据丢失,经过定位,发现writev在发送数据时,造成的数据丢失。
为证实这个问题,我写了一个段test code
具体情况是,server端创建了一个unix socket文件,在accept一个client socket时,将发送模式设置为unblock模式,这时client向server端发送超过tcp buffer所能缓冲的报文时,就是造成报文丢失,block模式不会丢失。
网上搜索相关问题发现也有人提出可能会造成丢失的问题,但没有解决方案,是否为kernel问题。
请问哪位遇到过这样的问题?如何解决?谢谢
附
testcode
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <zlib.h>
#include <ctype.h>
#include <signal.h>
#include <sys/un.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/tcp.h>
#define SOCK_PATH "/tmp/debug/testx"
#define BUFF_SIZE 1024*16
int main (int argc, char**argv)
{
socklen_t len=4;
int rrr,ret;
int sss = socket(AF_UNIX, SOCK_STREAM, 0);
if(sss > 0)
{
rrr = getsockopt(sss, SOL_SOCKET,SO_RCVBUF,&ret, &len);
if(rrr < 0){
printf("getsockopt ret %d, %s\n", rrr, strerror(errno));
return 1;
}
printf("get socket optional: sock receive buff %d,len%d\n",ret,len);
getsockopt(sss, SOL_SOCKET,SO_SNDBUF,&ret, &len);
printf("get socket optional: sock send buff %d,len%d\n",ret,len);
close(sss);
}
else
{
printf("create socket faid\n" ;
}
if(argc !=2)
return 1;
if(strcmp(argv[1],"server" == 0){
int listenfd, connfd;
char buff[1024*300]={'0'};
int sum=0;
socklen_t clilen;
struct sockaddr_un cliaddr, servaddr;
listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
unlink(SOCK_PATH);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, SOCK_PATH);
bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
listen(listenfd,5);
while(1){
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (struct sockaddr*)(&cliaddr),&clilen))<0)
continue;
int n;
sum=0;
while((n = read(connfd, buff, 1024)) > 0){
sum+=n;
}
printf("%d bytes read\n", sum);
printf("------------------------------------------\n" ;
if( n<0 )
printf("read err\n" ;
}
}
else{
int sockfd;
int n,val=1;
struct sockaddr_un servaddr;
char buf0[BUFF_SIZE];
char buf1[BUFF_SIZE];
char buf2[BUFF_SIZE];
char buf3[BUFF_SIZE];
char buf4[BUFF_SIZE];
char buf5[BUFF_SIZE];
char buf6[BUFF_SIZE];
char buf7[BUFF_SIZE];
struct iovec iov[8];
int iovcnt;
int ret ;
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, SOCK_PATH);
connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
n = setsockopt(sockfd, IPPROTO_TCP,TCP_CORK,&val,4);
if(n<0)
printf("setsockopt err %d %s\n",n,strerror(errno));
//setsockopt(connfd, IPPROTO_TCP,3,&val,4);
n = fcntl(sockfd,F_SETFL,O_RDWR|O_NONBLOCK);
if(n<0)
printf("fcntl err %d %s\n",n,strerror(errno));
memset(buf0,'a',BUFF_SIZE);
iov[0].iov_base = buf0;
iov[0].iov_len = BUFF_SIZE;
memset(buf1,'b',BUFF_SIZE);
iov[1].iov_base = buf1;
iov[1].iov_len = BUFF_SIZE;
memset(buf2,'c',BUFF_SIZE);
iov[2].iov_base = buf2;
iov[2].iov_len = BUFF_SIZE;
memset(buf3,'d',BUFF_SIZE);
iov[3].iov_base = buf3;
iov[3].iov_len = BUFF_SIZE;
memset(buf4,'e',BUFF_SIZE);
iov[4].iov_base = buf4;
iov[4].iov_len = BUFF_SIZE;
memset(buf5,'f',BUFF_SIZE);
iov[5].iov_base = buf5;
iov[5].iov_len = BUFF_SIZE;
memset(buf6,'g',BUFF_SIZE);
iov[6].iov_base = buf6;
iov[6].iov_len = BUFF_SIZE;
memset(buf7,'h',BUFF_SIZE);
iov[7].iov_base = buf7;
iov[7].iov_len = BUFF_SIZE;
iovcnt = sizeof(iov)/sizeof(struct iovec);
int i ;
for(i=0;i<10;i++){
printf("%d bytes must be write\n", iov[0].iov_len*iovcnt);
ret = writev(sockfd, iov, iovcnt);
if(ret <0)
printf("writev error %s\n", strerror(errno));
else
printf("%d bytes written\n", ret);
usleep(100);
}
sleep(5);
close(sockfd);
}
return 0;
}
|
|
|