当前位置: 首页 > news >正文

多点通信

目录

学习内容:

1. 套接字属性

1.1 套接字属性的获取和设置

1.2 案例实现

二、网络通信方式 

2.1. 单播:

2.2. 广播:

2.3. 组播:

三、广播

四、组播 

课外作业:

一、TCP机械臂测试


学习内容:

1. 套接字属性

1.1 套接字属性的获取和设置

       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int getsockopt(int sockfd, int level, int optname,
 void *optval, socklen_t *optlen);
       int setsockopt(int sockfd, int level, int optname,
 const void *optval, socklen_t optlen);
       功能:设置套接字在不同层上的属性
       参数1:套接字文件描述符
       参数2:要设置的层
               应用层:SOL_SOCKET
               传输层:tcp传输:IPPROTO_TCP
                       udp传输:IPPROTO_UDP
               网络层: IPPROTO_IP           
        参数3:要设置当前层的属性名称 ,常用每层属性见下表
        参数4:要设置或者获取属性的值    ,一般为int类型
        参数5:参数4的大小
        返回值:成功     返回0,失败返回-1并置位错误码      

1.2 案例实现

#include<myhead.h>int main(int argc, const char *argv[])
{//1、创建一个套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}//2、获取套接字地址重用的值int get_val = 1;socklen_t size = sizeof(get_val);       //获取属性值的大小if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &get_val, &size) == -1){perror("getsockopt error");return -1;}printf("get_val = %d\n", get_val);              //如果结果为0,表示套接字默认不允许端口号快速重用//3、设置允许端口号快速重用int set_val = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &set_val, sizeof(set_val)) ==-1){perror("setsockopt error");return -1;}printf("端口号快速重用成功\n");//4、验证是否设置成功了get_val = 0;if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &get_val, &size) == -1){perror("getsockopt error");return -1;}printf("get_val = %d\n", get_val);      //如果结果为1,表示套接字端口号快速重用设置成功return 0;
}

二、网络通信方式 

2.1. 单播:

        发送端和接收端完成一对一的通信方式。目前的通信模型都是单播

2.2. 广播:

        发送端和接收端完成一对多的通信方式,网络将发送端的数据,全部复制一遍发送给每个接收端一份。

2.3. 组播:

        发送端和接收端完成一对多的通信方式,但是仅仅只限于加入多播组的成员。

三、广播

1> 广播是实现网络通信中一对多的通信方式,发送端用于发送数据,每个接收端都可以收到消息

2> 对于套接字而言,一般是不允许发送广播消息的,需要对发送端套接字进行设置允许广播

        setsockopt ---> SOL_SOCKET ----> SO_BROADCAST ----> int

3> 广播的发送端需要绑定广播地址

        广播地址:网络号 + 255

        当前网络中,主机号为255的那个ip地址

4> 广播消息不允许穿过路由器,广播地址只对当前局域网中的所有主机进行消息的转发

5> 广播分为发送端和接收端,发送端用于发送数据,接收端用于接收数据

6> 广播只能使用UDP实现,接收端无论愿不愿意接收,发送端都正常发送消息

7> 广播的发送端流程 ---> UDP的客户端

1、socket(); //创建用于通信的套接字文件描述符

2、bind(); //可选,可以绑定也可以不绑定

3、setsockopt(); //设置当前套接字允许广播

4、sendto(); //向广播地址发送消息

5、close(); //关闭套接字

#include<myhead.h>int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("sfd = %d\n", sfd);//2、绑定可选//3、设置允许消息广播int broad = 1;if(setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broad, sizeof(broad)) == -1){perror("setsockopt error");return -1;}printf("设置广播成功\n");//4、向广播地址发送消息//4.1 封装广播的地址信息struct sockaddr_in bin;bin.sin_family = AF_INET;bin.sin_port = htons(5555);bin.sin_addr.s_addr = inet_addr("192.168.0.255");char wbuf[128] = "";while(1){printf("请输入>>>");fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf)-1] = 0;//发送消息sendto(sfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&bin, sizeof(bin));printf("发送成功\n");}//5、关闭套接字close(sfd);return 0;
}

8> 广播的接收端流程 ----> UDP的服务器端

1、socket(); //创建用于通信的套接字文件描述符

2、bind(); //必须进行,但是,绑定的广播地址和端口号

3、sendto(); //向广播地址发送消息

4、close(); //关闭套接字 

#include<myhead.h>int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int rfd = socket(AF_INET, SOCK_DGRAM, 0);if(rfd == -1){perror("socket error");return -1;}printf("rfd = %d\n", rfd);             //3//2、绑定广播地址和端口号//2.1 填充地址信息结构体struct sockaddr_in rin;rin.sin_family = AF_INET;        //通信域rin.sin_port = htons(5555);        //端口号rin.sin_addr.s_addr = inet_addr("192.168.0.255");   //广播地址//2.2 绑定工作if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1){perror("bind error");return -1;}printf("bind success\n");//3、接受数据char rbuf[128] = "";while(1){//清空容器bzero(rbuf, sizeof(rbuf));//接受广播消息recv(rfd, rbuf, sizeof(rbuf), 0);printf("收到广播消息为:%s\n", rbuf);}//4、关闭套接字close(rfd);return 0;
}

四、组播 

1> 组播也是实现一对多的通信方式,对于广播而言,网络需要对每个消息进行复制转发,会占用大量的带宽,导致网络拥塞

2> 组播可以实现小范围的数据传播:将需要接收数据的接收端加入多播组,发送端向多播组中发送消息,每个组内成员都能接收到消息

3> 需要对接收端进行设置,将接收端加入多播组

4> 组播也是使用UDP实现的,无论接收端是否愿意接收数据,发送端都可以正常向多播组中发送数据

5> 组播也分为发送端和接收端流程

6> 组播发送端流程 -----> 类似于UDP的客户端流程

1、socket(); //创建用于通信的套接字文件描述符

2、bind(); //可选,可以绑定也可以不绑定

3、sendto(); //向多播组地址发送消息

4、close(); //关闭套接字

#include<myhead.h>int main(int argc, const char *argv[])
{//1、socket();          //创建用于通信的套接字文件描述符int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(sfd == -1){perror("socket error");return -1;}//2、bind();             //可选,可以绑定也可以不绑定//3、sendto();               //向多播组地址发送消息struct sockaddr_in min;min.sin_family = AF_INET;min.sin_port = htons(9999);min.sin_addr.s_addr = inet_addr("224.1.2.3");char wbuf[128] = "";while(1){printf("请输入>>>>");fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf)-1] = 0;sendto(sfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&min, sizeof(min));printf("发送成功\n");}//4、close();                //关闭套接字close(sfd);return 0;
}

7> 组播的接收端流程 ------> 类似于UDP的服务器端流程

1、socket(); //创建用于通信的套接字文件描述符

2、bind(); //必须进行,但是,绑定的组播地址和端口号

3、setsockopt(); //加入多播组

4、sendto(); //向广播地址发送消息 5、close(); //关闭套接字 

#include<myhead.h>int main(int argc, const char *argv[])
{//1、socket();          //创建用于通信的套接字文件描述符int rfd = socket(AF_INET, SOCK_DGRAM, 0);if(rfd == -1){perror("socket error");return -1;}//3、setsockopt();          //加入多播组//准备要设置的数据struct ip_mreqn imr;        imr.imr_multiaddr.s_addr = inet_addr("224.1.2.3");   //组播ipimr.imr_address.s_addr = inet_addr("192.168.0.143");   //主机ipimr.imr_ifindex = 2;                        //网卡编号if(setsockopt(rfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)) == -1){perror("setsockopt error");return -1;}printf("加入多播组成功\n");//2、bind();             //必须进行,但是,绑定的组播地址和端口号struct sockaddr_in rin;rin.sin_family = AF_INET;rin.sin_port = htons(9999);rin.sin_addr.s_addr = inet_addr("224.1.2.3");     //组播地址if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1){perror("bind error");return -1;}printf("bind success\n");//4、recv();               //从组播地址中接受消息char rbuf[128] = "";while(1){//清空容器bzero(rbuf, sizeof(rbuf));//接受广播消息recv(rfd, rbuf, sizeof(rbuf), 0);printf("收到组播消息为:%s\n", rbuf);}//5、close();                //关闭套接字close(rfd);return 0;
}

课外作业:

一、TCP机械臂测试

通过w(红色臂角度增大)s(红色臂角度减小)d(蓝色臂角度增大)a(蓝色臂角度减小)按键控制机械臂

解析:

#include<myhead.h>
#define SER_PORT 8888             //与服务器保持一致
#define SER_IP  "192.168.2.28"    //服务器ip地址
#define CLI_PORT 9999               //客户端端口号
#define CLI_IP  "192.168.2.227"     //客户端ip地址int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int cfd = socket(AF_INET, SOCK_STREAM, 0);if(cfd == -1){perror("socket error");return -1;}printf("cfd = %d\n", cfd);             //3//3、连接到服务器//3.1 填充服务器地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;          //通信域sin.sin_port = htons(SER_PORT);      //服务器端口号sin.sin_addr.s_addr = inet_addr(SER_IP);     //服务器ip地址//3.2 连接服务器if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) == -1){perror("connect error");return -1;}printf("连接服务器成功\n");int x=30,y=30;//准备数据char rbuf[5] = {0xff, 0x02, 0x00, x, 0xff};char bbuf[5] = {0xff, 0x02, 0x01, y, 0xff};//发送给服务器,以初始化机械臂send(cfd, rbuf,sizeof(rbuf), 0);sleep(1);send(cfd, bbuf,sizeof(bbuf), 0);char a=0;while (1){printf("请输入wsad,q退出:");scanf("%s",&a);getchar();if(a == 'w'){x += 10;rbuf[3] = x;send(cfd, rbuf, sizeof(rbuf), 0);sleep(1);}else if (a == 's'){x -= 10; rbuf[3] = x;send(cfd, rbuf, sizeof(rbuf), 0);sleep(1);}else if (a == 'a'){y -= 2; bbuf[3] = y;send(cfd, bbuf, sizeof(bbuf), 0);sleep(1);}else if (a == 'd'){y += 2; bbuf[3] = y;send(cfd, bbuf, sizeof(bbuf), 0);sleep(1);}else if (a == 'q'){break;}else{printf("输入错误请重新输入\n");continue;}}//5、关闭套接字close(cfd);return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 子组件数据回显
  • 量化策略开发步骤系列(4)参数分析和过度拟合
  • TLE4966-3G带方向检测功能的高灵敏度汽车霍尔开关
  • 驾驭Git上游分支:高效设置与管理
  • 硬件面试经典 100 题(31~40 题)
  • AsyncTask
  • zdpgo_redis_v2 Go语言连接Redis的另一个版本,支持上下文操作,封装了一些便捷的处理操作
  • 知识学习技巧:如何从 iPhone 恢复误操作删除的视频
  • 005集——运算符和循环——C#学习笔记
  • 相机光学(三十四)——色差仪颜色观察者视角
  • 共享海外仓:海外仓也有共享经济?
  • 【智能流体力学】ANSYS Fluent流体仿真学习流程和Fluent模型方法概述
  • Django | 从中间件的角度理解跨站请求伪造(Cross-Site Request Forgey)[CSRF攻击]
  • git合入另一个分支连续的多个提交
  • 生物药物分离与纯化技术pdf文件分享
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • Android Volley源码解析
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • php中curl和soap方式请求服务超时问题
  • webpack+react项目初体验——记录我的webpack环境配置
  • 电商搜索引擎的架构设计和性能优化
  • 关于List、List?、ListObject的区别
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 马上搞懂 GeoJSON
  • 面试遇到的一些题
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 王永庆:技术创新改变教育未来
  • 一个项目push到多个远程Git仓库
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • NLPIR智能语义技术让大数据挖掘更简单
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 如何用纯 CSS 创作一个货车 loader
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #QT 笔记一
  • (1)(1.13) SiK无线电高级配置(五)
  • (11)MSP430F5529 定时器B
  • (floyd+补集) poj 3275
  • (windows2012共享文件夹和防火墙设置
  • (八)Flask之app.route装饰器函数的参数
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (二)测试工具
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (离散数学)逻辑连接词
  • (论文阅读11/100)Fast R-CNN
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (一)WLAN定义和基本架构转
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .Net Core缓存组件(MemoryCache)源码解析
  • .net core使用ef 6
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET Framework与.NET Framework SDK有什么不同?