2020-08-21 多路复用TCP双向通信

2023-05-16

                     多路复用TCP双向通信

首先说一下多路复用

         多路的作用:监测文件描述符的状态变化(监测文件描述符是否有数据可读写)
                               状态变化: 有数据可读,有数据可写,异常

     有可能需要监测多个文件描述符--》多个文件描述符该如何存储--》linux中定义了一个变量类型fd_set (文件描述符集合,  专门用来存放要监测的文件描述符)
        第一步:定义文件描述符集合变量
                               fd_set  myset;
       第二步:往集合中添加要监测的文件描述符
                               FD_ZERO(&myset);
                               FD_SET(你要监测的文件描述符, &myset);

       第三步:调用select去监测刚才你添加的文件描述符状态
       第四步(重点):判断你监测的文件描述符是否发生了状态改变
                              通过判断文件描述符在不在集合中即可实现
                             if(FD_ISSET(文件描述符,&myset))  //说明文件描述符在集合中--》说明是这个文件描述符发生了状态改变
                             {

                             }


相关的接口函数
         int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
             返回值:成功  >0
                            失败  -1
                            超时  0
              参数:nfds(重点) --》你要监测的所有的文件描述符中最大的文件描述符+1
                       readfds --》我想监测文件描述符是否有数据可读
                                  select(最大+1,&myset,NULL,NULL)  //表示我只想监测myset中的文件描述符是否有数据可读
                      writefds --》我想监测文件描述符是否有数据可写
                                    select(最大+1,NULL,&myset,NULL)  //表示我只想监测myset中的文件描述符是否有数据可写
                      exceptfds --》我想监测文件描述符是否发生异常
                                    select(最大+1,NULL,NULL,&myset)  //表示我只想监测myset中的文件描述符是否发生异常
                       timeout --》超时时间,设置NULL表示永久阻塞等待
                                         struct timeval
                                         {
                                                 tv_sec;  //秒
                                                 tv_usec;  //微秒
                                         }

             特点
             第一:select阻塞当前程序,直到想要监测的文件描述符发生了状态改变才解除阻塞
             第二:如果select监测的了多个文件描述符(比如:A,B,C三个),如果某个文件描述符发生了状态改变,那么select会自动将没有发生状态改变的文件描述符从集合中剔除, 也就是说:select会将发生状态改变的文件描述符保留在集合,其它的删除

       void FD_CLR(int fd, fd_set *set);  //从set中把fd删除
       int  FD_ISSET(int fd, fd_set *set);  //判断fd在不在set集合中    返回1  在集合中    返回0  不在集合中
       void FD_SET(int fd, fd_set *set);  //把fd添加都set集合中
       void FD_ZERO(fd_set *set);  //清空set集合


                                  多路复用实现TCP双向通信

代码:客户端

#include "myhead.h"

/*
	多路复用实现双向通信---》tcp客户端代码
	    
*/


int main(int argc,char **argv)
{
	int tcpsock;
	int ret;
	char buf[100];
	//定义客户端的ipv4地址结构体变量
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family = AF_INET;
    bindaddr.sin_port = htons(atoi(argv[2]));  //自己指定一个端口号
    bindaddr.sin_addr.s_addr = inet_addr(argv[1]); //指定自己的ip
  
    //定义服务器的ipv4地址结构体变量
    struct sockaddr_in serveraddr;
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[4]));  //服务器端口号
    serveraddr.sin_addr.s_addr = inet_addr(argv[3]); //服务器的ip
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!\n");
		return -1;
	}
	//设置端口重复使用
	int on=1;
	setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!\n");
		return -1;
	}
	
	//连接服务器
	ret=connect(tcpsock,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(ret==-1)
	{
		perror("连接服务器!\n");
		return -1;
	}
	//定义文件描述符集合变量
	fd_set myset;
	//多路复用监视文件描述符0--》键盘输入   文件描述符tcpsock是否可读
	 
	while(1)
	{
		//添加要监测的文件描述符
		FD_ZERO(&myset);
		FD_SET(0,&myset); 
		FD_SET(tcpsock,&myset);
		//printf("阻塞在select!\n");
		//调用select去监测   电子警察
		
		ret=select(tcpsock+1,&myset,NULL,NULL,NULL);
		if(ret>0) //监测成功,说明有文件描述符发生了状态变化
		{
			bzero(buf,100);
			//进一步去判断究竟是哪个文件描述符发生了状态改变
			if(FD_ISSET(0,&myset))
			{
				
				//printf("相信我,键盘一定有输入,不骗你的!\n");
				//主动调用scanf读取键盘输入的内容
				scanf("%s",buf);
				//发送给服务器
				write(tcpsock,buf,strlen(buf));
			}
			if(FD_ISSET(tcpsock,&myset))
			{
				//printf("相信我,tcpsock文件描述符可读,不骗你的!\n");
				//主动调用scanf读取键盘输入的内容
				ret=read(tcpsock,buf,100);
				if(ret==0)
				{
					printf("服务器已挂!\n");
					return -1;
				}
				printf("服务器发送过来的信息是:%s\n",buf);
			}
		}
		else if(ret==0)
		{
			
		}	
		else
		{
			perror("select监测失败!\n");
			return -1;
		}
	}
	
	close(tcpsock);
	return 0;
}

 服务器:

#include "myhead.h"

/*
	多路复用实现双向通信---》tcp客户端代码
*/

int main(int argc,char **argv)
{
	int tcpsock;
	int newsock;
	int ret;
	pthread_t id;
	char buf[100];
	//定义服务器的ipv4地址结构体变量
    struct sockaddr_in bindaddr;
    bzero(&bindaddr,sizeof(bindaddr));
    bindaddr.sin_family=AF_INET;
    bindaddr.sin_port=htons(atoi(argv[2]));  //服务器自己的端口号
    bindaddr.sin_addr.s_addr=inet_addr(argv[1]); //服务器自己的ip
 

	struct sockaddr_in clientaddr;
	bzero(&clientaddr,sizeof(clientaddr));
	int addrsize=sizeof(clientaddr);

	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!\n");
		return -1;
	}
	//printf("旧的文件描述符:%d\n",tcpsock);
	//设置端口重复使用
	int on=1;
	setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!\n");
		return -1;
	}
	//监听
	ret=listen(tcpsock,8);
	if(ret==-1)
	{
		perror("监听失败!\n");
		return -1;
	}
	//接收客户端的连接请求
	newsock=accept(tcpsock,(struct sockaddr *)&clientaddr,&addrsize);
	if(newsock==-1)
	{
		perror("接收客户端的连接请求失败!\n");
		return -1;
	}
	//printf("新的文件描述符:%d\n",newsock);
	//定义文件描述符集合变量
	fd_set myset;
	//多路复用监视文件描述符0--》键盘输入   文件描述符tcpsock是否可读
	while(1)
	{
		//添加要监测的文件描述符
		FD_ZERO(&myset);
		FD_SET(0,&myset); 
		FD_SET(newsock,&myset); 
		//printf("阻塞在select!\n");
		//调用select去监测   电子警察
		ret=select(newsock+1,&myset,NULL,NULL,NULL);
		if(ret>0) //监测成功,说明有文件描述符发生了状态变化
		{
			bzero(buf,100);
			//进一步去判断究竟是哪个文件描述符发生了状态改变
			if(FD_ISSET(newsock,&myset))
			{
				//printf("相信我,newsock文件描述符可读,不骗你的!\n");
				//主动调用scanf读取键盘输入的内容
				ret=read(newsock,buf,100);
				if(ret==0)
				{
					printf("客服端已断开!\n");
					return -1;
				}
				printf("客户端发送过来的信息是:%s\n",buf);
			}
			if(FD_ISSET(0,&myset))
			{
				
				//printf("相信我,键盘一定有输入,不骗你的!\n");
				//主动调用scanf读取键盘输入的内容
				scanf("%s",buf);
				//发送给服务器
				write(newsock,buf,strlen(buf));
			}
			
		}
		else if(ret==0)
		{
			
		}	
		else
		{
			perror("select监测失败!\n");
			return -1;
		}
	}
	close(tcpsock);
	close(newsock);
	return 0;
}

myhead.h

#ifndef MYHEAD_H_
#define MYHEAD_H_
//自定义的头文件,把其它常用的头文件都包含进来
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <pthread.h>
#include <linux/input.h>
#include <semaphore.h>
#include<stdbool.h>
#include <dirent.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#endif

重点:重点:重点:

          一定要记得文件描述符集合的设置放在while里面,因为每次:select会将发生状态改变的文件描述符保留在集合,其它的删除

  

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2020-08-21 多路复用TCP双向通信 的相关文章

  • 初出茅庐的小李第108篇博客二进制打印

    二进制打印介绍 C语言在格式化打印的时候有很多格式控制 xff0c 比如十进制打印用 d输出 xff0c 十六进制用 x输出 xff0c 八进制用 o格式输出 xff0c 但是当我们期望看一个数据的二进制的时候就必须借助计算器或者其他比较不
  • QGroundControl 自定义命令小工具的使用

    Custom Command Widgets 不用编译qgc的源码 xff0c 仅仅需要编写一个QML UIs文件这个小工具窗口可以被加载 xff0c 并且从重启之后仍然可以使用 xff0c 而且不受操作系统的限制主要有两个用途 xff11
  • HTTP请求方式GET和POST代码示例

    HTTP请求方式GET和POST代码示例 1 HTTP名词解释1 2 HTTP传输方式1 2 1GET名词解释1 2 1POST名词解释 1 3Http中Post 和Get代码实现 1 HTTP名词解释 HTTP大名叫做超文本传输协议 xf
  • Postman工具常见操作

    Postman常见操作 1 新建GET或POST请求 xff08 1 xff09 打开Postman xff0c 选择File gt New xff08 2 xff09 选择Request xff0c 进入 xff08 3 xff09 输入
  • Ubuntu18.04+ROS melodic 跑通VINS-MONO的一些踩坑记录

    VINS MONO的一些踩坑记录 0 本机环境 笔者的环境为Ubuntu 18 04 43 ros melodic 43 opencv 4 1 1 43 Eigen 3 3 9 43 ceres solver 1 14 跟VINS MONO
  • GPIO库函数开发和寄存器开发的区别

    函数原型为 xff1a void GPIO SetBits GPIO TypeDef GPIOx uint16 t GPIO Pin xff08 1 xff09 gt 箭头操作符要求左操作数必须是个指针GPIO TypeDef GPIOx
  • C++ 编译

    C 43 43 编译原理 参考博客 https www cnblogs com kevinWu7 p 10163443 html C C 43 43 编译就是要将C C 43 43 的代码映射到相应的机器码 xff0c 以及讨论其中的内存管
  • STM32串口中断的方式发送

    我将其改为真正的中断发送 步骤一 xff1a 初始化GPIO GPIO InitTypeDef GPIO InitStructure GPIO InitStructure GPIO Pin 61 GPIO Pin 10 LED1 PC10
  • 什么是大端小端 and 如何判断大端小端

    1 为什么会有大小端模式之分呢 xff1f 这是因为在计算机系统中 xff0c 我们是以字节为单位的 xff0c 每个地址单元都对应着一个字节 xff0c 一个字节为8bit 但是在C语言中除了8bit的char之外 xff0c 还有16b
  • python中串口通信的步骤及实现

    python内置的库函数确实很强大 xff0c serial库中包含了串口通信所用到的一些函数 本文用python实现了串口的一种简单通信 代码实现 xff1a span class token keyword import span se
  • 结构体作用(STM32)

    结构体作用 xff08 STM32 xff09 来源 xff1a 正点原子 MDK 中很多地方使用结构体以及结构体指针 xff0c 下面总结一下其使用结构体的主要作用 1 结构体是将不同的数据类型整合为一个有机整体 xff0c 方便数据管理
  • 两轴舵机云台的一点实践

    两轴舵机云台的一点实践 效果演示硬件使用情况定时器中断代码计算机体系下的云台角代码舵机控制代码工程源码下载 简介 xff1a 为了学习姿态解算相关知识 xff0c 最近做了一个作品 xff0c 模仿炮塔跟随系统 xff0c 用陀螺仪使两个舵
  • 栈的使用场景

    当数据的处理顺序要与接收顺序相反时 xff08 LIFO xff09 last in first out xff0c 就可以用栈 像文字处理器的 撤销 动作 xff0c 或网络应用程序的函数调用 xff0c 你应该都会需要栈来实现 在处理括
  • 如何重装Ubuntu 系统

    如果你弄坏了你的 Ubuntu 系统 xff0c 并尝试了很多方法来修复 xff0c 你最终放弃并采取简单的方法 xff1a 重新安装 Ubuntu 我们一直遇到这样一种情况 xff0c 重新安装 Linux 似乎比找出问题并解决来得更好
  • 精华:QinQ基础,VLAN双层TAG

    QinQ 是 802 1Q in 802 1Q 的简称 xff0c 是基于 IEEE 802 1Q 技术的一种比较简单的二层 VPN 协议 QinQ简介 IEEE 802 1Q 定义的 VLAN ID 域有 12 个比特 xff0c 最多可
  • Ubuntu更换默认终端

    终端是任何Linux系统的关键部分 它允许您通过shell访问Linux系统 虽说现在的Linux发行版 xff0c 比如Ubuntu xff0c CentOS等已经基本上可以采用GUI来完成绝大部分一般性的任务 但是 xff0c 终端程序
  • vim编辑器如何删除一行或者多行内容

    如何从Vim中删除行 xff1f 如何删除多行 xff1f 本文介绍在Vim编辑器中删除行的不同方法 安装vim 在Ubuntu Debian中的安装方式 sudo apt install vim 在RHEL Centos中的安装方式 yu
  • Linux系统入门命令学习经验

    此时此刻我想和大家分享一下我在学习linux过程中的一些经验和教训 xff0c 如果有人能够正好看到我的这篇文章 xff0c 希望能够让想学习linux的同学多少获得一点经验 xff0c 少走一些弯路 能够比较简单 快捷的迅速掌握知识是我们
  • CloudBeaver 参考架构

    CloudBeaver 是一个基于 Web 的云数据库管理工具 xff0c 支持 PostgreSQL MySQL MariaDB SQLite 和 Firebird 等数据库 server osgi 模式 xff0c 依赖dbeaver
  • 如何修改Vim默认注释

    在Linux下vim被注释掉的字体颜色默认为非常刺眼的蓝色 xff0c 看上去很不清晰 xff0c 我们可以通过设置用户根目录下 vimrc文件 xff0c 可以更改颜色的配置 Vim默认注释颜色如下图 xff1a 找到vim的配置文件 x

随机推荐

  • yum install 与 yum groupinstall 的区别

    yum 提供二种安装软件的方式 1 xff0c yum install 它安装单个软件 xff0c 以及这个软件的依赖关系 2 xff0c yum groupinstall 它安装一个安装包 xff0c 这个安装包包涵了很多单个软件 xff
  • 自制正点原子四轴遥控器无法连接minifly

    最近在群里有群友问自制遥控器无法对频的问题 xff0c 我过去也踩过这个坑 xff0c 已经解决了 我已经在群里回答四五次了 xff0c 但可能群友没注意或者进群较晚没看到 xff0c 正好今晚有空 xff0c 把这个坑填上 18年国庆后自
  • 红旗Linux系统安装教程

    用惯了Windows系统的您 xff0c 会不会想尝尝鲜 xff0c 试试Linux的系统呢 以下经验在虚拟机和实机都适用的哦 工具 原料 电脑 Linux系统镜像包 方法 步骤1 首先将镜像写到光盘或者U盘 xff0c 然后到bios设置
  • 安装CentOS7出现dracut:/#……time解决办法

    当选择install CentOS7以后一会就会出现错误 报错信息 xff1a 就是dracut xff1a timeout一大堆 我本来以为是我的启动盘没做好 xff0c 后来我又重做了好几次都是这问题 解决 通过搜索引擎检索 xff0c
  • 【PID控制 Ⅱ】在代码中实现PID控制算法的思路以及伪代码

    一 实现思路 定义PID控制器 xff1a 在代码中定义一个PID控制器 xff0c 包括三个参数 xff1a 比例系数 xff08 Kp xff09 积分系数 xff08 Ki xff09 和微分系数 xff08 Kd xff09 这些参
  • 使用ZED-stereo相机配合SURF算法识别目标并测距

    这是以前做的小项目里的一部分 xff0c 由于时间久远 xff0c 在这里整理以下 xff0c 也方便自己以后查阅 使用ZED stereo相机配合SURF算法识别目标并测距 ZED stereo是很好用功能强大的双目相机 xff0c 可以
  • 联合标定单目相机和imu,使用工具Kalibr

    使用Kalibr工具标定单目相机和IMU的外参 xff0c 操作过程和联合标定双目相机和IMU类似 xff0c 以下介绍不同部分 最后标定时所需要的相机参数由双目变成了单目 xff0c 以下是配置文件的格式 xff1a cam0 camer
  • DETR3D的关键:feature_sampling(3D到2D的图像特征采样)

    流程 xff1a 坐标转换 gt 归一化坐标 gt grid sample 方法 gt mask 坐标转换 gt 归一化坐标 gt grid sample 方法 span class token comment 特征采样部分 xff0c I
  • extern “C”的用法和作用

    extern 34 C 34 的主要作用就是为了能够正确实现C 43 43 代码调用其他C语言代码 xff0c 实现C 43 43 与C及其它语言的混合编程 加上extern 34 C 34 后 xff0c 会指示编译器这部分代码按C语言的
  • Qt中常用的控件详细介绍

    这里写目录标题 1 容器的布局系统提供的布局控件利用 widget 做布局 2 QListWidget xff08 列表控件 xff09 3 QTreeWidget xff08 树控件 xff09 4 QTableWidget xff08
  • Qt中三种定时器的触发方式

    定时器QTimer控件 定时器触发方式3种所需api资料 1 定时器事件 触发案例1 xff1a 定时器事件案例2 xff1a 同时启动多个定时器 2 定时器对象 触发案例3 xff1a 通过定时器对象 定时 3 静态成员函数 触发案例4
  • shell脚本语言(超全超详细)

    shell脚本语言 1 shell的概述2 脚本的调用形式打开终端时系统自动调用 xff1a etc profile 或 bashrc 3 shell语法初识3 1 定义以开头 xff1a bin bash3 2 单个 34 34 号代表注
  • post请求百度网址内容和访问本地springmvc工程controller

    1 xff0c 访问百度 import java io BufferedReader import java io InputStreamReader import java io PrintWriter import java net U
  • 音乐播放器mplayer的简单使用

    mplayer 1 mplayer的安装2 mplayer的键盘模式基本控制键 xff1a 3 Slave模式 xff1a 启动方法一 xff1a 在终端下敲命令来启动mplayerMplayer 在slave模式下常用的命令 xff1a
  • AJAX和CGI 技术的应用

    AJAX xff0c CGI 一 AJAX1 AJAX的概述AJAX局部更新网页流程图 xff1a 异步流程 xff1a 2 AJAX的通信过程2 1 创建xmlHttpRequest对象2 2 设置服务器响应的回调函数标准的XMLHttp
  • W25QXX使用教程

    W25QXX是华邦公司生产的一块FLASH储存芯片 那W25Q256为例 xff1a 驱动方式 xff1a 单路双路四路SPI QSPI xff1b 擦写周期 xff1a 10W次 支持电压 xff1a 2 7 3 6V 频率 xff1a
  • QT串口通信

    QT串口的使用 1 添加头文件2 串口通信的7个步骤3 发送接收数据 1 添加头文件 span class token macro property span class token directive keyword include sp
  • Qt存储图片到数据库&&从数据库读取图片

    使用Qt将图片存储到sqlite my sql span class token double colon punctuation span span class token function my sql span span class
  • SQL常用语句大全

    创建表and插入数据 课程表 span class token keyword create span span class token keyword database span stuinfo span class token comm
  • 2020-08-21 多路复用TCP双向通信

    多路复用TCP双向通信 首先说一下多路复用 多路的作用 xff1a 监测文件描述符的状态变化 监测文件描述符是否有数据可读写 状态变化 xff1a 有数据可读 xff0c 有数据可写 xff0c 异常 有可能需要监测多个文件描述符 多个文件