网络编程 lesson7 广播组播和本地通信

news2024/11/26 19:32:34

目录

广播

什么是广播?(了解)

广播发送流程

广播接收流程

组播

什么是组播?

组播地址

组播结构体

组播发送流程

组播接收

本地套接字通信

什么是本地套接字通信?

特性

核心代码

程序实例

服务端

客户端


广播

什么是广播?(了解)

网络编程中的广播是一种通信方式,用于向网络中的多个主机发送消息或数据。它被广泛应用于局域网(LAN)或广域网(WAN)环境中,使得一台主机能够向整个网络中的其他主机发送消息,而不需要逐个发送给每个目标主机。

广播可以被看作是一种单向通信模式,其中发送方将消息广播到网络上的所有主机,而接收方则可以选择是否接收该消息。这使得广播非常适用于一些场景,如发送实时事件通知、传递系统状态更新或进行服务发现等。

在网络编程中,广播通常使用IP协议的特定地址来实现,例如IPv4中的广播地址(通常为255.255.255.255)或IPv6中的多播地址。发送方使用广播地址作为目标地址来发送消息,而接收方可以通过监听广播地址来接收消息。

广播通常使用UDP(用户数据报协议)来发送消息,因为UDP是一种无连接的协议,它不需要在发送前建立连接,这使得广播更加高效。然而,也可以使用TCP(传输控制协议)来进行广播,尽管这需要建立连接并可能带来一些额外的开销。

在实际的网络编程中,广播需要考虑一些安全性和网络规模的问题。由于广播消息可以发送给整个网络,可能存在滥用和安全风险。因此,在实现广播功能时需要进行适当的安全措施,例如对广播消息进行身份验证或加密,以确保只有授权的接收方可以接收和处理广播消息。

总结起来,网络编程中的广播是一种向网络中的多个主机发送消息或数据的通信方式。它利用特定的广播地址和UDP或TCP协议来实现,可以用于实时事件通知、系统状态更新和服务发现等场景。

广播发送流程

  1. 创建用户数据报套接字
  2. 缺省创建的套接字不允许广播数据包,使用setsockopt设置属性
  3. 接收方的地址指定为广播的地址
  4. 指定端口信息
  5. 发送数据包
int on =1;

setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&on,sizeof(on));
//设置属性代码

 完整代码

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

int main(int argc, char const *argv[])
{
    if(argc<2)
    {
        printf("please input addr and port\n");
        return -1;
    }
    //1.创建数据报套接子
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }

    //设置发送广播权限
    int op = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));

    //填充结构体:广播ip和接受方端口
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    char buf[128];
    while (1)
    {
        fgets(buf, sizeof(buf), stdin);
        sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr, sizeof(addr));
    }
    close(sockfd);
    return 0;
}
 

广播接收流程

  1. 创建用户数据报套接字
  2. 绑定IP地址(广播IP或者0.0.0.0)和端口
  3. 绑定端口必须和发送方指定的端口相同
  4. 等待接收数据
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    if(argc<2)
    {
        printf("please input addr and port\n");
        return -1;
    }
    
    //1.创建数据报套接子
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    //填充结构体:广播ip和接受方端口
    struct sockaddr_in addr,caddr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    socklen_t len=sizeof(caddr);

    if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
    {
        perror("bind err.");
        return -1;
    }

    char buf[128];
    while (1)
    {
        recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&caddr,&len);
        printf("ip=%s  port=%d :%s\n",inet_ntoa(caddr.sin_addr),\
        ntohs(caddr.sin_port),buf);
    }
    close(sockfd);
    return 0;
}

组播

什么是组播?

组播(Multicast)是一种网络通信方式,用于将数据从一个发送者传输给一组特定的接收者。在组播通信中,发送者只需将数据发送到一个特定的组播组地址,而不需要知道接收者的具体地址。这样,所有加入该组播组的接收者都可以接收到相同的数据。

组播通信适用于需要同时将相同数据发送给多个接收者的场景,例如实时视频流、音频流、多媒体广播、在线会议等。相比单播(Unicast)一对一通信和广播(Broadcast)一对所有通信,组播可以减少网络带宽的使用,因为数据只需发送一次,而不是复制多份发送。

在组播通信中,路由器在网络中负责处理组播数据的传递。它们使用一种称为组播路由协议(Multicast Routing Protocol)的协议来确定数据应传递到哪些接收者。常见的组播路由协议包括多协议标签交换(Multiprotocol Label Switching, MPLS)和协议无关组播(Protocol Independent Multicast, PIM)。

组播地址

不分网络地址和主机地址,第1字节的前4位固定为1110 。是D类IP

224.0.0.1-239.255.255.255

组播结构体

#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

struct ip_mreq
{
    struct in_addr imr_multiaddr;   /* 指定多播组IP */
    struct in_addr imr_interface;   /* 本地网卡地址,通常指定为 INADDR_ANY--0.0.0.0 */
};

struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));  // 初始化 mreq 结构体为 0

mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");  // 设置多播组 IP 地址
mreq.imr_interface.s_addr = INADDR_ANY;  // 设置本地网卡地址为任意地址

setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
// 设置套接字选项,加入指定的多播组
// 参数说明:
// - sockfd: 套接字描述符
// - IPPROTO_IP: 指定 IP 协议
// - IP_ADD_MEMBERSHIP: 加入多播组的选项
// - &mreq: 指向 ip_mreq 结构体的指针,其中包含要加入的多播组 IP 和本地网卡地址
// - sizeof(mreq): ip_mreq 结构体的大小

组播发送流程

  1. 创建用户数据报套接字
  2. 接收方地址指定为组播地址
  3. 指定端口信息
  4. 发送数据包
//发送端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(int argc, char const *argv[])
{
    if(argc<2)
    {
        printf("please input addr and port\n");
        return -1;
    }
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket err.");
        exit(-1);
    }
    //绑定结构体
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(atoi(argv[2]));//输入端口是字符串,这里得转换一下
    saddr.sin_addr.s_addr=inet_addr(argv[1]);//组播ip
     char buf[128];
     while (1)
     {
         fgets(buf,sizeof(buf),stdin);
         sendto(socked,buf,sizeof(buf),0,(struct sockaddr*)&saddr,sizeof(saddr));
     }
     close(socked);
    return 0;
}

组播接收

  1. 创建用户数据报套接字
  2. 加入多播组
  3. 绑定IP地址(加入组的组IP或0.0.0.0)和端口
  4. 等待接收数据

加入多播组的核心代码

//接收端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>


int main(int argc, char const *argv[])
{
    if(argc<2)
    {
        printf("please input addr and port\n");
        return -1;
    }
    //创建套接字
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket err.");
        exit(-1);
    }
    //新增操作,将主机IP放到多播组
    struct ip_mreq mreq;//多播结构体
    mreq.imr_multiaddr.s_addr=inet_addr(argv[1]);//地址
    mreq.imr_interface.s_addr=inet_addr("0.0.0.0");
    //添加多播组权限
    setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
    
    //绑定结构体
    struct sockaddr_in saddr,caddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(atoi(argv[2]));//端口
    saddr.sin_addr.s_addr=inet_addr(argv[1]);//地址

    socklen_t len=sizeof(caddr);//提前计算出结构体得长度
    //绑定结构体
    if(bind(socked,(struct sockaddr*)&saddr,sizeof(saddr))<0)//出现问题
    {
        perror("bind err.");
        return -1;
    }
    char buf[128];
    while (1)
    {
        //接收客户端发来代码
        recvfrom(socked,buf,sizeof(buf),0,(struct sockaddr*)&caddr,&len);
        //inet_ntoa从机器到人 ntohs网络字节序到主机
        printf("ip =%s port=%d:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buf);    
    }
    close(socked);
    return 0;
}

代码结果

本地套接字通信

什么是本地套接字通信?

本地通信套接字(Local Communication Socket)是一种用于在同一台计算机上进行进程间通信的机制。它允许不同的进程通过在内核中创建的特殊文件描述符来进行相互通信。

本地通信套接字在操作系统中以文件的形式存在,通常称为"Unix域套接字"或"本地域套接字"。与网络套接字不同,本地通信套接字不涉及网络协议栈,而是直接通过内核中的特殊通信机制进行数据传输。

特性

  1. socket同样可以用于本地通信
  2. 创建套接字时使用本地协议AF_UNIX(或AF_LOCAL)
  3. 分为流式套接字和用户数据报套接字
  4. 和其他进程间通信方式相比使用方便、效率更高
  5. 常用于前后台进程通信

核心代码

#include <sys/socket.h>
#include <sys/un.h>

unix_socket = socket(AF_UNIX, type, 0);
// 创建一个 Unix 域套接字
// 参数说明:
// - AF_UNIX: 指定使用 Unix 域协议
// - type: 指定套接字的类型,如 SOCK_STREAM、SOCK_DGRAM 等
// - 0: 在创建套接字时不指定额外选项
struct sockaddr_un {
   sa_family_t sun_family;               /* AF_UNIX */
   char        sun_path[UNIX_PATH_MAX];  /* 本地路径 */
};

struct sockaddr_un myaddr;
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = AF_UNIX; 
strcpy(myaddr.sun_path, "mysocket");  // 可以指定路径

程序实例

注意:客户端和服务器是相互依赖的,需要先运行服务器程序,然后再运行客户端程序以建立连接并进行通信。

服务端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    //1.创建本读通信套接字
    int sockfd=socket(AF_UNIX,SOCK_STREAM,0);//这里选用了流式套接字
    if (sockfd<0)
    {
        perror("socker err.");
        return -1;
    }
    //2.填充本地通信套接字
    struct sockaddr_un saddr;
    saddr.sun_family=AF_UNIX;
    strcpy(saddr.sun_path,"./test");
    unlink("./test");//删除本地套接字
    //3.绑定本地套接字
    if(bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))<0)
    {
        perror("bind err");
        return -1;
    }
    //4.开启监听
    if(listen(sockfd,5)<0)
    {
        perror("listen err.");
        return -1;
    }
    //5.接收连接
    int acceptfd=accept(sockfd,NULL,NULL);//不关心发送者是谁,这里填NULL
    if(accept<0)
    {
        perror("accept err.");
        return -1;
    }
    //6.接收
    char buf[128];
    while (1)
    {
        int ret=recv(acceptfd,buf,sizeof(buf),0);
        if(ret<0)
        {
            perror("recv err.");
        }else if (ret == 0)//在三次握手时出现了
        {
            printf("client exit.\n");
            break;
        }else
        {
            printf("buf:%s\n",buf);
        }
    }
    close(sockfd);
    close(acceptfd);
    return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    //1.创建本读通信套接字
    int sockfd=socket(AF_UNIX,SOCK_STREAM,0);//这里选用了流式套接字
    if (sockfd<0)
    {
        perror("socker err.");
        return -1;
    }
    //2.填充本地通信套接字
    struct sockaddr_un saddr;
    saddr.sun_family=AF_UNIX;
    strcpy(saddr.sun_path,"./test");
    //3.建立链接
    if(connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))<0)
    {
        perror("connect err.");
        return -1;
    }
    char buf[128];
    while (1)
    {
        fgets(buf,sizeof(buf),stdin);
        send(sockfd,buf,sizeof(buf),0);//发送信息
    }
    close(sockfd);//关闭套接字
    return 0;
}

结果

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

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

相关文章

SpringCloud源码解析-gatewayopenFeign

SpringCloud高级应用-源码解析 1. gateway 源码解析1.1 自动装配1.2 核心装配1.2.1 GatewayClassPathWarningAutoConfiguration1.2.2 GatewayAutoConfiguration1.2.3 GatewayLoadBalancerClientAutoConfiguration1.2.4 GatewayRedisAutoConfiguration 1.3 Gateway 工作机制1.3.…

分布式任务调度XXL-JOB

XXL-JOB 分布式任务调度平台特点 职责分离&#xff0c;任务调度&#xff0c;任务执行解耦 执行一致性&#xff0c;任务执行不会多次重复执行 丰富的路由策略&#xff08;指定那个执行实例执行&#xff09; 阻塞处理 &#xff08;触发的任务&#xff0c;上一次没有执行完&am…

Android Studio类ChatGpt的免费AI编程助手

ChatGpt大火&#xff0c;带动了AI工具的发展&#xff0c;介绍两款免费的AI编程助手&#xff0c;一款用于输入关键字自动输出代码&#xff0c;一款则是自动补全提示&#xff0e; 可支持大部分代码编辑器&#xff0c;这里主要介绍Android Studio上安装使用&#xff0e; Bito 支…

来阿里面试,问我未来3-5年规划,我给领导画个大饼...

在面试的过程中是不是经常被面试官问未来几年的职业规划?你会答吗&#xff1f;是不是经常脑袋里一片空白&#xff0c;未来规划&#xff1f;我只是想赚更多的钱啊&#xff0c;哈哈哈&#xff0c;今天我来教大家&#xff0c;如何给面试官画一个大饼&#xff0c;让他吃的不亦乐乎…

c++day4 ——homework

1.思维导图 2. 整理类中特殊成员函数&#xff1a;构造函数&#xff0c;析构函数&#xff0c;拷贝构造函数&#xff0c;拷贝赋值函数的使用和实现 特殊成员函数的使用和实现&#xff1a; ① 构造函数 功能&#xff1a;当使用类实例化对象时&#xff0c;给类对象初始化空间以及初…

基于RK3399+FPGA的地面测试台多参数数据记录仪方案(一)硬件设计

地面测试台属于某型号数据记录仪的配套测试设备&#xff0c;主要工作包括&#xff1a;飞行前对记录 仪的功能检查&#xff0c;测试其工作状态和稳定性&#xff1b;实验结束后对已存储到记录仪中的数据进行 回读和进一步处理&#xff0c;通过数据分析得出导弹各项参数在飞行试…

苹果的首款“头显设备”Vision Pro在短期内必将被Meta Quest超越

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;Vision Pro是苹果在今年的WWDC2023开发者大会上发布的一款结合了增强现实(AR)和虚拟现实(VR)的“头显设备”&#xff0c;Vision Pro 的最终售价高达 3499 美元&#xff08;约合…

观察级水下机器人使用系列之二多普勒速度记录仪(DVL)

本文主要讲述观察级水下机器人所使用的多普勒速度记录仪器&#xff08;DVL&#xff09;&#xff0c;见下图。多普勒测速技术自1960年开始研究&#xff0c;1980年开始实现商业化&#xff0c;80年代中后期&#xff0c;窄带多普勒测速技术研究已日趋成熟&#xff0c;90年代以后&am…

初学者应该怎么学git-上

初学者应该怎么学git-上 Git 下载&安装 官网 地址: https://git-scm.com/ 下载版本: Git-2.33.0.2-64-bit.exe 下载慢&#xff0c;可以到镜像下载: http://npm.taobao.org/mirrors/git-for-windows/ 卸载 说明&#xff1a;如果安装过&#xff0c;可以卸载和老师版本…

详解Java中static的使用及其注意事项

1.可以用来修饰的结构&#xff1a; 主要用来修饰类的内部结构 属性、方法、代码块、内部类 2.static修饰属性&#xff1a;静态变量&#xff08;或类变量&#xff09; ​ 2.1 属性&#xff0c;是否使用static修饰&#xff0c;又分为&#xff1a;静态属性 vs 非静态属性(实例…

Yolov5更换上采样方式( 最近邻 / 双线性 / 双立方 / 三线性 / 转置卷积)

原文地址: https://www.iotword.com/3138.html 1. 常用上采样方式介绍 1. 1 最近邻插值(Nearest neighbor interpolation) >>> input torch.arange(1, 5, dtypetorch.float32).view(1, 1, 2, 2) >>> input tensor([[[[ 1., 2.],[ 3., 4.]]]])>>&g…

【goframe】(4):使用goframe 接入grpc服务,非常的方便,可以简单的构建和生成服务代码,并且启动方法也特别简单,使用代码本地调用成功

目录 前言1&#xff0c;关于grpc微服务2&#xff0c;修改生成代码3&#xff0c;相关的goframe的grpc配置4&#xff0c;总结 前言 本文的原文连接是: https://blog.csdn.net/freewebsys/article/details/108971807 未经博主允许不得转载。 博主CSDN地址是&#xff1a;https://b…

3.变量|Java学习笔记

文章目录 数据类型整型的类型浮点型的类型字符类型boolean类型 基本数据类型转换自动类型转换强制类型转换 基本数据类型和String类型的转换 变量 变量名 值 数据类型 https://www.matools.com/# 数据类型 整型的类型 浮点型的类型 关于浮点数在机器中存放形式的简单说明&…

Ibatis与Mybatis的区别—侧重于Ibatis

目录 一、什么是Ibatis&#xff1f; 1、iBatis是一款轻量级的持久化框架 2、iBatis最大的特点是将SQL语句与Java代码分离 3、iBatis具有以下几个关键组成部分&#xff1a; 二、Ibatis与Mybatis的区别 1、基本信息不同 2、开发时间不同 3、配置方法不同 三、Ibatis与My…

HotSpot虚拟机垃圾回收算法及收集器

目录 一、对象引用 二、堆区和方法区回收 1. 堆区回收 2. 方法区回收 三、垃圾回收算法 1. 算法总结 2. 算法相关细节 四、垃圾收集器 1. 新生代收集器 2. 老年代收集器 3. 混合式收集器G1 4. 低延迟收集器 五、参考资料 一、对象引用 判定对象是否存活和引用离…

Unix/Linux编程:Unix domain socket

〇、前言 socket 是一种 IPC &#xff08;Inter-Process Communication&#xff0c;进程间通信&#xff09;方法&#xff0c;它允许位于同一主机&#xff08;计算机&#xff09;或使用网络连接起来的不同主机上的应用程序之间交换数据。通过使用Socket&#xff0c;开发人员可以…

在VSCode中使用LaTex,语法检测插件grammarly

整个文章分为以下几个内容&#xff0c;打 * 的是必须要安装的 LaTex 安装*VSCode 安装*在 VSCode 中配置 LaTexGrammarly语法检测插件 LaTex 安装* latex的下载安装可参考&#xff1a;LaTex&#xff08;2021&#xff09;安装教程 VSCode 安装* VSCode下载&#xff1a;VSCo…

带你用WePY框架提升开发效率

在小程序开发中&#xff0c;提高开发效率、优化代码质量和增强用户体验是每位开发者都追求的目标。而wepy作为一种基于Vue.js的小程序开发框架&#xff0c;提供了更好的开发体验和更高效的开发方式。本文将介绍wepy的基本功能和特性&#xff0c;分享一些实际的代码案例&#xf…

图像的匹配

2023.6.7 图像的匹配 模板匹配是一种在较大图像中搜索和查找模板图像位置的方法。为此&#xff0c;OpenCV 带有一个函数 cv.matchTemplate()。它只是在输入图像上滑动模板图像&#xff08;如在 2D 卷积中&#xff09;&#xff0c;并比较模板图像下的模板和输入图像的补丁。在…

STM32——CAN通信

1、CAN通信概述 STM32F103有两个CAN&#xff0c;都分别有自己的发送接收邮箱。 发送邮箱共有3个来发送报文&#xff0c;发送调度器根据优先级决定哪个邮箱的报文先被发送。 共有2个接收FIFO&#xff0c;每个FIFO都可以存放3个完整的报文。它们完全由硬件来管理。 CAN通信通过…