共享内存的操作函数
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
Unix域socket通信
#include<sys/un.h>
struct sockaddr_un
{
unit8_tsun_len;
sa_family_t sun_family;
charsun_path[104];
};
#include<sys/socket.h>
socket操作的相关函数
使用select调用处理多路管道
#include <sys/time.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
void FD_ZERO(fd_set *fdset);/*initialize the mask pointed to by fdset */
void FD_SET(int fd, fd_set *fdset); /*set the bit, fd, in the mask pointed to by fdset*/
/*isthe bit, fd, set in the mask pointed to by fdset*/
void FD_ISSET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
struct timeval{
long tv_sec;
long tv_usec;
};
调用实例
#include <sys/time.h>
#include <sys/type.h>
#include <fcntl.h>
……
int fd1, fd2;
fd_set readset;
fd1= open(“file1”, O_RDONLY);
fd2= open(“file2”, O_RDONLY);
FD_ZERO(&readset);
FD_SET(fd1, &readset);
FD_SET(fd2, &readset);
Switch (select(5, &readset, NULL, NULL, NULL))
{
……
}
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
//#include <openssl/ssl.h>
//#include <openssl/err.h>
#include <pthread.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <unistd.h>
#include <signal.h>
#include <net/if_arp.h>
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/vfs.h>
#include <sys/un.h>
#define JOSEPH_IPNC_SYS_NAME "av_server"
#define SOCK_UNIX_VIDEO_STREAM_FILE "/tmp/video1_sock"
#define SOCK_UNIX_VIDEO_STREAM_FILE_SEVER "/tmp/video1_server"
#define SOCK_UNIX_VIDEO_STREAM_FILE_CLIENT "/tmp/video1_client"
struct sockaddr_un server_address_udp;
struct sockaddr_un server_address_client;
extern struct sockaddr_un server_address_udp;
int video_stream_net_func_udp(void)
{
#if 0
int server_sockfd;
//unlink (SOCK_UNIX_VIDEO_STREAM_FILE_SEVER);//delete the file link for the function of bind
server_sockfd = socket (AF_UNIX, SOCK_DGRAM, 0);
server_address_udp.sun_family = AF_UNIX;
//server_address_udp.sin_port=htons(PORT);
strcpy (server_address_udp.sun_path, SOCK_UNIX_VIDEO_STREAM_FILE_SEVER);
joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp_socket_size = sizeof (server_address_udp);
//bind (server_sockfd, (struct sockaddr *)&server_address_udp, server_len);
joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp = 0;
joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp = server_sockfd;
printf("%s %d The udp mode send to jss succeed ,joseph_ipnc_s_socket_fd_udp is %d !\n",__FUNCTION__,__LINE__,joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp);
#else
int client_sockfd, ret;
//struct sockaddr_un pmmanager_addr, pmapi_addr;
client_sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(client_sockfd == -1)
{
perror("cannot create pmapi fd.");
}
unlink(SOCK_UNIX_VIDEO_STREAM_FILE_CLIENT); //configure pmapi's addr
memset(&server_address_client, 0, sizeof(server_address_client));
server_address_client.sun_family = AF_UNIX;
strcpy(server_address_client.sun_path, SOCK_UNIX_VIDEO_STREAM_FILE_CLIENT); //bind pmapi_fd to pmapi_addr
ret = bind(client_sockfd, (struct sockaddr*)&server_address_client, SUN_LEN(&server_address_client));
if(ret == -1)
{
perror("bind error.");
}
//configure pmmanager's addr
memset(&server_address_udp, 0, sizeof(server_address_udp));
server_address_udp.sun_family = AF_UNIX;
strcpy(server_address_udp.sun_path, SOCK_UNIX_VIDEO_STREAM_FILE_SEVER);
joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp = 0;
joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp = client_sockfd;
printf("%s %d The udp mode send to jss succeed ,joseph_ipnc_s_socket_fd_udp is %d !\n",__FUNCTION__,__LINE__,joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp);
#endif
return 0;
}
void net_send_stream_first(void *video_buf,int video_length)
{
int s_length;
#if 0
if(video_length <= 8) return;
#else
if(video_length <= 4) return;
#endif
if(joseph_ipnc_s_socket.joseph_ipnc_s_scoket_sta == 1)
{
#if 1
char buf_time[128] = {0};
memset(buf_time,0,128);
get_current_time(buf_time);
printf("%s %d %s send begin time is : \n",__FUNCTION__,__LINE__,buf_time);
printf("%s %d The num is %d ,The buf size is %d !\n",__FUNCTION__,__LINE__,joseph_ipnc_param.joseph_ipnc_network_attr.joseh_send_to_jss_frame_num,video_length);
printf("%s %d joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp is %d \n",__FUNCTION__,__LINE__,joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp);
#endif
#if 0
s_length = send(joseph_ipnc_s_socket.joseph_ipnc_s_scoket_fd, video_buf, video_length, 0);
#else
/*
int sendto ( socket s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;
sendto(sockfd, buffer, len, 0, (struct addr*)&addr, addr_len);¡±
*/
s_length = sendto(joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp, video_buf, video_length, 0,(struct sockaddr*)&server_address_udp,SUN_LEN(&server_address_udp));
#endif
if(s_length <= 0)
{
printf("%s %d The send is err, The length is %d !!! \n",__FUNCTION__,__LINE__,s_length);
close(joseph_ipnc_s_socket.joseph_ipnc_s_scoket_fd);
//close(joseph_ipnc_s_socket.joseph_ipnc_s_socket_fd_udp);
joseph_net_lock();
joseph_ipnc_s_socket.joseph_ipnc_s_scoket_sta = -2;
joseph_net_unlock();
//exit(-2);
}
else
{
//printf("%s %d net_send_stream_first succeed \n",__FUNCTION__,__LINE__);
//do nothing
}
#if 0
memset(buf_time,0,128);
get_current_time(buf_time);
printf("%s %d %s send end time is : \n",__FUNCTION__,__LINE__,buf_time);
#endif
}
else
{
// do nothing
}
}
unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API于在不同主机上执行客户/服务器通信所有的API(套接字API,如AF_INET、AF_INET6等类型的API)相同。unix域协议可以视为是进程之间本地通信IPC的一种。
unix域提供两类套接口:字节流套接口(类似TCP)和数据报套接口(类似UDP)。使用Unix域套接口的理由有三:
Unix域中用域标识客户和服务器的协议地址是普通文件系统中的路径名(类比:IPv4协议的地址由一个32位地址和一个16位端口号构成,IPv6协议的地址由一个128位地址和16位端口号构成。)。
简单介绍了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); } }
3、可能碰到的另外一个问题
如果你没有设置足够大的发送缓冲区大小,你很有可能碰到EMSGSIZE的错误!因为应用程序写了一个大于套机口发送缓冲区大小的数据报,内核报EMSGSIZE错误。如下图:
(注意:UDP套接口有发送缓冲区的大小,并且可以通过SO_SNDBUF套接口选项修改。不过它仅仅是写到套接口的UDP数据报的大小,因为UDP是不可靠的,它不必保存应用进程的数据拷贝,因此无需一个真正的发送缓冲区。)上面的代码已经设置了足够大的发送缓冲区大小。
在sendto发送>=128K大小的消息时,返回ENOBUFS错误。
。。。。。。 size-131072(DMA) 0 0 131072 1 32 : tunables 8 4 0 : slabdata 0 0 0 size-131072 0 0 131072 1 32 : tunables 8 4 0 : slabdata 0 0 0 size-65536(DMA) 0 0 65536 1 16 : tunables 8 4 0 : slabdata 0 0 0 size-65536 0 0 65536 1 16 : tunables 8 4 0 : slabdata 0 0 0 size-32768(DMA) 0 0 32768 1 8 : tunables 8 4 0 : slabdata 0 0 0 size-32768 0 0 32768 1 8 : tunables 8 4 0 : slabdata 0 0 0 size-16384(DMA) 0 0 16384 1 4 : tunables 8 4 0 : slabdata 0 0 0 size-16384 0 0 16384 1 4 : tunables 8 4 0 : slabdata 0 0 0 size-8192(DMA) 0 0 8192 1 2 : tunables 8 4 0 : slabdata 0 0 0 size-8192 0 0 8192 1 2 : tunables 8 4 0 : slabdata 0 0 0 size-4096(DMA) 0 0 4096 1 1 : tunables 24 12 0 : slabdata 0 0 0 size-4096 4 4 4096 1 1 : tunables 24 12 0 : slabdata 4 4 0 size-2048(DMA) 0 0 2048 2 1 : tunables 24 12 0 : slabdata 0 0 0 size-2048 12 14 2048 2 1 : tunables 24 12 0 : slabdata 7 7 0 size-1024(DMA) 0 0 1024 4 1 : tunables 54 27 0 : slabdata 0 0 0 size-1024 11 12 1024 4 1 : tunables 54 27 0 : slabdata 3 3 0 size-512(DMA) 0 0 512 8 1 : tunables 54 27 0 : slabdata 0 0 0 size-512 208 208 512 8 1 : tunables 54 27 0 : slabdata 26 26 0 size-256(DMA) 0 0 256 15 1 : tunables 120 60 0 : slabdata 0 0 0 size-256 75 75 256 15 1 : tunables 120 60 0 : slabdata 5 5 0 size-192(DMA) 0 0 192 20 1 : tunables 120 60 0 : slabdata 0 0 0 size-192 40 40 192 20 1 : tunables 120 60 0 : slabdata 2 2 0 size-128(DMA) 0 0 128 30 1 : tunables 120 60 0 : slabdata 0 0 0 size-128 86 90 128 30 1 : tunables 120 60 0 : slabdata 3 3 0 size-96(DMA) 0 0 96 40 1 : tunables 120 60 0 : slabdata 0 0 0 size-96 388 400 96 40 1 : tunables 120 60 0 : slabdata 10 10 0 size-64(DMA) 0 0 64 59 1 : tunables 120 60 0 : slabdata 0 0 0 size-32(DMA) 0 0 32 113 1 : tunables 120 60 0 : slabdata 0 0 0 size-64 451 472 64 59 1 : tunables 120 60 0 : slabdata 8 8 0 size-32 871 904 32 113 1 : tunables 120 60 0 : slabdata 8 8 0 。。。。。。
我在Ubuntu 10.10上测试,不会报ENOBUFS的错误。内核版本为: