8.16 IO多路复用——select的TCP服务器/客户端

2023-05-16

文章目录

    • select的TCP服务器/客户端
      • select的服务器
        • 代码示例
      • select的客户端
        • 代码示例

select的TCP服务器/客户端

select的服务器

代码示例

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

#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
}while(0);

#define PORT 8888   				//1024-49151
#define IP "192.168.31.156" 		//本机IP,用ifconfig查看
int update_maxfd(int maxfd,fd_set readfds);
int main(int argc, const char *argv[])
{
	//创建流式套节字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("create socket success\n");

	//允许端口快速重用
	int reuse = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	//填充地址信息结构体,真实的地址信息结构体与协议族相关
	//AF_INET,所以详情请看 man 7 ip
	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 )
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");
	//将套接字设为被动监听状态,让内核去监听是否有客户端连接
	if(listen(sfd,10) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	//创建一个读集合
	fd_set readfds,tempfds;
	//将集合清空
	FD_ZERO(&readfds);
	//将0号文件描述符添加到集合
	FD_SET(0,&readfds);
	//将sfd文件描述符添加到集合
	FD_SET(sfd,&readfds);
	//最大文件描述符
	int maxfd = sfd;
	int select_res = 0;
	char buf[128] = "";
	ssize_t res = 0;
	int newfd = -1;
	struct timeval tm;
	tm.tv_sec = 300;
	tm.tv_usec = 0;
	struct sockaddr_in arr[1020];
	while(1)
	{
		tempfds = readfds;
		select_res = select(maxfd+1,&tempfds,NULL,NULL,&tm);
		if(select_res < 0)
		{
			ERR_MSG("select");
			break;
		}
		else if(0 == select_res)
		{
			fprintf(stderr,"select time out\n");
			break;
		}
		//能允许到当前位置则说明集合中有文件描述符准备就绪
		//且集合中会只剩下产生事件的文件描述符
		//例如:0号产生事件,则会只剩下0号
		//sfd产生事件,则会只剩下sfd
		//0和sfd同时产生事件,则0和sfd都会剩下
		//所以只需要判断集合中剩下哪个文件描述符,走到对应函数即可
		for(int i = 0;i<=maxfd;i++)
		{
			//判断0~maxfd这些文件描述符在不在集合中
			if(FD_ISSET(i,&tempfds) == 0)
			{
				continue;
			}
			//能运行到当前位置,则说明i所代表的文件描述符有事件产生
			if(0 == i)
			{
				//触发键盘输入事件
				printf("触发键盘输入事件:");
				fflush(stdout);

				bzero(buf, sizeof(buf));
				
				//从终端获取文件描述符以及要发送的内容
				int sendfd;
				int res = scanf("%d %s", &sendfd, buf);
				while(getchar() != 10);
				if(res != 2)
				{
					fprintf(stderr, "请输入正确格式:文件描述符 要发送的内容\n");
					continue;
				}
				//判断获取到的文件描述符是否在readfds集合中
				if(FD_ISSET(sendfd, &readfds) == 0)
				{
					fprintf(stderr, "sendfd=%d 文件描述符不在集合中\n", sendfd);
					continue;
				}
				if(send(sendfd, buf, sizeof(buf), 0) < 0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("send message success\n");	
			}
			else if(sfd == i)
			{
				printf("触发客户端连接事件:");
				fflush(stdout);
				//从已经完成链接的队列头中,取出一个客户端信息,创建一个新的套接字文件描述符,
				//该文件描述符才是与客户通信的文件描述符!!!
				newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
				if(newfd < 0)
				{   
					ERR_MSG("accept");
					return -1;
				}
				//网络字节序的IP-->点分十进制 网络字节序的port-->本机字节序
				printf("[%s : %d] newfd = %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);

				arr[newfd-4] = cin;
				//将newfd添加到集合中
				FD_SET(newfd,&readfds);
				//更新maxfd
				maxfd = maxfd>newfd?maxfd:newfd;
			}
			else
			{
				bzero(buf,sizeof(buf));
				//循环接收
				res = recv(i,buf,sizeof(buf),0);
				if(res < 0)
				{
					ERR_MSG("recv");
					return -1;
				}
				else if(0 == res)
				{
					printf("[%s : %d] newfd = %d客户端退出\n",inet_ntoa(arr[i-4].sin_addr),ntohs(arr[i-4].sin_port),i);
					//关闭文件描述符
					close(i);
					//将文件描述符从集合中剔除
					FD_CLR(i,&readfds);
					//更新maxfd
					maxfd = update_maxfd(maxfd,readfds);
				}
				else
					printf("[%s : %d] newfd = %d : %s \n",inet_ntoa(arr[i-4].sin_addr),ntohs(arr[i-4].sin_port),i,buf);
			}
		}
	}
	close(sfd);
	return 0;
}
int update_maxfd(int maxfd,fd_set readfds)
{
	int i=maxfd;
	for(;i>0;i--)
	{
		if(FD_ISSET(i,&readfds))
			return i;
	}
	return 0;
}

select的客户端

代码示例

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

#define ERR_MSG(msg) do{\
    fprintf(stderr,"__%d__",__LINE__);\
    perror(msg);\
}while(0);
#define PORT 8888                   //1024-49151
#define IP "192.168.31.156"         //本机IP,用ifconfig查看      
int main(int argc, const char *argv[])
{
	//创建流式套节字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd < 0)
	{                                          
		ERR_MSG("socket");
		return -1;
	}
	printf("create socket success\n");
	//绑定客户端的地址信息结构体-》非必须绑定
	//填充要连接的服务器的地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family 		= AF_INET;
	sin.sin_port 		= htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	//连接服务器
	if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");
	//创建一个读集合
	fd_set readfds,tempfds;
	//将集合清空
	FD_ZERO(&readfds);
	//将0号文件描述符添加到集合
	FD_SET(0,&readfds);
	//将sfd添加到集合
	FD_SET(sfd,&readfds);
	//最大文件描述符
	int maxfd = sfd;
	int select_res = 0;
	char buf[128];
	ssize_t res=0;
	while(1)
	{
		tempfds = readfds;
		select_res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(select_res < 0)
		{
			ERR_MSG("select");
			break;
		}
		else if(0 == select_res)
		{
			fprintf(stderr,"select time out\n");
			break;
		}

		for(int i=0;i<=maxfd;i++)
		{
			if(FD_ISSET(i,&tempfds) == 0)
				continue;
			//客户端发送
			if(0 == i)
			{
				bzero(buf,sizeof(buf));
				fgets(buf,sizeof(buf),stdin);
				buf[strlen(buf)-1] = '\0';
				if(send(sfd, buf, sizeof(buf),0) < 0)
				{
					ERR_MSG("send");
					return -1;
				}
			}
			//客户端接收
			else if(sfd == i)
			{
				bzero(buf,sizeof(buf));
				res = recv(sfd,buf,sizeof(buf),0);
				if(res < 0 )
				{
					ERR_MSG("recv");
					return -1;
				}
				else if(0 == res)
				{
					printf("server is off-line\n");
					return 0;
				}
				else
					printf("%ld : %s\n",res,buf);
			}
		}
	}
	close(sfd);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

8.16 IO多路复用——select的TCP服务器/客户端 的相关文章

  • C语言基础入门:链表详解篇

    链表概述 链表是一种常见的重要的数据结构 它是动态地进行存储分配的一种结构 它可以根据需要开辟内存单元 链表有一个 头指针 变量 xff0c 以head表示 xff0c 它存放一个地址 该地址指向一个元素 链表中每一个元素称为 结点 xff
  • Linux c udp广播

    文章目录 1 对比2 代码2 1 服务端2 2 客户端 1 对比 服务端 xff1a 需要利用这个函数开发套接字的发广播权限 xff0c 并且需要客户端地址绑定为广播地址 span class token function setsocke
  • React—— HelloWorld

    React 学习笔记 Hello WorldJSX JavaScript XML 语法规则JavaScript 语法函数组件 类组件 amp 属性 props组合组件 生命周期函数 xff08 不全 xff09 amp 状态 state事件
  • Linux下makefile 编译项目

    文章目录 1 规划makefile编写2 makefile文件2 1 根目录下common mk2 2 config mk2 3 根目录makefile 2 4 其他目录下 1 规划makefile编写 a 根目录下放三个文件 xff1a
  • RPLIDAR激光雷达测试

    本文主要介绍PRLIDAR A2M8 R2激光雷达的的测试过程 关于该激光雷达的具体参数和描述 xff0c 可以直接去官网查询 本文的测试环境为Ubantu16 04 ROS xff08 kinetic xff09 关于Ubantu16 0
  • 【ROS机器人入门】1.1 ROS概念及环境配置

    文章目录 ROS设计目标系统要求配置步骤1 设置安装源2 设置ROS软件Key3 更新软件包4 安装完整版ROS Noetic软件5 配置ROS环境6 安装构建依赖7 1 安装rosdep 7 1与7 2任选其一 解决方法 7 2 安装ro
  • 纯C语言进行Get和Post请求(亲测)

    废话不多说 xff0c 直接上代码 span class token macro property span class token directive hash span span class token directive keywor
  • C++ 实现Get和Post请求(亲测)

    废话不多说 xff0c 直接上代码 span class token comment include lt stdlib h gt span span class token macro property span class token
  • php 接入海康平台

    php获取海康平台的监控流地址 先获取所有监控点 xff08 artemis api resource v1 cameras xff09 在根据监控点的cameraIndexCode请求 artemis api video v1 camer
  • [开源]一个面向数仓开发人员的低代码工具,零代码开发API服务

    一飞开源 xff0c 介绍创意 新奇 有趣 实用的免费开源应用 系统 软件 硬件及技术 xff0c 一个探索 发现 分享 使用与互动交流的开源技术社区平台 致力于打造活力开源社区 xff0c 共建开源新生态 xff01 一 开源项目简介 介
  • (14)Ubuntu 安装 velodyne 激光雷达的Ros驱动包

    1 安装ROS驱动 xff1a sudo apt get install ros kinetic velodyne 2 创建ROS工程 xff1a mkdir p catkin velodyne src cd catkin velodyne
  • (2)ROS终端出现没有那个文件或目录,解决每次都要source问题

    1 在创建完程序包后需要 source catkin ws devel setup bash 即解决每次都要source方法 在终端输入 xff1a gedit bashrc 在文件末尾添加一下这一行 xff0c 保存即可 xff1a so
  • (3)GNSS在ROS中数据获取与解析

    1 在ubuntu16 04中安装串口工具minicom 输入sudo minicom s进行串口配置 xff1a 弹出如下设置界面 xff1a 使用方向键 选择 Serial port setup xff0c 按Enter键 xff0c
  • 一篇文章搞定Github API 调用 (v3)

    收藏 segmentfault 作者 SolomonXie 文章 xff1a 一篇文章搞定Github API 调用 v3 xff09
  • (3)安装ROS报错sh: 0: Illegal option -h解决办法及国内源ROS安装教程

    从ROS官网安装ROS报错 sh 0 Illegal option h 可能是软件源的原因 xff0c 使用国内的软件源可以解决此问题 1 安装软件源 xff0c 建议采用国内软件源 xff0c 下面的为USTC的软件源 sudo sh c
  • (1)robot_pose_ekf扩展卡尔曼滤波功能包的使用方法

    这里写自定义目录标题 robot pose ekf功能包的编译安装如何使用机器人姿势EKF 编译运行robot pose ekf订阅的话题发布的话题机器人姿态ekf如何工作参考文章 robot pose ekf功能包的编译安装 ros wi
  • (15)sudo rosdep init报错的解决方式及rosdep update解决方案

    Ubuntu16 04下安装ROS时 xff0c 执行到sudo rosdep init这一步时会遇到问题 xff0c 如下图所示 xff1a 解决办法 xff1a 步骤一 xff1a 1 查询现有真实IP 输入网址 xff1a IPAdd
  • (16)Ubuntu下PCL库安装和测试程序

    安装PCL库 PCL库Github下载地址 xff1a https github com PointCloudLibrary pcl 安装依赖项 xff1a sudo add apt repository ppa v launchpad j
  • 【Vue】条纹进度条

    一 效果演示及使用 作为组件引入到项目 xff08 引入地址修改为自己实际的存放地址 xff09 xff0c 注册到components import stripeloading from 34 64 components LSUI loa
  • c++中 . 和 -> 的区别是什么

    c 43 43 中 和 gt 主要是用法上的不同 1 A B则A为对象或者结构体 xff1b 2 A gt B则A为指针 xff0c gt 是成员提取 xff0c A gt B是提取A中的成员B xff0c A只能是指向类 结构 联合的指针

随机推荐

  • rosdep update报错解决

    一 报错 reading in sources list data from etc ros rosdep sources list d ERROR error loading sources list 39 The read operat
  • 解决多个Ardupilot运行仿真环境冲突问题

    情况说明 分别安装了4 2和4 3两个版本的ardupilot工作环境 xff0c 出现运行4 3版本sim vehicle py时路径链接到4 2版本工作路径 解决 为防止文件识别错误 xff0c 更改sim vehicle py文件名为
  • yum、apt-get、curl、wget你了解吗?

    在这里整理一些自己想要了解的一些概念 内容来自网络博客 一般来说著名的linux系统基本上分两大类 xff1a RedHat系列 xff1a Redhat Centos Fedora等Debian系列 xff1a Debian Ubuntu
  • 2020电赛备战总结(一)

    你有多渴望 xff0c 就要有多努力 2020 xff0c 注定被载入史册的一个年份 xff0c 希望2020电赛也能让我永远记住 机会来的突然 xff0c 有一点小幸运吧 xff0c 在寒假回家的时候我带上了我的32 xff0c 然后在无
  • StringBuilder的容量capacity变化规则

    StringBuilder的容量capacity变化 xff0c 是每次2倍增长吗 xff1f xff08 jdk1 8 xff09 测试代码 1 StringBuilder sb 61 span class hljs keyword ne
  • Mavros Client md5sum Error

    ERROR Client mavros wants topic State to have datatype md5sum mavros msgs State 4048c9de2a16f4ae8e0538085ebf1b97 but our
  • Chrome安装Proxy SwitchyOmega插件&Ubuntu20.04安装Proxychains

    目录 1 Chrome浏览器1 1 安装Proxy SwitchyOmega插件1 2 安装Proxy SwitchyOmega插件 2 Ubuntu服务器2 1 安装2 2 配置2 3 测试2 4 异常处理 1 Chrome浏览器 1 1
  • ozone-1.1.0(最新版)单节点搭建教程

    目录 1 搭建环境说明2 Java环境配置 xff08 Linux xff09 2 1 jdk下载2 2 源码包解压2 3 配置jdk环境变量2 4 测试 3 Ozone配置 1 搭建环境说明 服务器 xff1a Ubuntu20 4 JA
  • aws: command not found

    安装aws前先要安装pip3 环境 xff1a centos 安装pip3 yum install span class token operator span y python3 span class token operator spa
  • Linux命令总结

    记录一下在工作中遇到的命令 xff0c 碰到一个就总结一个吧 xff01 uname i uname span class token operator span i 查看linux是多少位的 ps aux span class token
  • 【Windows安装pip全过程详解】

    1 Ctrl 43 A全选并复制get pip py文件官方链接地址 链接1 get pip py 2 在python文件中建立get pip py文件 2 1 进入python文件 2 2 新建一个 txt文档 xff0c Ctrl 43
  • 工作总结模板

    最近要准备中期答辩 xff0c 画了一张工作总结的思维导图 xff0c 供大家参考 xff01
  • Pycharm安装包报错【To search for alternate channels that may provide the conda package...】

    1 在Pycharm安装包 xff0c 命令行 conda install xx包名 xff0c 报错提示如下 xff1a 2 解决办法 xff1a 改用 pip install xx包名 安装成功 xff01
  • 【Python】照片批量命名

    1 照片批量命名代码如下 span class token comment 批量修改文件名 xff0c 默认操作为将图片按1 xff0c 2 xff0c 3 xff0c xff0c xff0c 顺序重命名 span span class t
  • Nexus Repository Manager 3 私服搭建 —— windows版

    nexus3 本文安装的是免费版 xff1a Nexus Repository OSS 下载 最新版本下载链接1 最新版本下载链接2 或到 https my sonatype com 可以下载nexus2和3两大版本 参考页面 xff1a
  • stm32f103在使用Free RTOS操作系統是遇到prvTaskExiterror解决办法

    1 检查已建立的线程中是否均有while xff08 1 xff09 2 是否含有break从而使程序跳出线程
  • 用HALL 库配置GPIO以及相关寄存器

    文章目录 一 初始化GPIO 一 定义一个结构体变量GPIO InitStruct xff0c 该变量类型是GPIO InitTypeDef 二 使能时钟 三 配置引脚的初始化电平 xff08 四 xff09 通过结构体变量配置具体的引脚
  • px4offboard模式无法设置成功

    px4offboard模式无法设置成功 这两天在测试px4的offboard模式 xff0c 根据官方使用手册给出的代码测试成功 xff0c 在这个基础上修改结果发现无法设置成功了 经过与官方代码对比分析 xff0c 在设置offboard
  • VsCode 配置 C/C++ 开发环境,真的很简单

    旧日的旧图 工欲善其事 xff0c 必先利其器 最近在学习C语言版的数据结构 xff0c 要敲敲C C 43 43 的代码 xff0c DevC 43 43 成功把我劝退了 之前写后端用习惯了Idea 写前端习惯用VsCode了 xff0c
  • 8.16 IO多路复用——select的TCP服务器/客户端

    文章目录 select的TCP服务器 客户端select的服务器代码示例 select的客户端代码示例 select的TCP服务器 客户端 select的服务器 代码示例 span class token macro property sp