您的位置:首页 > 大数据 > 人工智能

(unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误

2013-11-06 11:35 459 查看
一个困扰我两天的问题,

Google和Baidu没有找到解决方法!

此文为记录这个问题,并给出原因和解决方法。

1、Unix domain socket简介

unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API于在不同主机上执行客户/服务器通信所有的API(套接字API,如AF_INET、AF_INET6等类型的API)相同。unix域协议可以视为是进程之间本地通信IPC的一种。

unix域提供两类套接口:字节流套接口(类似TCP)和数据报套接口(类似UDP)。使用Unix域套接口的理由有三:

Unix域套接口往往比位于同一主机的TCP套接口快出一倍。

Unix域套接口可用于在同一主机上的不同进程之间传递描述字。

Unix域套接口把客户的凭证(用户ID和用户组ID)提供给服务器,从而实现能够提供额外的安全检查措施。

Unix域中用域标识客户和服务器的协议地址是普通文件系统中的路径名(类比:IPv4协议的地址由一个32位地址和一个16位端口号构成,IPv6协议的地址由一个128位地址和16位端口号构成。)。

2、问题描述

简单介绍了Unix域套接口之后,进入主题——描述我碰到的问题。由于unix域套接口用于本机间进程通信比网络套接口效率高,因为它是不经过协议栈的!在项目中选择了unix域的数据报套接口。在使用过程中碰到了如下,问题:发送<128K的消息时,客户、进程可以正常收发消息;发送>=128K的消息时,发送端(sendto)返回ENOBUFS的错误。

服务器的代码如下:

服务器端

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<errno.h>

//define send and recv buf size
#define BUFSIZE 512*1024

//define unix domain socket path
#define pmmanager "/tmp/pmmanager"
#define pmapi "/tmp/pmapi"

int main(int argc, char** argv)
{
char rx_buf[BUFSIZE];
int pmmanager_fd, ret;
socklen_t len;
struct sockaddr_un pmmanager_addr, pmapi_addr;

//create pmmanager socket fd
pmmanager_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(pmmanager_fd ==-1)
{
perror("cannot create pmmanager fd.");
}

unlink(pmmanager);
memset(&pmmanager_addr, 0, sizeof(pmmanager_addr));
pmmanager_addr.sun_family = AF_UNIX;
strncpy(pmmanager_addr.sun_path, pmmanager, sizeof(pmmanager_addr.sun_path)-1);

//bind pmmanager_fd to pmmanager_addr
ret = bind(pmmanager_fd, (struct sockaddr*)&pmmanager_addr, sizeof(pmmanager_addr));
if(ret ==-1)
{
perror("can not bind pmmanager_addr");
}

int recvBufSize;
len =sizeof(recvBufSize);
ret = getsockopt(pmmanager_fd, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &len);
if(ret ==-1)
{
perror("getsocket error.");
}
printf("Before setsockopt, SO_RCVBUF-%d\n",recvBufSize);
recvBufSize =512*1024;
ret = setsockopt(pmmanager_fd, SOL_SOCKET, SO_RCVBUF, &recvBufSize, len);
if(ret ==-1)
{
perror("setsockopt error.");
}
ret = getsockopt(pmmanager_fd, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &len);
if(ret ==-1)
{
perror("getsocket error.");
}
printf("Set recv buf successful, SO_RCVBUF-%d\n",recvBufSize);

int recvSize;
memset(&pmapi_addr, 0, sizeof(pmapi_addr));
len =sizeof(pmapi_addr);
printf("==============wait for msg from pmapi====================\n");
for(;;)
{
memset(rx_buf, 0, sizeof(rx_buf));
recvSize = recvfrom(pmmanager_fd, rx_buf, sizeof(rx_buf), 0, (struct sockaddr*)&pmapi_addr, &len);
if(recvSize ==-1)
{
perror("recvfrom error.");
}
printf("Recved message from pmapi: %s\n", rx_buf);
}
}


客户端

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<errno.h>

//define send and recv buf size
#define BUFSIZE 250*1024

//define unix domain socket path
#define pmmanager "/tmp/pmmanager"
#define pmapi "/tmp/pmapi"

int main(int argc, char** argv)
{
char tx_buf[BUFSIZE];
int pmapi_fd, ret;
socklen_t len;
struct sockaddr_un pmmanager_addr, pmapi_addr;

//create pmmanager socket fd
pmapi_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(pmapi_fd ==-1)
{
perror("cannot create pmapi fd.");
}

unlink(pmapi);
//configure pmapi's addr
memset(&pmapi_addr, 0, sizeof(pmapi_addr));
pmapi_addr.sun_family = AF_UNIX;
strncpy(pmapi_addr.sun_path, pmapi, sizeof(pmapi_addr.sun_path)-1);
//bind pmapi_fd to pmapi_addr
ret = bind(pmapi_fd, (struct sockaddr*)&pmapi_addr, sizeof(pmapi_addr));
if(ret ==-1)
{
perror("bind error.");
}

int sendBufSize;
len =sizeof(sendBufSize);
ret = getsockopt(pmapi_fd, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &len);
if(ret ==-1)
{
perror("getsocket error.");
}
printf("Before setsockopt, SO_SNDBUF-%d\n",sendBufSize);
sendBufSize =512*1024;
ret = setsockopt(pmapi_fd, SOL_SOCKET, SO_SNDBUF, &sendBufSize, len);
if(ret ==-1)
{
perror("setsockopt error.");
}
ret = getsockopt(pmapi_fd, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &len);
if(ret ==-1)
{
perror("getsocket error.");
}
printf("Set send buf successful, SO_SNDBUF-%d\n\n\n", sendBufSize);

//configure pmmanager's addr
memset(&pmmanager_addr, 0, sizeof(pmmanager_addr));
pmmanager_addr.sun_family = AF_UNIX;
strncpy(pmmanager_addr.sun_path, pmmanager, sizeof(pmmanager_addr)-1);
len =sizeof(pmmanager_addr);

int sendSize =0;
int i;
for(i=1; i<=4; i++)
{
memset(tx_buf, '0', sizeof(tx_buf));
sprintf(tx_buf, "send msg %d to pmmanager.", i);
printf("%s, msg size - %d\n",tx_buf, sizeof(tx_buf));
sendSize = sendto(pmapi_fd, tx_buf, sizeof(tx_buf), 0, (struct sockaddr*)&pmmanager_addr, len);
if(sendSize ==-1)
{
perror("sendto error.");
}
printf("Send message to pmmanager: %s\n\n\n", tx_buf);
}
}


代码

。。。。。。
size-131072(DMA)       00131072132 : tunables    840 : slabdata      000
size-13107200131072132 : tunables    840 : slabdata      000
size-65536(DMA)        0065536116 : tunables    840 : slabdata      000
size-655360065536116 : tunables    840 : slabdata      000
size-32768(DMA)        003276818 : tunables    840 : slabdata      000
size-32768003276818 : tunables    840 : slabdata      000
size-16384(DMA)        001638414 : tunables    840 : slabdata      000
size-16384001638414 : tunables    840 : slabdata      000
size-8192(DMA)         00819212 : tunables    840 : slabdata      000
size-819200819212 : tunables    840 : slabdata      000
size-4096(DMA)         00409611 : tunables   24120 : slabdata      000
size-409644409611 : tunables   24120 : slabdata      440
size-2048(DMA)         00204821 : tunables   24120 : slabdata      000
size-20481214204821 : tunables   24120 : slabdata      770
size-1024(DMA)         00102441 : tunables   54270 : slabdata      000
size-10241112102441 : tunables   54270 : slabdata      330
size-512(DMA)          0051281 : tunables   54270 : slabdata      000
size-51220820851281 : tunables   54270 : slabdata     26260
size-256(DMA)          00256151 : tunables  120600 : slabdata      000
size-2567575256151 : tunables  120600 : slabdata      550
size-192(DMA)          00192201 : tunables  120600 : slabdata      000
size-1924040192201 : tunables  120600 : slabdata      220
size-128(DMA)          00128301 : tunables  120600 : slabdata      000
size-1288690128301 : tunables  120600 : slabdata      330
size-96(DMA)           0096401 : tunables  120600 : slabdata      000
size-9638840096401 : tunables  120600 : slabdata     10100
size-64(DMA)           0064591 : tunables  120600 : slabdata      000
size-32(DMA)           00321131 : tunables  120600 : slabdata      000
size-6445147264591 : tunables  120600 : slabdata      880
size-32871904321131 : tunables  120600 : slabdata      880
。。。。。。


我在Ubuntu 10.10上测试,不会报ENOBUFS的错误。内核版本为:



/proc/slabinfo的信息如下,跟上面的有些差异:



kmalloc的最大限制是8192K,故我们运行上述程序没有问题!
原来都是内核惹得祸阿,害我困惑那么久!!!baidu和google都没有找到原因,因此分享此文,以警惕后者。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: