IO多路复用

步骤:

1、首先我们需要创建一张文件描述符集合表

  fd_set stFdr;//大小为1024字符

  FD_ZERO(&stFdr);//初始化集合表将表全置为0

2、 然后将我们打开的文件的文件描述符添加到这张表里面

  FD_SET(n, &stFdr);//将文件描述符加入列表

3、 用select()函数监听所有通道情况,集合表里面的所有通道没有响应的话就阻塞(在最后一个参数置为NULL的时候阻塞生效)有响应的话将该通道对应的集合表对应的bit位置1,然后返回有响应的通道个数。

  //函数功能:将有响应的置为1,若没有响应的就阻塞

  //参数1:n+1是最大监控多少个从0开始算

  //  一般是文件描述符中最大的那个+1

  //参数2:所有要读的文件文件描述符的集合

  //参数3:所有要写的文件文件描述符的集合

  //参数4:其他文件描述符的集合

  //参数5:超时设置,若为NULL则表示阻塞。

  // 置为0的话只检测文件描述符的状态

  // 非0的话在指定时间内监听,若在规定时间内没有响应则超时返回

  //返回值:返回响应的数量

  int ret = select(n+1, &stFdr,NULL,NULL,NULL);

  if(ret <= 0)

  {

    continue;//不跳出循环继续执行

  }

4、  当有响应的时候通过FD_ISSET()函数来判断是哪些通道的响应,进而执行某些对应的数据操作;

  //函数功能:判断某一个通道的状态是否有响应

  //参数1:文件描述符,

  //参数2:描述符集合表地址;

  //返回值:若有响应则返回1,没有返回0

  FD_ISSET(n, &stFdr);

5、执行对应文件操作;

多路复用案例:

tcp.c

#include "tcp.h"


//服务器套接字初始化
//三个参数分别为IP、端口号、允许最大连接
int tcp_server_init(char *ip, int port, int backlog)
{
    //创建套接字文件打通软件和硬件的关节
    int skt = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == skt)
    {
        printf("socker error\n");
        return -1;
    }
    //在一个端口号和IP绑定多个socket
    int on = 1;
    setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));    
    //将IP和端口号存入结构体
    struct sockaddr_in sddr;
    sddr.sin_family         = AF_INET;
    sddr.sin_port           = htons(port);
    sddr.sin_addr.s_addr    = inet_addr(ip);
    //将套接字和IP、端口号进行绑定
    int ret = bind(skt, (struct sockaddr *)&sddr, sizeof(sddr));
    if(-1 == ret)
    {
        printf("bind error\n");
        return -1;
    }
    //监听套接字并设置最大链接数量
    ret = listen(skt, backlog);
    if(-1 == ret)
    {
        printf("listen error\n");
        return -1;
    }
    puts("listen....");
    return skt;
}
//服务器连接函数
//参数是打开的套接字文件描述符
int tcp_server_connect(int skt)
{
    struct sockaddr_in cddr;
    int len = sizeof(cddr);            
    int nfd = accept(skt, (void *)&cddr, &len);
    /*if(-1 == nfd)
    {
        perror("accept error\n");
        return -1;
    }*/
    return nfd;
}
//客户端连接函数
//两个参数分别为IP、端口号
int tcp_app_connect(char *ip, int port)
{
    //创建套接字
    int skt = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == skt)
    {
        printf("socket error\n");
        return -1;
    }
    //将IP、端口号存入结构体
    struct sockaddr_in sddr;
    sddr.sin_family         = AF_INET;
    sddr.sin_port           = htons(port);
    sddr.sin_addr.s_addr    = inet_addr(ip);
    //绑定
    int ret = connect(skt, (struct sockaddr *)&sddr, sizeof(sddr));
    if(-1 == ret)
    {
        printf("connect error\n");
        return -1;
    }
    return skt;
}

tcp.h

#ifndef _TCP_H
#define _TCP_H

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

#include <arpa/inet.h>


#define N 10

//服务器套接字初始化
//三个参数分别为IP、端口号、允许最大连接
int tcp_server_init(char *ip, int port, int backlog);
//服务器连接函数
//参数是打开的套接字文件描述符
int tcp_server_connect(int skt);
//客户端连接函数
//两个参数分别为IP、端口号
int tcp_app_connect(char *ip, int port);



#endif

server.c

#include "tcp.h"

int main(void)
{
    int skt = tcp_server_init("0.0.0.0", 8888, 10);
    
    //创建一张文件描述符集合表
    fd_set table;
    //清空表
    FD_ZERO(&table);
    //将skt加入表
    FD_SET(skt, &table);
    //监听最大值
    int max = skt;
    int nfd = 0;
    int ret = 0;
    int i;
    char buf[N] = {'\0'};
    
    while(1)
    {
        fd_set tableTmp = table;
        ret = select(max+1, &tableTmp, NULL, NULL, NULL);
        if(ret <= 0)
        {
            continue;
        }
        
        for(i = 0; i < max+1; i++)
        {
            //判断是哪路响应
            if(FD_ISSET(i, &tableTmp))
            {
                printf("%d号通道响应\n",i);
                //判断是不是socket通道响应
                if(i == skt)
                {    
                    //如果是,再开辟一条软通道传输数据
                    nfd = tcp_server_connect(skt);
                    if(nfd < 0)
                    {
                        continue;
                    }
                    printf("%d号通道被开通!\n",nfd);
                    //将开通的通道加到真实表中去
                    FD_SET(nfd, &table);
                    if(max < nfd)
                    {
                        max = nfd;
                    }
                }
                else
                {
                    //若不是socket通道响应则读取数据
                    //ret = read(i,buf,N);//不能用~~
                    ret = recv(i,buf,N,0);
                    if(ret > 0)
                    {
                        //对读取到的数据做处理
                        puts(buf);
                            //write(nfd,buf,N);//不能用~~
                            send(i,buf,N,0);
                    }
                    else
                    {
                        printf("%d号通道关闭\n",i);
                        //若读取到的数据为空则关闭通道
                        close(i);
                        FD_CLR(i, &table);
                    }
                        
                }
            }
        }
    }
    close(skt);
    return 0;
}

app.c

#include "tcp.h"


int main(void)
{
    int skt = tcp_app_connect("192.168.4.8", 8888);
    char buf[N] = {'\0'};
    while(1)
    {
        fgets(buf,N,stdin);
        write(skt,buf,N);
        read(skt,buf,N);
            puts(buf);
    }
    close(skt);
    return 0;
}

 

posted @ 2022-04-07 08:46  西北小蚂蚁  阅读(44)  评论(0编辑  收藏  举报