//----------------------------------------------------
//AUTHOR: lanyang123456
//DATE: 2014-10-20
//----------------------------------------------------
socket在主机间和进程间使用,方法类似,主要区别是进程间通信使用的是sockaddr_un,而主机间的通信使用的是sockadd_in。
struct sockaddr_un{
sa_family_t sun_family;//AF_UNIX,它是一个短整型
char sum_path[];//路径名 <pre name="code" class="cpp">};
struct sockaddr_in{ short int sin_family;//AF_INET unsigned short int sin_port;//端口号 struct in_addr sin_addr;//IP地址 };
使用socket作为进程间通信方式,有什么注意事项?
(1) Server
a. 创建一个server socket
创建的socket是AF_UNIX域的。
b. 设置Server的地址
利用bind函数。
注意:地址一般通过一个字符串来标识,一般的做法是通过一个Linux路径来实现;注意使用之前必须要把该路径unlink掉,否则可能出现bind失败的情况。
c. 开始监听
利用listen函数。
注意:最大监听的长度为128.
d. 接客
利用accept函数。
注意:accept函数默认为阻塞模式。有一个可以设置非阻塞的为accept4函数;
在accept函数阻塞的过程中,一些信号对打断accept的阻塞,这是正常现象。因此如果要设置一直阻塞,需要考虑这种情况。
e. 收钱
利用recv()函数
注意:recv函数是在accept新生成的socket上接收消息。recv()函数可以工作在阻塞模式,也可以工作在非阻塞模式。一般都是阻塞模式。新生成的socket注意要关闭。
(2) client
a. 创建
注意域为AF_UNIX。
b. 连接服务器:connect调用
注意:connect为非阻塞模式,需要增加重试机制保证可靠性。
c. 发送数据:send
注意:该调用可以是阻塞的,也可以是非阻塞的,最好设置为非阻塞模式,默认为阻塞模式。另外,可以调用setsockopt()来设置阻塞时长。level:SOL_SOCKET,SO_SNDTIMEO。
例子如下:
server
/* IPC socket AF_UNIX server */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <errno.h> #define UNIX_DOMAIN "/tmp/UNIX.domain" #define QUEUE_LEN 5 int main(void) { socklen_t clt_addr_len; int listen_fd; int com_fd; int ret; int i; char recv_buf[1024]; int len; struct sockaddr_un client_addr; struct sockaddr_un server_addr; listen_fd=socket(PF_UNIX, SOCK_STREAM, 0); if(listen_fd < 0) { perror("cannot create communication socket"); return -1; } //set server addr server_addr.sun_family = AF_UNIX; strncpy(server_addr.sun_path, UNIX_DOMAIN, sizeof(server_addr.sun_path) - 1); unlink(UNIX_DOMAIN); //bind sockfd & addr ret = bind(listen_fd, (struct sockaddr*)&server_addr,sizeof(server_addr)); if(ret == -1) { perror("cannot bind server socket"); close(listen_fd); unlink(UNIX_DOMAIN); return -1; } //listen sockfd ret = listen(listen_fd, 1); if(ret==-1) { perror("cannot listen the client connect request"); close(listen_fd); unlink(UNIX_DOMAIN); return -1; } //have connect request use accept len = sizeof(client_addr); com_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len); if(com_fd < 0) { perror("cannot accept client connect request"); close(listen_fd); unlink(UNIX_DOMAIN); return -1; } //read and printf sent client info printf("---------------\n"); memset(recv_buf,0,1024); ret = read(com_fd, recv_buf, sizeof(recv_buf) - 1); if (ret <= 0) { printf("write error(%d) %s\n", errno, strerror(errno)); close(com_fd); close(listen_fd); unlink(UNIX_DOMAIN); return -1; } printf("Message from client :%s\n", recv_buf); close(com_fd); close(listen_fd); unlink(UNIX_DOMAIN); return 0; }
client
/* IPC socket AF_UNIX client */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <errno.h> #define UNIX_DOMAIN "/tmp/UNIX.domain" int main(void) { int connect_fd; int ret; char snd_buf[1024]; int i; static struct sockaddr_un server_addr; //creat unix socket connect_fd=socket(AF_UNIX, SOCK_STREAM, 0); if(connect_fd<0) { perror("cannot create communication socket"); return 1; } server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, UNIX_DOMAIN); //connect server ret=connect(connect_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if(ret==-1) { perror("cannot connect to the server"); close(connect_fd); return 1; } memset(snd_buf, 0, 1024); strcpy(snd_buf, "message from client"); ret = write(connect_fd,snd_buf,sizeof(snd_buf)); if (ret <= 0) { printf("write error(%d) %s\n", errno, strerror(errno)); close(connect_fd); return -1; } close(connect_fd); return 0; }
测试:
#./server
可通过一下命令查看结果
$ netstat -an | grep tmp/UNIX.domain
unix 2 [ ACC ] STREAM LISTENING 302051 /tmp/UNIX.domain
参考
http://blog.chinaunix.net/uid-26790551-id-3171897.html
http://blog.sina.com.cn/s/blog_9cd4235201019cy6.html