1,什么是UNIX SOCKET
UNIX SOCKET,域套接字,UNIX SOCKET可用于同一台设备进程间通信,它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序列号应答等,只需要将数据从一个进程复制到另一个进程,有两种类型,字节流套接字和数据报套接字。类似于TCP和UDP,但是面向消息的UNIX socket也是可靠的,消息既不会丢失也不会顺序错乱
2,UNIX SOCKET工作流程图
3,UNIX SOCKET的方法
使用UNIX SOCKET一般需要包含两个头文件
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
这里主要说明UNIX SOCKET相比于SOCKET不同的两个方法(传入的参数有差异,方法名是一致的),其它的方法都和SOCKET通讯的方法是一样的。
1,int socket(int domain, int type, int protocol)
该方法用于创建套接字,各参数的含义:
- domain:使用AF_UNIX或者AF_LOCAL
- type : 使用SOCK_STREAM(TCP)或者SOCK_DGRAM(UDP)
- protocol:如果type不是SOCK_RAM,一般是0
domain决定了socket的地址类型。对于AF_UNIX/AF_LOCAL,地址类型为
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX 或 AF_LOCAL */
char sun_path[108]; /* pathname */
socket执行成功的话,返回一个文件描述符,失败的话返回 -1
2,int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
该方法用于对地址进行绑定,各参数的含义如下:
- sockfd:socket方法创建成功返回的文件描述符
- addr:地址,对于UNIX SOCKET传入上面sockaddr_un 类型
- addrlen:地址长度
bind执行成功返回0,失败返回 -1
4,UNIX SOCKET进程间通讯实战
服务端:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#define MY_SOCK_PATH "/dev/server-socket"
#define LISTEN_BACKLOG 50
int main(){
int result;
int listenfd,connfd;
struct sockaddr_un my_addr,peer_addr;
socklen_t peer_addr_size;
char buf[512];
listenfd = socket(AF_UNIX, SOCK_STREAM, 0);//1,创建套接字,注意传入的参数
if(listenfd < 0){
printf("socket error!\n");
return -1;
}
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strcpy(my_addr.sun_path, MY_SOCK_PATH);
socklen_t len = sizeof(my_addr.sun_family)+strlen(MY_SOCK_PATH);
unlink(MY_SOCK_PATH);
result = bind(listenfd,(struct sockaddr *)&my_addr,len);//2,绑定
if(result < 0){
printf("bind error!\n");
return -1;
}
printf("bind sucess!\n");
result = listen(listenfd, LISTEN_BACKLOG);//3,添加监听
if(result<0){
printf("listen error!\n");
return -1;
}
printf("listen....!\n");
while(1){
peer_addr_size = sizeof(struct sockaddr_un);
connfd = accept(listenfd, (struct sockaddr *) &peer_addr,&peer_addr_size);//,4,等待客户端连接,返回的是连接的客户端的文件描述符
if(connfd < 0){
printf("accept error!\n");
continue;
}
while(1){
memset(buf,0,sizeof(buf));
int len = read(connfd,buf,sizeof(buf));//从客户端读取数据
printf("server len:%d\n",len);
if(len < 0){
printf("read error!\n");
break;
}else if(len == 0){
printf("EOF!\n");
break;
}else{
buf[len] = '\n';
printf("server recive buf:%s\n",buf);
if(strncmp(buf,"quit",4) == 0){
break;
}else{
buf[0] = 'A';
write(connfd,buf,len);//把数据写给客户端
}
}
}
close(connfd);
}
close(listenfd);
return 0;
}
客户端:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#define MY_SOCK_PATH "/dev/server-socket"
int main(){
int socket_fd,result;
struct sockaddr_un my_addr;
char buf[512]={0};
socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);//1,创建socket
if(socket_fd<0){
printf("socket error!\n");
return -1;
}
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH,sizeof(my_addr.sun_path) - 1);
result = connect(socket_fd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr_un));//2,连接
if(result<0){
printf("connect error!\n");
return -1;
}
printf("please input buf:\n");
while(fgets(buf,sizeof(buf),stdin) != NULL){
write(socket_fd,buf,sizeof(buf));
int len = read(socket_fd,buf,sizeof(buf));
printf("read len:%d!\n",len);
if(len<=0){
printf("read error!\n");
break;
}else{
printf("client recive buf:%s\n",buf);
}
printf("please input buf:\n");
}
close(socket_fd);
return 0;
}
运行结果:
please input buf:
hjd
server len:512
server recive buf:hjd
read len:512!
client recive buf:Ajd
可以看到发送给服务端的buf,经过服务端的处理后(将首个字符变成A),返回给了客户端