1. 本地套接字
socket API原本为网络通信而设计,后来在其基础上扩展出本地套接字机制用于本地进程间通信。
本地套接字为全双工通信方式。
2. 本地套接字的使用
本地套接字通信步骤
(1)创建本地socket
本地套接字使用文件来标识,该文件在绑定之前不能存在,因为会自动创建。
(2)绑定
(3)监听
(4)提取
(5)读写
(6)关闭
创建本地套接字API
(1)socket创建本地套接字
int socket(int domain, int type, int protocol);
/*
参数:
domain:AF_UNIX
type:SOCK_STREAM 或 SOCK_DGRAM
protocol:0
返回值:
成功:文件描述符
失败:-1
*/
(2)bind绑定
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
/*
参数:
sockfd:本地套接字文件描述符;
addr:本地套接字结构体;
#include<sys/un.h>
struct sockaddr_un {
sa_family sun_family; // 直接写AF_UNIX
char sun_path[108]; // 文件路径名
}
addrlen:本地套接字结构体长度
*/
3. 本地套接字实现TCP通信
服务器端:
#include<stdio.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<string.h>
#include<stddef.h>
#include<unistd.h>
/*本地套接字实现TCP服务器*/
int main(int argc, const char* argv[]) {
unlink("sock.s");
// 1.创建本地流式套接字
int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
// 2.绑定
struct sockaddr_un myaddr;
myaddr.sun_family = AF_UNIX;
strcpy(myaddr.sun_path, "sock.s");
int len = offsetof(struct sockaddr_un, sun_path) + strlen(myaddr.sun_path);
bind(lfd, (struct sockaddr*)&myaddr, len);
// 3.监听
listen(lfd, 128);
// 4.提取
struct sockaddr_un cliaddr;
socklen_t len_c = sizeof(cliaddr);
int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len_c);
printf("new client filepath: %s\n", cliaddr.sun_path);
// 5.读写
char buf[1500] = "";
while (1) {
int n = recv(cfd, buf, 1500, 0);
if (n < 0) {
printf("err or closed.\n");
break;
} else {
printf("%s\n", buf);
send(cfd, buf, n, 0);
}
}
// 6.关闭
close(cfd);
close(lfd);
return 0;
}
使用nc命令测试的运行结果:
注意:客户端可以隐式绑定,但服务器不可以。因为nc命令为隐式绑定,因此该结果无法打印文件路径。
客户端:
#include<stdio.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<stddef.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
int main(int argc, const char* argv[]) {
unlink("sock.c");
// 1.创建本地流式套接字
int cfd = socket(AF_UNIX, SOCK_STREAM, 0);
// 2.绑定。若客户端不绑定,则为隐式绑定
struct sockaddr_un myaddr;
myaddr.sun_family = AF_UNIX;
strcpy(myaddr.sun_path, "sock.c");
if (bind(cfd, (struct sockaddr*)&myaddr, sizeof(myaddr)) < 0) {
perror("bind");
return 1;
}
// 2.连接
struct sockaddr_un servaddr;
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, "sock.s");
connect(cfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
// 3.读写
while (1) {
char buf[1500] = "";
int n = read(STDIN_FILENO, buf, 1500);
send(cfd, buf, n, 0);
memset(buf, 0, 1500);
n = recv(cfd, buf, 1500, 0);
if (n <= 0) {
printf("err or closed.\n");
break;
} else {
printf("%s\n", buf);
}
}
// 4.关闭
close(cfd);
return 0;
}
客户端、服务端通信,运行结果: