6.物联网LWIP之并发服务器编程

news2024/9/23 19:25:51

一。并发服务器(多线程)实现

#include "socket_udp_server.h"
#include "socket_tcp_server.h"
#include "socket_wrap.h"
#include "ctype.h"

static char ReadBuff[BUFF_SIZE];

/**
  * @brief  udp 服务器任务
  * @param  None
  * @retval None
  */
void vUdpServerTask(void){

	int 	 sfd, n, i;
	struct sockaddr_in server_addr, client_addr;
	socklen_t	client_addr_len;
	
	//创建socket	udp通信
	sfd = Socket(AF_INET, SOCK_DGRAM, 0);
	server_addr.sin_family 			= AF_INET;
	server_addr.sin_port   			= htons(SERVER_PORT);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//绑定socket
	Bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	client_addr_len = sizeof(client_addr);
	while(1){
		//等待客户端发送数据
		n = Recvfrom(sfd, ReadBuff, BUFF_SIZE, 0, (struct sockaddr *)&client_addr, &client_addr_len);
		//进行大小写转换
		for(i = 0; i < n; i++){
		
			ReadBuff[i] = toupper(ReadBuff[i]);		
		}
		//写回客户端
		Sendto(sfd, ReadBuff, BUFF_SIZE, 0, (struct sockaddr *)&client_addr, client_addr_len);
	}
	
}

二。多路IO服用服务器模型

三。select API

1.标准select

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

//nfds: 	监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态
//readfds:	监控有读数据到达文件描述符集合,传入传出参数
//writefds:	监控写数据到达文件描述符集合,传入传出参数
//exceptfds:监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数
//timeout:	定时阻塞监控时间,3种情况
			//1.NULL,永远等下去
			//2.设置timeval,等待固定时间
			//3.设置timeval里时间均为0,检查描述字后立即返回,轮询
//return:	成功:所监听的所有监听集合中,满足条件的总数!
		  //失败:0 超时
		  //错误:-1
	struct timeval {
		long tv_sec; /* seconds */
		long tv_usec; /* microseconds */
	};
	void FD_CLR(int fd, fd_set *set); 	//把文件描述符集合里fd清0
	int FD_ISSET(int fd, fd_set *set); 	//测试文件描述符集合里fd是否置1
	void FD_SET(int fd, fd_set *set); 	//把文件描述符集合里fd位置1
	void FD_ZERO(fd_set *set); 			//把文件描述符集合里所有位清0
/*
注意:
    1.	select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数
2.		解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力
*/

2.LWIP select

/* FD_SET used for lwip_select */
#ifndef FD_SET
#undef  FD_SETSIZE
/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */
#define FD_SETSIZE    MEMP_NUM_NETCONN
#define FDSETSAFESET(n, code) do { \
  if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \
  code; }} while(0)
#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\
  (code) : 0)
#define FD_SET(n, p)  FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] |=  (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define FD_CLR(n, p)  FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] &= ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] &   (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define FD_ZERO(p)    memset((void*)(p), 0, sizeof(*(p)))
//fd_set
typedef struct fd_set
{
  unsigned char fd_bits [(FD_SETSIZE+7)/8];
} fd_set;
//MEMP_NUM_NETCONN
#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__
#define MEMP_NUM_NETCONN                4
#endif
//LWIP_SOCKET_OFFSET
#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__
#define LWIP_SOCKET_OFFSET              0
#endif

3.select编程模型

四。并发服务器(select)实现

 

#include "socket_wrap.h"
#include "socket_select_server.h"
#include "socket_tcp_server.h"
#include "string.h"
#include "FreeRTOS.h"
#include "task.h"
#include "ctype.h"

static char ReadBuff[BUFF_SIZE];
/**
  * @brief  select 并发服务器
  * @param  none
  * @retval none
  */
void vSelectServerTask(void)
{

	int 	 sfd, cfd, maxfd, i, nready, n, j;
	struct sockaddr_in server_addr, client_addr;
	socklen_t	client_addr_len;
	fd_set all_set, read_set;
	//FD_SETSIZE里面包含了服务器的fd
	int		 clientfds[FD_SETSIZE - 1];
	
	//创建socket
	sfd = Socket(AF_INET, SOCK_STREAM, 0);
	server_addr.sin_family 			= AF_INET;
	server_addr.sin_port   			= htons(SERVER_PORT);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//绑定socket
	Bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	//监听socket
	Listen(sfd, 5);
	
	client_addr_len = sizeof(client_addr);
	//初始化 maxfd 等于 sfd
	maxfd = sfd;
	
	//清空fdset
	FD_ZERO(&all_set);
	
	
	//把sfd文件描述符添加到集合中
	
	FD_SET(sfd, &all_set);
	
	
	//初始化客户端fd的集合
	
	for(i = 0; i < FD_SETSIZE -1 ; i++){
		//初始化为-1
		clientfds[i] = -1;
	}
	while(1)
	{
		//每次select返回之后,fd_set集合就会变化,再select时,就不能使用,
		//所以我们要保存设置fd_set 和 读取的fd_set
		read_set = all_set;
		nready = select(maxfd + 1, &read_set, NULL, NULL, NULL);
		//没有超时机制,不会返回0
		if(nready < 0){
			printf("select error \r\n");
			vTaskDelete(NULL);
		}
		//判断监听的套接字是否有数据
		if(FD_ISSET(sfd, &read_set)){
		
			//有了客户端进行连接了
			//客户接入
			cfd = accept(sfd, (struct sockaddr *)&client_addr, &client_addr_len);
			if(cfd < 0){
				printf("accept socket error\r\n");
				//继续select
				continue;
			}
			printf("new client connect fd = %d\r\n", cfd);
			//把新的cfd 添加到fd_set集合中
			FD_SET(cfd, &all_set);
			//更新要select的maxfd
			maxfd = (cfd > maxfd)?cfd:maxfd;
			//把新的cfd 保存到cfds集合中
			for(i = 0; i < FD_SETSIZE -1 ; i++){
				if(clientfds[i] == -1){
					clientfds[i] = cfd;
					//退出,不需要添加
					break;
				
				}
			}
			//没有其他套接字需要处理:这里防止重复工作,就不去执行其他任务
			if(--nready == 0){
				//继续select
				continue;
			}
		
		}
		//遍历所有的客户端文件描述符
		for(i = 0; i < FD_SETSIZE -1 ; i++){
			if(clientfds[i] == -1){
				//继续遍历
				continue;
			}
			//是否在我们fd_set集合里面
			if(FD_ISSET(clientfds[i], &read_set)){
				n = Read(clientfds[i], ReadBuff, BUFF_SIZE);
				//Read函数已经关闭了这个客户端的fd
				if(n <= 0){
					//从集合里面清除
					FD_CLR(clientfds[i], &all_set);
					//当前的客户端fd 赋值为-1
					clientfds[i] = -1;
				}else{
					//进行大小写转换
					for(j = 0; j < n; j++){
					
						ReadBuff[j] = toupper(ReadBuff[j]);		
					}
					//写回客户端
					n = Write(clientfds[i], ReadBuff, n);
					if(n < 0){
						//从集合里面清除
						FD_CLR(clientfds[i], &all_set);
						//当前的客户端fd 赋值为-1
						clientfds[i] = -1;		
					}				
				}
			}
		}		
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/908489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习论文: Learning Transferable Visual Models From Natural Language Supervision

深度学习论文: Learning Transferable Visual Models From Natural Language Supervision Learning Transferable Visual Models From Natural Language Supervision PDF: https://arxiv.org/pdf/2103.00020.pdf 官方代码: https://github.com/OpenAI/CLIP PyTorch代码: https:…

vector(介绍)

目录 1.vector的介绍及使用 1.1 vector的介绍 1.2 vector的使用 1.2.1 vector的定义 1.2.2 vector iterator 的使用 1.2.3 vector 空间增长问题 1.2.4 vector 增删查改 1.2.5 vector 迭代器失效问题。&#xff08;重点&#xff09; 2.vector深度剖析及模拟实现 2.1 使用…

PHP“牵手”淘宝商品评论数据采集方法,淘宝API接口申请指南

淘宝天猫商品评论数据接口 API 是开放平台提供的一种 API 接口&#xff0c;它可以帮助开发者获取商品的详细信息&#xff0c;包括商品的标题、描述、图片等信息。在电商平台的开发中&#xff0c;详情接口API是非常常用的 API&#xff0c;因此本文将详细介绍详情接口 API 的使用…

深入理解Semaphore

Semaphore&#xff08;信号量&#xff09;是操作系统中PV操作的原语在java中的实现&#xff0c;它也是基于AQS实现的。其中PV操作是操作系统中一种实现进程互斥与同步的有效方法。PV操作与信号量&#xff08;S&#xff09;的处理有关&#xff0c;P表示通过&#xff0c;V表示释放…

2023.8 - java - 泛型

泛型问题的引出&#xff1a; jdk 1.5 引出泛型 // package 泛型; public class index {public static void main (String[] args){test t new test();t.setContent("aaa");int a (int) t.getContent();System.out.println(a);} }class test{Object content;publi…

分享图片 | 快速浏览网页资源,批量保存、一键分享图片

前言 小伙伴学习吉他&#xff0c;有时需要在互联网搜索曲谱资源&#xff0c;而多数曲谱均为图片&#xff0c;并且为多页&#xff0c;在电脑上显示练习很不方便&#xff0c;需要停下来点击鼠标进行翻页&#xff0c;影响练习的连贯性。 为了解决上述问题&#xff0c;通常把图片…

【数据分析入门】Jupyter Notebook

目录 一、保存/加载二、适用多种编程语言三、编写代码与文本3.1 编辑单元格3.2 插入单元格3.3 运行单元格3.4 查看单元格 四、Widgets五、帮助 Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 …

产品流程图是什么?怎么做?

产品流程图是什么&#xff1f; 产品流程图是一种图形化的表达方式&#xff0c;用于描述产品开发、制造、销售、使用等各个阶段中涉及的流程、步骤和关系。它通过图形符号、箭头、文本等元素&#xff0c;展示了产品的各个环节之间的关联和顺序&#xff0c;通常被用于可视化产…

IT项目即将上线:项目经理的前夜清单

在IT项目的生命周期中&#xff0c;投产前的准备是至关重要的。作为项目经理&#xff0c;你需要确保所有的细节都已经准备好&#xff0c;以确保项目的顺利上线。以下是一份详细的清单&#xff0c;帮助项目经理在项目投产前进行全面的准备。 1. 项目的回顾 在项目即将上线之前&…

stm32的命令规则

stm32型号的说明&#xff1a;以STM32F103RBT6这个型号的芯片为例&#xff0c;该型号的组成为7个部分&#xff0c;其命名规则如下&#xff1a;

前端(十三)——JavaScript 闭包的奥秘与高级用法探索

&#x1f636;博主&#xff1a;小猫娃来啦 &#x1f636;文章核心&#xff1a;深入理解 JavaScript 中的闭包 文章目录 不理解闭包&#xff1f;这玩意很难&#xff1f;闭包的定义与原理闭包是什么创建一个闭包 闭包的应用场景闭包与作用域闭包与作用域之间的关系全局作用域、函…

python之Pandas

1.Pandas简介 Pandas 是 Python 语言的一个扩展程序库&#xff0c;用于数据分析。 Pandas 名字衍生自术语 “panel data”&#xff08;面板数据&#xff09;和 “Python data analysis”&#xff08;Python 数据分析&#xff09;。 Pandas 一个强大的分析结构化数据的工具集…

苹果手机桌面APP带云图标有个箭头,过一段时间经常要下载才能使用APP

环境&#xff1a; IPhone 11 IOS13.0 问题描述&#xff1a; 苹果手机桌面APP带云图标有个箭头&#xff0c;过一段时间经常要下载才能使用APP 解决方案&#xff1a; 1.打开设置&#xff0c;往下找到iTunes Store与App Store 2.找到下面卸载未使用的APP 关闭按钮

记录几个Hudi Flink使用问题及解决方法

前言 如题&#xff0c;记录几个Hudi Flink使用问题&#xff0c;学习和使用Hudi Flink有一段时间&#xff0c;虽然目前用的还不够深入&#xff0c;但是目前也遇到了几个问题&#xff0c;现在将遇到的这几个问题以及解决方式记录一下 版本 Flink 1.15.4Hudi 0.13.0 流写 流写…

一百六十三、Kettle——Linux上安装Kettle9.2(亲测有效,附截图)

一、目的 由于之前发现kettle8.2和kettle9.3这两个版本&#xff0c;或多或少的存在问题 比如kettle8.2的本地服务没问题&#xff0c;但在Linux上创建共享资源库时就有问题&#xff1b; 比如kettle9.3由于不自带shims驱动包&#xff0c;目前在新的下载官网上无法找到下载路径…

Gitbook超详细使用教程,搭建属于你自己的博客!

文章目录 简介与github同步1.创建space2.安装github插件3.同步github4.生成space的url 博客搭建指南1.自定义域名2.发表博客内容3.设置域名默认页面4.界面设置注意事项 End 简介 Gitbook 是一个平台&#xff0c;允许用户创建和分享内容丰富的在线书籍。它有一个用户友好的界面…

JDK JRE JVM 三者之间的详解

JDK : Java Development Kit JRE: Java Runtime Environment JVM : JAVA Virtual Machine JDK : Java Development Kit JDK : Java Development Kit【 Java开发者工具】&#xff0c;可以从上图可以看出&#xff0c;JDK包含JRE&#xff1b;java自己的一些开发工具中&#…

SpringBootWeb案例 Part 2

3. 员工管理 完成了部门管理的功能开发之后&#xff0c;我们进入到下一环节员工管理功能的开发。 基于以上原型&#xff0c;我们可以把员工管理功能分为&#xff1a; 分页查询 带条件的分页查询 删除员工 新增员工 修改员工 那下面我们就先从分页查询功能开始学习。 3.…

内存分布(以及new,delete)

今天给大家说下内存分布&#xff0c;我们都知道的是&#xff0c;像局部变量都在栈区&#xff0c;但是像我们自己有时候申请的空间都在堆区&#xff0c;当然&#xff0c;内存分布不只只是栈区和堆区&#xff0c;还有常量区&#xff0c;代码区等等。如下图&#xff1a; 这就是内存…

项目实战笔记4:敏捷

术语介绍 敏捷项目管理是一种以快速响应变化为核心的项目管理方法。与传统的瀑布模型不同&#xff0c;敏捷方法强调迭代开发和紧密的团队合作。其目的是尽可能快地交付可用的产品&#xff0c;然后在客户和团队之间进行反馈和迭代&#xff0c;以不断优化产品和开发过程。 在敏捷…