浅谈【网络编程】之Unix与多路复用

目录

1、Unix域协议

2、多路复用

select

[poll / epol](#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:

cpp 复制代码
#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:

cpp 复制代码
#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 的实现是在内核中开辟了一个内核线程去实现的
    • 同时监听," 轮询 " :轮流询问 文件描述符
cpp 复制代码
/* 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 结构体
复制代码
```cpp
#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 不会去检测无意义的文件描述符

cpp 复制代码
#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;    
}
相关推荐
444A4E6 分钟前
深入Linux进程优先级:Nice值与O(1)调度器原理
linux·操作系统
dustcell.6 分钟前
Cisco Packer Tracer 综合实验
网络
Jooolin6 分钟前
【编程史】Git是如何诞生的?这可并非计划之中...
linux·git·ai编程
云边有个稻草人10 分钟前
【Linux系统】第八节—进程概念(上)—冯诺依曼体系结构+操作系统+进程及进程状态+僵尸进程—详解!
linux·进程·冯诺依曼体系结构·pcb·僵尸进程·进程的状态·task_ struct
xian0gang20 分钟前
rk3588 区分两个相同的usb相机
linux
Unpredictable22223 分钟前
【VINS-Mono算法深度解析:边缘化策略、初始化与关键技术】
c++·笔记·算法·ubuntu·计算机视觉
这儿有一堆花30 分钟前
安全访问家中 Linux 服务器的远程方案 —— 专为单用户场景设计
linux·服务器·安全
RussellFans1 小时前
Linux 文本三剑客(grep, awk, sed)
linux·运维·服务器
PingdiGuo_guo1 小时前
C++智能指针的知识!
开发语言·c++
Chuncheng's blog1 小时前
CentOS 7如何编译安装升级gcc至7.5版本?
linux·运维·c++·centos