目录
1、Unix域协议
2、多路复用
select
poll / epol
谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注
没错,说的就是你,不用再怀疑!!!
希望我的文章内容能对你有帮助,一起努力吧!!!
1、Unix域协议
Unix域协议是一种 IPC 通信的方式,利用 Socket 进行进程间的通信
利用 Socket 编程接口来实现进行本地进程间的通信
Unix有自己的协议簇:
- Unix域协议:
- AF_UNIX / AF_LOCAL
- Socket 套接字
- SOCK_DGRAM 数据报套接字 UDP
- SOCK_STRTEAM 流式套接字 TCP
- Unix域协议,编程接口和流程同 IPV4 协议簇一样,只不过Unix协议网络地址
下面是一个小例子:
Unix_recv:
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <cstring>
#include <unistd.h>
#define UNIX_PATH ("/home/thirteen/unix.socket")
int main()
{
// 创建套接字
int sock = socket(AF_UNIX,SOCK_STREAM,0);
if(sock == -1)
return -1;
// 绑定地址
struct sockaddr_un remote;
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path,UNIX_PATH);
// 连接
if(connect(sock,(struct sockaddr*)&remote,sizeof(remote)) == -1)
{
close(sock);
return -1;
}
// 通信
while(1)
{
char buf[1024]={0};
if(recv(sock,buf,1024,0) == -1&&(std::string(buf) == "exit"))
break;
std::cout << "来自其他进程的消息:" << buf << std::endl;
}
close(sock);
return 0;
}
unix_send:
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <cstring>
#include <unistd.h>
#define UNIX_PATH ("/home/thirteen/unix.socket")
int main()
{
// 创建套接字
int sock = socket(AF_UNIX,SOCK_STREAM,0);
if(sock == -1)
return -1;
// 绑定地址
struct sockaddr_un unix_infor;
unix_infor.sun_family = AF_UNIX;
strcpy(unix_infor.sun_path,UNIX_PATH);
if(bind(sock,(struct sockaddr*)&unix_infor,sizeof(unix_infor)) == -1)
{
close(sock);
return -1;
}
// 监听一下
if(listen(sock,10) == -1)
{
close(sock);
return -1;
}
// 等待连接
int sock_s = -1;
while(1)
{
struct sockaddr_un client;
socklen_t client_size = sizeof(client);
sock_s = accept(sock,(struct sockaddr*)&client,&client_size);
if(sock_s != -1)
break;
}
// 通信
while(1)
{
char buf[1024]={0};
std::cout << "请输入消息:";
std::cin >> buf;
send(sock_s,buf,strlen(buf),0);
if(std::string(buf) == "exit")
break;
}
close(sock_s);
close(sock);
return 0;
}
2、多路复用
多路复用:主要就是同时监听多个文件描述符是否就绪( readable / writeable / error )
阻塞IO
- 读
- 没有数据可以读的时候,类似 read 的函数,会阻塞( wait )直到有数据可以读了,或者说 出错了。
- 写
- 没有空间可以写的时候,类似 write 的函数,会阻塞,直到可以写或则是出错了,有空间就 写。
是内核默认一种 IO 方式,也是一种最简单的方式。
多路复用
-
select
- select 的实现是在内核中开辟了一个内核线程去实现的
- 同时监听,“ 轮询 ” :轮流询问 文件描述符
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
int main()
{
int fd = open("1.txt",O_RDWR);
if(fd == -1)
return -1;
fd_set rfds;
FD_SET(fd,&rfds);
struct timeval tm;
tm.tv_sec = 1;
tm.tv_usec = 0;
if(select(fd+1,&rfds,nullptr,nullptr,&tm) <= 0)
{
close(fd);
return -1;
}
if(FD_ISSET(fd,&rfds))
std::cout << "可以读" << std::endl;
}
-
poll / epoll
- poll 的功能和select类似,“ 监听多个文件描述符 ” 是否就绪,只不过 poll 用一个结构体 struct pollfd 来描述发 " 监听请求 "
- 监听一个文件描述符,就需要一个 struct pollfd 结构体,监听多个文件描述符就需要多个 struct pollfd 结构体
-
#include <sys/poll.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> int main() { int fd = open("1.txt",O_RDWR); if(fd == -1) return -1; struct pollfd rfds[1]; rfds[0].events = POLLIN|POLLOUT; // 读事件 rfds[0].fd = fd; // 需要监听的文件描述符 struct timeval tm; tm.tv_sec = 1; tm.tv_usec = 0; if(poll(rfds,1,1) <= 0) { close(fd); return -1; } if(rfds[0].revents & POLLIN) { std::cout << "读就绪" << std::endl; } else std::cout << "读未就绪" << std::endl; close(fd); }
- epoll_create :创建一个监听文件的集合
- epoll_ctl :设置监听事件
- epoll_wait : 用来等待监听事件的发生的
epoll 相对而言在文件描述符很多的情况下,效率要比 select 和 poll 要高
epoll 支持ET
epoll 和 poll 和 select 的区别, epoll 不会去检测无意义的文件描述符
#include <sys/epoll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
int main()
{
int fd = open("epoll.cpp",O_RDWR);
if(fd == -1)
return -1;
int epoll = epoll_create(1);
if(epoll == -1)
{
close(fd);
return -1;
}
std::cout << "epoll创建成功" <<std::endl;
struct epoll_event event;
event.events = EPOLLIN | EPOLLOUT;
// event.data.fd = fd;
if(epoll_ctl(epoll,EPOLL_CTL_ADD,fd,&event) == -1)
{
perror("设置出错了");
close(fd);
return -1;
}
std::cout << "epoll设置成功" <<std::endl;
struct epoll_event events={0};
if(epoll_wait(epoll,&events,1,1000) == 0)
{
close(fd);
return -1;
}
else
{
}
if(events.events & EPOLLIN)
std::cout << "读就绪" << std::endl;
else
std::cout << "读未就绪" << std::endl;
}