进程间通信
PIPE FIFO 实现简单
mmap 非血缘关系进程间
信号 开销小
domain 稳定性最好
本地套接字
1、文件格式:pipe 、fifo
2、本地套接字s-->伪文件
3、服务端流程
创建套接字:lfd = socket(AF_UNIX, SOCK_STREAM,0)
绑定:
struct sockaddr_un serv;
serv.sun_famliy = AF_UNIX;
strcpy(serv.sun_path, "server.socket");现在还未创建
bind(lfd, (struct sockaddr*)&serv, len); 绑定成功则创建server.socket文件
设置监听
listen()
等待接收连接请求
struct sockaddt_un client;
int cfd = accept(lfd, &client, &len);
通信
send()
recv()
断开连接
close()
4、客户端流程
①创建套接字:fd = socket(AF_UNIX, SOCK_STREAM,0)
②绑定:
struct sockaddr_un client;
serv.sun_famliy = AF_UNIX;
strcpy(serv.sun_path, "client.socket");现在还未创建
bind(lfd, (struct sockaddr*)&client, len); 绑定成功则创建client.socket文件
③连接服务器
struct sockaddr_un serv;
serv.sun_family=AF_UNIX;
strcpy(serv.sun_path, "server.socket");现在还未创建
connect(fd, &serv, sizeof(server));
④通信
recv
send
⑤关闭
close
本地套接字和网络套接字
头文件:sys/un.h
#define UNIX_PATH_MAX 128
struct sockaddr_un{
__kernel_sa_family_t sun_famliy;
char sun_pathname[UNIX_PATH_MAX];
};
服务编程流程:
①创建套接字 int lfd = sockfd(AF_UNIX, SOCK_STREAM, 0);
②绑定:
struct sockaddr_un server;
server.sun_family = AF_LOCAL;
strcpy(server.sun_path, "/tmp/server.socket");
bind(lfd, (struct sockaddr)&server, len);
③设置监听
listen()
④等待接收请求
int cfd=accetp(lfd, &client, &len);
UNIX Domain Socket的特点
1.UNIX Domain Socket为什么比TCP/IP在本地上通信更加快
因为UNIX Domain Socket不经过网络协议栈 / 不需要打包拆包 / 计算校验和 / 维护序号和应答,只是将应用层数据从一个进程拷贝到另一个进程
2.UNIX Domain Socket也提供面向流和面向数据包的两种API接口,类似于TCP和UDP,但是面向消息的 UNIX Domain Socket也是可靠的,消息既不会丢失也不会失序。
3.全双工
4.目前UNIX Domain Socket已经成为最广泛的IPC机制
4.常用API
1)用于创建类似于无名管道(pipe)的本地套接字
int socketpair(int domain, int type, int protocol, int sv[2]);
2)当不再需要这个 Unix 域套接字时,应删除路径名对应的文件
int unlink(const char *pathname);
int remove(const char *pathname);
注意,如果是抽象路径名,就不需要在使用完本地套接字后手动删除对应的套接字文件,因为当本地套接字被关闭之后,内核会自动删除这个抽象名。
3)获取本地套接字的地址信息
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
客户端3.c
客户端3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <stddef.h>
int main(void)
{
int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
struct sockaddr_un client;
client.sun_family = AF_LOCAL;
strcpy(client.sun_path, "client.sock");
bind(fd, (struct sockaddr *)&client, sizeof(client));
//初始化server信息
struct sockaddr_un serv;
serv.sun_family = AF_LOCAL;
strcpy(serv.sun_path, "serv.sock");
//连接服务器
connect(fd, (struct sockaddr*)&serv, sizeof(serv));
while(1)
{
char buf[1024]={0};
fgets(buf, sizeof(buf), stdin);
send(fd, buf, strlen(buf)+1, 0);
recv(fd, buf, sizeof(buf), 0);
printf("recv buff:%s\n", buf);
}
close(fd)
return 0;
}
服务段3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <stddef.h>
int main(void)
{
//创建
int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
//绑定
struct sockaddr_un serv;
serv.sun_family = AF_UNIX;
strcpy(serv.sun_path, "socket.server");
bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
//监听
listen(lfd, 36);
//等待连接请求
struct sockaddr_un client;
socklen_t len = sizeof(client);
int cfd = accept(lfd, (struct sockaddr*)&client, &len);
//通信
while(1)
{
char buf[1024] = {0};
int recvlen = recv(cfd, buf, sizeof(buf), 0);
send(cfd, buf, recvlen, 0);
}
close(cfd);
close(lfd);
return 0;
}
TCP(字节流套接字)
【unixstr_cli.c】
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIXSTR_PATH "/tmp/unix.str"
#define LISTENQ 5
#define BUFFER_SIZE 256
int main(void)
{
int sockfd;
struct sockaddr_un servaddr;
sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXSTR_PATH);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
char buf[BUFFER_SIZE];
while(1)
{
bzero(buf, sizeof(BUFFER_SIZE));
printf(">> ");
if(fgets(buf, BUFFER_SIZE, stdin) == NULL)
{
break;
}
write(sockfd, buf, strlen(buf));
}
close(sockfd);
return 0;
}
【unixstr_serv.c】
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIXSTR_PATH "/tmp/unix.str"
#define LISTENQ 5
#define BUFFER_SIZE 256
int main(void)
{
int listenfd, connfd;
socklen_t len;
struct sockaddr_un servaddr, cliaddr;
if(-1 == (listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)))
{
perror("socket");
exit(EXIT_FAILURE);
}
unlink(UNIXSTR_PATH);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXSTR_PATH);
if(-1 == bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
{
perror("bind");
exit(EXIT_FAILURE);
}
listen(listenfd, LISTENQ);
len = sizeof(cliaddr);
if(-1 == (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len)))
{
perror("accept");
exit(EXIT_FAILURE);
}
char buf[BUFFER_SIZE];
while(1)
{
bzero(buf, sizeof(buf));
if(read(connfd, buf, BUFFER_SIZE) == 0) break;
printf("Receive: %s", buf);
}
close(listenfd);
close(connfd);
unlink(UNIXSTR_PATH);
return 0;
}
服务器2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <stddef.h>
#define SERV_ADDR "serv.socket"
#define offsetof(type, member) ((int)&((type *)0)->MEMBER)
int main(void)
{
int lfd, cfd, len, size, i;
struct sockaddr_un, servaddr, clieaddr;
char buff[4096];
lfd = socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, SERV_ADDR);
/*计算成员sun_path在结构体中sockaddr_un中的偏移量*/
len=offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
unlink(SERV_ADDR);
bind(lfd, (struct sockaddr *)&servaddr, len);
listen(lfd, 20);
printf("Accept ...\n");
while(1)
{
len=sizeof(cliaddr);
cfd=accept(lfd, (struct sockaddr*)&cliaddr, (socklen_t *)&len);
len -=offsetof(struct sockaddr_un, sun_path);
cliaddr.sun_path[len]='\0';
printf("client bind filename %s\n", cliaddr.sun_path);
while((size = read(cfd, buf, sizeof(buf))) > 0)
{
for(i =0; i<size; i++)
buf[i]=toupper(buf[i]);
write(cfd, buf, size);
}
close(cfd);
}
close(lfd);
return 0;
}
客户端2.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/inet.h>
#include <stddef.h>
#define SERV_ADDR "serv.socket"
#define CLIE_ADDR "clie.socket"
int main(void)
{
int cfd, len;
struct sockaddr_un servaddr,cliaddr;
char buf[4096];
cfd=socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sun_family = AF_UNIX;
strcpy(cliaddr.sun_path, CLIE_ADDR);
/*本地套接字为什么需要绑定??不需要吧*/
len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);
unlink(CLIE_ADDR);
bind(cfd, (struct sockaddr *)&cliaddr, len);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family=AF_UNIX;
strcpy(servaddr.sun_path, SERV_ADDR);
len=offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
connet(cfd, (struct sockaddr *)&servaddr, len);
while(fgets(buf, sizeof(buf), stdin) != NULL)
{
write(cfd, buf, strlen(buf));
len = read(cfd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, len);
}
close(cfd);
return 0;
}