IO多路复用练习

这篇具有很好参考价值的文章主要介绍了IO多路复用练习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、通过select搭建TCP服务器

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#define PORT 8808
#define IP "192.168.122.92"

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd < 0)
	{
		perror("socket");
		fprintf(stderr,"socket failed __%d__\n",__LINE__);
		return -1;
	}
	printf("socket success...\n");

	//设置允许端口号复用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)  
	{
		perror("setsockopt");
		return -1;
	}

	//填充地址信息结构体,真是的地址信息结构体根据地址族制定
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);

	//绑定服务器IP和端口号
	if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("bind");
		fprintf(stderr,"bind failed __%d__\n",__LINE__);
		return -1;
	}
	printf("bind success...\n");

	//将套接字设置为被动监听状态
	if(listen(sfd,10) < 0)
	{
		perror("listen");
		return -1;
	}
	printf("listen success...\n");

	//从已完成连接的队列中获取一个客户信息,生成一个新的文件描述符,该文件描述符才是与客户端通信的文件描述符
	struct sockaddr_in cin[1021];
	socklen_t addrlen = sizeof(cin);
	int s_res = -1;
	fd_set readfds;
	fd_set tempfds;
	FD_ZERO(&readfds);
	FD_ZERO(&tempfds);
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);
	ssize_t res = 0;
	char buf[128] = "";
	int newfd = -1;
	int maxfd = sfd;
	int j = 0;

	while(1)
	{
		tempfds = readfds;
		s_res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(s_res < 0)
		{
			perror("select");
			return -1;
		}
		else if(0 == s_res)
		{
			break;
		}
		for(int i=0;i<=maxfd;i++)
		{
			if(!FD_ISSET(i,&tempfds))
				continue;
			if(0 == i)
			{
				fgets(buf,sizeof(buf),stdin);
				buf[strlen(buf)-1] = 0;
				printf("%s\n",buf);
			}
			else if(sfd == i)
			{
				newfd = accept(sfd,(struct sockaddr *)&(cin[j]),&addrlen);
				cin[newfd] = cin[j];
				if(newfd < 0)
				{
					perror("accept");
					return -1;
				}
				printf("[%s : %d] accept success\n",inet_ntoa(cin[newfd].sin_addr),ntohs(cin[newfd].sin_port));
				FD_SET(newfd,&readfds);
				maxfd = maxfd > newfd ? maxfd : newfd;
			}
			else
			{
				bzero(buf,sizeof(buf));
				res = recv(i,buf,sizeof(buf),0);
				if(res < 0)
				{
					perror("recv");
					return -1;
				}
				else if(0 == res)
				{
					printf("[%s : %d] client offline\n",inet_ntoa(cin[i].sin_addr),ntohs(cin[i].sin_port));
					close(i);
					FD_CLR(i,&readfds);
					while(FD_ISSET(maxfd,&readfds) == 0 && maxfd-->=0);
					continue;
				}
				printf("[%s : %d] %s\n",inet_ntoa(cin[i].sin_addr),ntohs(cin[i].sin_port),buf);
				//发送数据
				if(send(i,buf,sizeof(buf),0) < 0)
				{
					perror("send");
					return -1;
				}
			}
		}
	}

	//关闭所有文件描述符
	close(sfd);
	return 0;
}

二、通过select搭建TCP客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#define PORT 8808
#define IP "192.168.122.92"

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int cfd = socket(AF_INET,SOCK_STREAM,0);
	if(cfd < 0)
	{
		perror("socket");
		fprintf(stderr,"socket failed __%d__\n",__LINE__);
		return -1;
	}
	printf("socket success...\n");

	//设置允许端口号复用
	int reuse = 1;
	if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)  
	{
		perror("setsockopt");
		return -1;
	}


	//填充地址信息结构体,真是的地址信息结构体根据地址族制定
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);

	//连接服务器
	if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("connetc");
		return -1;
	}
	printf("connect success...\n");

	ssize_t res = 0;
	char buf[128] = "";
	int s_res = -1;
	fd_set readfds;
	fd_set tempfds;
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);

	while(1)
	{
		tempfds = readfds;
		s_res = select(cfd+1,&tempfds,NULL,NULL,NULL);
		if(s_res < 0)
		{
			perror("select");
			return -1;
		}
		else if(0 == s_res)
		{
			break;
		}
		if(FD_ISSET(0,&tempfds))
		{
			bzero(buf,sizeof(buf));
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1] = 0;
			//发送数据
			if(send(cfd,buf,sizeof(buf),0) < 0)
			{
				perror("send");
				return -1;
			}
		}
		if(FD_ISSET(cfd,&tempfds))
		{

			//接受数据
			bzero(buf,sizeof(buf));
			res = recv(cfd,buf,sizeof(buf),0);
			if(res < 0)
			{
				perror("recv");
				return -1;
			}
			else if(0 == res)
			{
				printf("[%s : %d] server offline\n",IP,PORT);
				break;
			}
			printf("[%s : %d] %s\n",IP,PORT,buf);
		}
	}

	//关闭所有文件描述符
	close(cfd);
	return 0;
}

三、通过poll搭建客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>

#define PORT 8808
#define IP "192.168.122.92"

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int cfd = socket(AF_INET,SOCK_STREAM,0);
	if(cfd < 0)
	{
		perror("socket");
		fprintf(stderr,"socket failed __%d__\n",__LINE__);
		return -1;
	}
	printf("socket success...\n");

	//设置允许端口号复用
	int reuse = 1;
	if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)  
	{
		perror("setsockopt");
		return -1;
	}


	//填充地址信息结构体,真是的地址信息结构体根据地址族制定
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);

	//连接服务器
	if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("connetc");
		return -1;
	}
	printf("connect success...\n");

	ssize_t res = 0;
	char buf[128] = "";
	int p_res = -1;
	struct pollfd fds[2];
	fds[0].fd = 0;
	fds[0].events = POLLIN;
	fds[1].fd = cfd;
	fds[1].events = POLLIN;


	while(1)
	{

		p_res = poll(fds,2,-1);
		if(p_res < 0)
		{
			perror("select");
			return -1;
		}
		else if(0 == p_res)
		{
			break;
		}
		if(fds[0].revents & POLLIN != 0)
		{
			bzero(buf,sizeof(buf));
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1] = 0;
			//发送数据
			if(send(cfd,buf,sizeof(buf),0) < 0)
			{
				perror("send");
				return -1;
			}
		}
		if(fds[1].revents & POLLIN)
		{

			//接受数据
			bzero(buf,sizeof(buf));
			res = recv(cfd,buf,sizeof(buf),0);
			if(res < 0)
			{
				perror("recv");
				return -1;
			}
			else if(0 == res)
			{
				printf("[%s : %d] server offline\n",IP,PORT);
				break;
			}
			printf("[%s : %d] %s\n",IP,PORT,buf);
		}
	}

	//关闭所有文件描述符
	close(cfd);
	return 0;
}

文章来源地址https://www.toymoban.com/news/detail-663082.html

到了这里,关于IO多路复用练习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【APUE】网络socket编程温度采集智能存储与上报项目技术------多路复用

    作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习 擅长领域:驱动开发,嵌入式软件开发,BSP开发 作者主页:一个平凡而乐于分享的小比特的个人主页 文章收录专栏:网络socket编程之温度采集智能存储与上报项目,本

    2024年04月10日
    浏览(47)
  • 网络编程代码实例:IO复用版

    网络编程代码实例:IO复用版。 yezhening/Environment-and-network-programming-examples: 环境和网络编程实例 (github.com) Environment-and-network-programming-examples: 环境和网络编程实例 (gitee.com) 使用传输控制协议(TCP) 服务端多进程,一个服务端可连接多个客户端 用户在客户端终端输入,可多次

    2024年02月02日
    浏览(35)
  • IO多路复用练习

    一、通过select搭建TCP服务器 二、通过select搭建TCP客户端 三、通过poll搭建客户端

    2024年02月12日
    浏览(33)
  • 【高并发服务器 02】——线程池与IO多路复用

    线程池的好处 :所有的池都是为了事先把资源准备好,在后续用的时候可以更加方便的拿到这个资源—— 不用去申请、释放资源 什么时候用线程池 ? IO事务并发较高 :人在杭州,但是数据库在北京,想要查询数据库,需要通过互联网建立TCP三次握手,频繁地创建和销毁线

    2024年03月23日
    浏览(51)
  • 多线程|多进程|高并发网络编程

    多进程并发服务器是一种经典的服务器架构,它通过创建多个子进程来处理客户端连接,从而实现并发处理多个客户端请求的能力。 概念: 服务器启动时,创建主进程,并绑定监听端口。 当有客户端连接请求时,主进程接受连接,并创建一个子进程来处理该客户端连接。

    2024年02月07日
    浏览(38)
  • 网络模型与 IO 多路复用

      socket也称作“套接字”,用于描述IP地址和端口,是一个通信链路的描述符。应用程序通常通过“套接字”向对端发出请求或者应答网络请求。   socket是连接运行在网络上的两个程序之间的通信端点。通信的两端都有socket,它是一个通道,数据在两个socket之间进行传输

    2024年02月01日
    浏览(52)
  • [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

    网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现…

    2024年02月16日
    浏览(66)
  • Linux网络编程:多进程 多线程_并发服务器

    文章目录: 一:wrap常用函数封装 wrap.h  wrap.c server.c封装实现 client.c封装实现 二:多进程process并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 三:多线程thread并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 ​​​​   read 函数的返回值 wrap.h  wrap

    2024年02月12日
    浏览(56)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(81)
  • 【高并发网络通信架构】引入IO多路复用(select,poll,epoll)实现高并发tcp服务端

    目录 一,往期文章 二,基本概念 IO多路复用 select 模型 poll 模型 epoll 模型 select,poll,epoll 三者对比 三,函数清单 1.select 方法 2.fd_set 结构体 3.poll 方法 4.struct pollfd 结构体 5.epoll_create 方法 6.epoll_ctl 方法 7.epoll_wait 方法 8.struct epoll_event 结构体 四,代码实现 select 操作流程 s

    2024年02月12日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包