【Linux学习笔记55】TCP服务器IO模型之非阻塞轮询

引言

之前都介绍了多线程,多进程的方式解决各种TCP服务器的问题。那么本篇笔记主要记录单进程非阻塞的方式处理TCP服务器的服务。使用的方法就是轮询的机制处理,虽然这种方法很少使用,因为其占用的CPU资源很多,但是还是很有必要了解一下。

各种模型的理解图

在这里插入图片描述

  • 第一种是前面笔记的多线程TCP服务端之简易QQ/多进程处理TCP服务器IO模型之并发阻塞处理多任务的方式
  • 第二种是本篇笔记的主要内容,单进程要处理多个任务,只能通过轮询的方式
  • 第三种是UDP专属的信号驱动模式UDP服务器IO模型之信号驱动,这种模式是依靠信号的,TCP任务太多,产生的信号也很多,因此不能使用。
  • 第四种是通过使用Poll 函数实现的TCP服务器多路复用的功能处理。

代码实现

server.c:

#include "head4sock.h"
#include "kernel_list.h"

typedef struct
{
	int fd ;
	struct list_head list;
}client;

client *new_cli(int fd)
{
	client *new = malloc(sizeof(client));
	if (new != NULL)
	{
		new->fd =fd ;
		INIT_LIST_HEAD(&new->list);
	}
	return new;
}

client *init_list(void)
{
	client *head = malloc(sizeof(client));
	if (head != NULL)
	{
		INIT_LIST_HEAD(&head ->list);
	}
	return head;
}

int main(int argc, char const *argv[])
{
	if(argc != 2)
	{
		printf("Usage: %s <PORT>\n", argv[0]);
		exit(0);
	}

	// 创建一个TCP套接字
	int fd = Socket(AF_INET, SOCK_STREAM, 0); //设为IPv4的套接字

	// 绑定地址(IP:PORT)
	struct sockaddr_in srvaddr, cliaddr;
	socklen_t len = sizeof(srvaddr);
	bzero(&srvaddr, len);

	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(atoi(argv[1]));
	// inet_pton(AF_INET, "192.168.1.166", &srvaddr.sin_addr);
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	Bind(fd, (struct sockaddr *)&srvaddr, len);

	// 设置监听套接字
	Listen(fd, 3); //如果同时有人发出请求,能够同时处理若干个,在Linux中至少同时允许4+3个连接请求

	long val =fcntl(fd,F_GETFL); //得到当前的IO状态
	val |= O_NONBLOCK;
	fcntl(fd,F_SETFL,val); //设置fd为非阻塞状态

	client * head =init_list();
	int connfd;
	while (1)
	{
		 connfd = accept(fd, (struct sockaddr *)&cliaddr, &len);

		 if (connfd > 0)
		 {
			long val =fcntl(connfd,F_GETFL); //得到当前的IO状态
		 	val |= O_NONBLOCK;
		 	fcntl(connfd,F_SETFL,val); //设置connfd为非阻塞状态

			char peeraddr[50];
 			bzero(peeraddr, 50);
 			printf("new connection: %s:%hu\n",  //打印端口号
 						inet_ntop(AF_INET, &cliaddr.sin_addr, peeraddr, 50),
 						ntohs(cliaddr.sin_port));

			client * new = new_cli(connfd); //为了更好利用资源,使用动态链表将套接字起来
			list_add_tail(&new->list,&head->list); //将新的节点添加到链表中
		 }

	char buf[SIZE];
	struct list_head *pos,*n;
	list_for_each_safe(pos,n,&head->list)
	{
		client *tmp = list_entry(pos,client,list);
		bzero(buf,SIZE);
		int nread;
		if((nread=read(tmp->fd,buf,SIZE))==0)
		{
			list_del(pos);
			free(tmp);
		}
		else if(nread >0)  //此时有数据
		{
			printf("%s",buf );
		}
	}
}
}

client .c :

与上一篇一样

代码运行结果:

在这里插入图片描述
从图中可以看到 server占用的CPU资源比较多,效率比较低,非阻塞模型的轮询机制一般不采用。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值