I/O多路转接模型

在这种模型下,如果请求的I/O操作阻塞,且它不是真正阻塞I/O,而是让其中的一个函数等待,在这期间,I/O还能进行其他操作。select()和poll()就属于这种模型。

下面根据该模型一步步创建双管道聊天窗口机制:

首先用mkfifo创建管道文件作为传入参数。

Makefile:

SRCS:=$(wildcard *.c)
ELFS:=$(SRCS:%.c=%)
all:$(ELFS)
    @for i in $(ELFS);do gcc -o $${i} $${i}.c;done
clean:
    rm -rf $(ELFS)
  • 单管道:一端只读,一端只写,读端获取写端数据

read_pipe.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd = open(argv[1], O_RDONLY);
    ERROR_CHECK(fd, -1, "open");
    printf("read fd = %d\n", fd);
    char buf[128] = {0};
    read(fd, buf, sizeof(buf));
    printf("buf = %s\n", buf);
    return 0;
}

write_pipe.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd = open(argv[1], O_WRONLY);
    ERROR_CHECK(fd, -1, "open");
    printf("write fd = %d\n", fd);
    sleep(3);
    write(fd, "hello", 5);
    return 0;
}
  • 双管道模型

read_pipe.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdr = open(argv[1], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    int fdw = open(argv[2], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    printf("chat1 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    read(fdr, buf, sizeof(buf));
    printf("buf = %s\n", buf);
    write(fdw, "I am chat1",10);
    return 0;
}

write_pipe.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdw = open(argv[1], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    int fdr = open(argv[2], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    printf("chat2 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    write(fdw, "I am chat2 ",10);
    read(fdr, buf, sizeof(buf));
    printf("buf = %s\n", buf);
    return 0;
}

若写端顺序和读端顺序一样会造成死锁,写端必须先写再读,读端先读再写。

  • 同步聊天模型

chat1.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdr = open(argv[1], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    int fdw = open(argv[2], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    printf("chat1 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        read(fdr, buf, sizeof(buf));
        printf("%s\n", buf);
        memset(buf, 0, sizeof(buf));
        read(0, buf, sizeof(buf)); 
        write(fdw, buf, strlen(buf)-1);
    }
    return 0;
}

chat2.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdw = open(argv[1], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    int fdr = open(argv[2], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    printf("chat2 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        read(0, buf, sizeof(buf));
        write(fdw, buf, strlen(buf)-1);
        memset(buf, 0, sizeof(buf));
        read(fdr, buf, sizeof(buf));
        printf("%s\n", buf);
    }
    return 0;
}

这个模型还有个问题,必须一人说一句,但在实际聊天过程中肯定不是这样的,继续改进。

  • 异步聊天模型

#include <sys/select.h>

int select( int nfds, fd_set FAR* readfds, fd_set * writefds, fd_set * exceptfds, const struct timeval * timeout);

nfds:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。

readfds:(可选)指针,指向一组等待可读性检查的套接口。

writefds:(可选)指针,指向一组等待可写性检查的套接口。

exceptfds:(可选)指针,指向一组等待错误检查的套接口。

timeout:select()最多等待时间,对阻塞操作则为NULL。

chat1.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdr = open(argv[1], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    int fdw = open(argv[2], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    printf("chat1 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    fd_set rdset;
    int ret;
    while(1)
    {
        FD_ZERO(&rdset);
        FD_SET(STDIN_FILENO, &rdset);
        FD_SET(fdr, &rdset);
        ret = select(fdr + 1, &rdset, NULL, NULL, NULL);
        if(ret > 0)
        {
            if(FD_ISSET(fdr, &rdset))
            {
                memset(buf, 0, sizeof(buf));
                ret = read(fdr, buf, sizeof(buf));
                if(ret == 0) 
                {
                    printf("byebye!\n");
                    break;
                }
                printf("%s\n", buf);
            }
            if(FD_ISSET(0, &rdset))
            {
                memset(buf, 0, sizeof(buf));
                ret = read(0, buf, sizeof(buf)); 
                if(ret == 0) 
                {
                    printf("byebye!\n");
                    break;
                }
                write(fdw, buf, strlen(buf)-1);
            }   
        }
    }
    return 0;
}

chat2.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 3);
    int fdw = open(argv[1], O_WRONLY);
    ERROR_CHECK(fdw, -1, "open");
    int fdr = open(argv[2], O_RDONLY);
    ERROR_CHECK(fdr, -1, "open");
    printf("chat2 fdr = %d, fdw = %d\n", fdr, fdw);
    char buf[128] = {0};
    int ret;
    fd_set rdset;
    while(1)
    {
        FD_ZERO(&rdset);
        FD_SET(STDIN_FILENO, &rdset);
        FD_SET(fdr, &rdset);
        ret = select(fdr + 1, &rdset, NULL, NULL, NULL);
        if(ret > 0)
        {
            if(FD_ISSET(fdr, &rdset))
            {
                memset(buf, 0,sizeof(buf));
                ret = read(fdr, buf, sizeof(buf));
                if(ret == 0)
                {
                    printf("byebye!\n");
                    break;
                }
                printf("%s\n", buf);
            }
            if(FD_ISSET(0, &rdset))
            {
                memset(buf, 0, sizeof(buf));
                ret = read(0, buf, sizeof(buf));
                if(ret == 0)
                {
                    printf("byebye!\n");
                    break;
                }
                write(fdw, buf, strlen(buf) - 1);
            }
        }
    }
    return 0;
}

效果图:

猜你喜欢

转载自www.cnblogs.com/Mered1th/p/10703634.html