目录
0x01 本地套接字实现流程
0x02 程序实现
客户端代码实现
服务端代码实现
对于之前学习的TCP/IP、UDP协议等,这些都是网络套接字通信,它同样也可以实现进程间的通信,只不过是面向不同主机的进程间的通信,其实就是网络通信,但是本地套接字是用于本地的进程间的通信,其可以实现:
有关系的进程间的通信。
没有关系的进程间的通信。
本地套接字实现流程和网络套接字类似,一般使用TCP进行通信,其流程主要如下:
对于服务端:
创建监听套接字
int lfd = socket(AF_UNIX/AF_LOCAL, SOCK_STREAM, 0);
监听的套接字绑定本地的套接字文件(对标内核缓冲区中的文件,是个伪文件)
// 使用结构体
#include
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; // 地址族协议 af_local
char sun_path[UNIX_PATH_MAX];
};
struct sockaddr_un addr; // 绑定成功之后,指定的sun_path中的套接字文件会自动生成。 bind(lfd, addr, len);
监听
listen(lfd,100);
等待并接受连接请求
struct sockaddr_un cliaddr; int cfd = accept(lfd, &cliaddr, len);
通信
接收数据:read/recv
发送数据:write/send
关闭连接:close()
对于客户端:
创建通信的套接字 int fd = socket(AF_UNIX/AF_LOCAL, SOCK_STREAM, 0);
监听的套接字绑定本地的IP 端口 struct sockaddr_un addr; // 绑定成功之后,指定的sun_path中的套接字文件会自动生成。 bind(lfd, addr, len);
连接服务器 struct sockaddr_un serveraddr; connect(fd, &serveraddr, sizeof(serveraddr));
通信 接收数据:read/recv 发送数据:write/send
关闭连接 close();
#include
#include
#include
#include
#include
#include
int main() {
unlink("client.sock");
// 1.创建套接字
int cfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if(cfd == -1) {
perror("socket");
exit(-1);
}
// 2.绑定本地套接字文件
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, "client.sock");
int ret = bind(cfd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
// 3.连接服务器
struct sockaddr_un seraddr;
seraddr.sun_family = AF_LOCAL;
strcpy(seraddr.sun_path, "server.sock");
ret = connect(cfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
if(ret == -1) {
perror("connect");
exit(-1);
}
// 4.通信
int num = 0;
while(1) {
// 发送数据
char buf[128];
sprintf(buf, "hello, i am client %d\n", num++);
send(cfd, buf, strlen(buf) + 1, 0);
printf("client say : %s\n", buf);
// 接收数据
int len = recv(cfd, buf, sizeof(buf), 0);
if(len == -1) {
perror("recv");
exit(-1);
} else if(len == 0) {
printf("server closed....\n");
break;
} else if(len > 0) {
printf("server say : %s\n", buf);
}
sleep(1);
}
close(cfd);
return 0;
}
#include
#include
#include
#include
#include
#include
int main() {
//在运行前删除某个文件
unlink("server.sock");
// 1.创建监听的套接字
int lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if(lfd == -1) {
perror("socket");
exit(-1);
}
// 2.绑定本地套接字文件
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, "server.sock");
//绑定成功会生成对应文件在目录下
int ret = bind(lfd, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) {
perror("bind");
exit(-1);
}
// 3.监听
ret = listen(lfd, 100);
if(ret == -1) {
perror("listen");
exit(-1);
}
// 4.等待客户端连接
struct sockaddr_un cliaddr;
int len = sizeof(cliaddr);
int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
if(cfd == -1) {
perror("accept");
exit(-1);
}
printf("client socket filename: %s\n", cliaddr.sun_path);
// 5.通信
while(1) {
char buf[128];
int len = recv(cfd, buf, sizeof(buf), 0);
if(len == -1) {
perror("recv");
exit(-1);
} else if(len == 0) {
printf("client closed....\n");
break;
} else if(len > 0) {
printf("client say : %s\n", buf);
send(cfd, buf, len, 0);
}
}
close(cfd);
close(lfd);
return 0;
}
可以理解为他们的通信其实就是绑定对应的文件,如果遇到关闭服务端、客户端时,又想绑定却遇到服务端、客户端在被占用的情况,这个时候可以将目录下的.sock
文件删除,也可以在程序前对文件进行删除,使用函数unlink
。