(unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
2013-11-06 11:35
459 查看
一个困扰我两天的问题,
Google和Baidu没有找到解决方法!
此文为记录这个问题,并给出原因和解决方法。
unix域提供两类套接口:字节流套接口(类似TCP)和数据报套接口(类似UDP)。使用Unix域套接口的理由有三:
Unix域套接口往往比位于同一主机的TCP套接口快出一倍。
Unix域套接口可用于在同一主机上的不同进程之间传递描述字。
Unix域套接口把客户的凭证(用户ID和用户组ID)提供给服务器,从而实现能够提供额外的安全检查措施。
Unix域中用域标识客户和服务器的协议地址是普通文件系统中的路径名(类比:IPv4协议的地址由一个32位地址和一个16位端口号构成,IPv6协议的地址由一个128位地址和16位端口号构成。)。
服务器的代码如下:
服务器端
客户端
代码
我在Ubuntu 10.10上测试,不会报ENOBUFS的错误。内核版本为:
/proc/slabinfo的信息如下,跟上面的有些差异:
kmalloc的最大限制是8192K,故我们运行上述程序没有问题!
原来都是内核惹得祸阿,害我困惑那么久!!!baidu和google都没有找到原因,因此分享此文,以警惕后者。
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都没有找到原因,因此分享此文,以警惕后者。
相关文章推荐
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- 嵌入式 (unix domain socket本地套接字)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
- 使用udp发送大于128K的消息会报ENOBUFS的错误
- 使用psql命令基于udp(unix-domain-socket)协议连接postgresql数据库
- QUdpSocket简单使用Demo(局域网内发送给所有客户端消息与接收)
- python,UPD,socket(一) 使用udp 发送消息
- Socket编程 (连接,发送消息) (Tcp、Udp) ,这个是同步,跟上一篇差不多
- 使用udp协议给飞Q发送消息
- UNIX Domain Socket使用
- 基于UDP协议的网络编程(使用DatagramSocket发送接收数据)
- 使用DatagramSocket发送、接收数据(Socket之UDP套接字)
- ASP.NET--使用Socket发送和接收消息[转载]
- iOS学习笔记4-GCDAsyncUdpSocket的使用(实现异步发送接收数据)
- python:使用udp协议发送飞秋消息