Linux系统编程——I/O多路转接模型之select

在这种模型下,如果请求的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
", fd);
	char buf[128] = {0};
	read(fd, buf, sizeof(buf));
	printf("buf = %s
", 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
", 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
", fdr, fdw);
	char buf[128] = {0};
	read(fdr, buf, sizeof(buf));
	printf("buf = %s
", 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
", fdr, fdw);
	char buf[128] = {0};
	write(fdw, "I am chat2 ",10);
	read(fdr, buf, sizeof(buf));
	printf("buf = %s
", 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
", fdr, fdw);
	char buf[128] = {0};
	while(1)
	{
		memset(buf, 0, sizeof(buf));
		read(fdr, buf, sizeof(buf));
		printf("%s
", 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
", 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
", 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
", 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!
");
					break;
				}
				printf("%s
", buf);
			}
			if(FD_ISSET(0, &rdset))
			{
				memset(buf, 0, sizeof(buf));
				ret = read(0, buf, sizeof(buf)); 
				if(ret == 0) 
				{
					printf("byebye!
");
					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
", 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!
");
					break;
				}
				printf("%s
", buf);
			}
			if(FD_ISSET(0, &rdset))
			{
				memset(buf, 0, sizeof(buf));
				ret = read(0, buf, sizeof(buf));
				if(ret == 0)
				{
					printf("byebye!
");
					break;
				}
				write(fdw, buf, strlen(buf) - 1);
			}
		}
	}
	return 0;
}

效果图:

原文地址:https://www.cnblogs.com/Mered1th/p/10703634.html