Linux网络编程广播/组播创建和设置

本文详细介绍了如何在编程中使用getsockopt和setsockopt函数来获取和设置套接字属性,包括SOL_SOCKET、IPPROTO_IP和IPPROTO_TCP层的选项,以及A、B、C、D类网络地址、广播和组播的概念。展示了如何在客户端和服务器间实现广播和组播的数据传输。
摘要由CSDN通过智能技术生成

       

获取/设置套接字属性

  • 1、getsockopt()获取套接字属性

  • 2、setsockopt()设置套接字属性

  • 参数

    • sockfd:套接字文件描述符
    • level:设置属性层
      • SOL_SOCKET:通用套接字层
      • IPPROTO_IP:IP层
      • IPPRO_TCP:TCP层
    • optname:指定操作,一般用宏表示
    • optval:设置属性对应的值
    • optlen:设置属性对应长度
  • 返回值

    • 成功返回 0,失败返回-1                       

level网络属性设置

                                              * SOL_SOCKET

    | optname                                                                    | optval类型     |

    | ------------------------------------------ | -------------- |

    | **SO_BROADCAST**  允许发送广播数据          | int            |

    | SO_DEBUG      允许调试                               | int            |

    | SO_DONTROUTE  不查找路由                           | int            |

    | SO_ERROR     获得套接字错误                   | int            |

    | SO_KEEPALIVE             保持连接                            | int            |

    | SO_LINGER     延迟关闭连接                      | struct linger  |

    | SO_OOBINLINE   带外数据放入正常数据流     | int            |

    | SO_RCVBUF      接收缓冲区大小                   | int            |

    | SO_SNDBUF     发送缓冲区大小                    | int            |

    | SO_RCVLOWAT    接收缓冲区下限                   | int            |

    | SO_SNDLOWAT   发送缓冲区下限                    | int            |

    | SO_RCVTIMEO     接收超时                              | struct timeval |

    | SO_SNDTIMEO    发送超时                               | struct timeval |

    | **SO_REUSEADDR**  允许重用本地地址和端口 | int            |

    | SO_TYPE       获得套接字类型                   | int            |

    | SO_BSDCOMPAT    与BSD系统兼容                    | int            |

                                          * IPPROTO_IP

    | optname                                                                            | optval类型     |

    | --------------------------------------------------                                 | -------------- |

    | IP_ADD_MEMBERSHIP   将指定IP加入到组播组中         | struct ip_mreq |

    | IP_MULTICAST_IF             允许开启组播报文的接口         | struct ip_mreq |

                                          * IPPRO_TCP

    | optname                                                 | optval类型 |

    | -------------------------------         | ---------- |

    | TCP_MAXSEG TCP最大数据段的大小   | int        |

    | TCP_NODELAY  不使用Nagle算法            | int        |

网络地址

  • A类地址

    • 第一字节为网络地址,其他3个字节为主机地址。第一字节的最高位固定为0
      1.0.0.1—126.255.255.255
  • B类地址

    • 第一字节和第二字节是网络地址,其他2个字节是主机地址。第一字节的前三位固定为10
      128.0.0.1—191.255.255.255​
  • C类地址

    • 前三个字节是网络地址,最后一个字节是主机地址。第一字节的前三位固定为110
      192.0.0.1—223.255.255.255
  • D类地址(组播地址)

    • 不分网络地址和主机地址,第一个字节的前四位固定为1110
      224.0.0.1—239.255.255.255

广播

  • 同时发给局域网中的所有主机
  • IP:192.168.7.215 子网掩码:255.255.255.0 则网络号为:192.168.7(ip和掩码相与) 广播地址为:192.168.7.255
  • 只有用户数据报(使用UDP协议)套接字才能广播
  • 255.255.255.255在所有网段中都代表广播地址

1、发送方——客户端

  • 创建用户数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0)

  • 缺省创建的套接字不允许广播数据包,需要设置属性
    setsockopt可以设置套接字属性
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));

  • 接收方地址指定为广播地址,指定端口信息
    struct sockaddr_in saddr;
    saddr.sin_port = htons(8989);
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = inet_addr("192.168.7.255");

  • 发送数据包
    char sendbuf[32] = {0};
    while(1)
    {
    read(0, sendbuf, sizeof(sendbuf));
    sendto(sockfd, sendbuf, sizeof(sendbuf), (struct sockaddr*)&saddr, sizeof(saddr));
    memset(sendbuf, 0, sizeof(sendbuf));
    ​}

  • #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    { 
        //创建用户数据报套接字
        int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    
        //缺省创建的套接字不允许广播数据包,需要设置属性
        //setsockopt可以设置套接字属性
        int opt = 1;
        setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));
        //接收方地址指定为广播地址 指定端口信息
        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        saddr.sin_port   = htons(8848);
        saddr.sin_addr.s_addr = inet_addr("192.168.7.255");
        //循环发送数据包
        char sendBuf[32] = {0};
        while(1)
        {
            read(0,sendBuf,sizeof(sendBuf));
            sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
        }
    
        return 0;
    } 
    

2、接收方——服务器

  • 创建用户数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0)

  • 绑定ip地址和端口
    struct sockaddr_in saddr;
    ​saddr.sin_port = htons(8989);
    ​saddr.sin_family = AF_INET;
    ​saddr.sin_addr.s_addr = inet_addr("192.168.7.255");
    bind(sockfd, (struct sockaddr*)&saddr,sizeof(saddr));

  • 等待接收数据
    char recvbuf[32] = {0};
    ​while(1)
    ​{
    ​recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0,NULL,NULL);
    memset(recvbuf, 0 , sizeof(recvbuf));
    ​}

  • 发送数据包
    char sendbuf[32] = {0};
    while(1)
    {
    read(0, sendbuf, sizeof(sendbuf));
    sendto(sockfd, sendbuf, sizeof(sendbuf), (struct sockaddr*)&saddr, sizeof(saddr));

  • #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    { 
        //创建用户数据报套接字
        int sockfd = socket(AF_INET,SOCK_DGRAM,0);
        //绑定IP地址(广播IP或0.0.0.0)和端口
        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        saddr.sin_port   = htons(8848);
        saddr.sin_addr.s_addr = inet_addr("192.168.7.255");
        //绑定的端口必须和发送方指定的端口相同
        bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
        //等待接收数据
        char recvBuf[32] = {0};
        while(1)
        {
            recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
            printf("recvBuf:%s\n",recvBuf);
            memset(recvBuf,0,sizeof(recvBuf));
        }
    
        return 0;
    } 
    

组播

        广播方式发给所有主机,过多的广播会占用大量的网络带宽,造成广播风暴,影响正常通信。

        组播又称为多播,是一种折中的方式,只有加入某个多播组的主机才能接收到数据。

        多播方式既可以发给多个主机,又能避免像广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)。

发送方

  • 创建用户数据报套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);

  • 接收方地址指定为组播地址

  • 指定端口信息
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("224.10.10.10");
  • 发送数据包
    char sendBuf[32] = {0};
    while(1)
    {
    read(0,sendBuf,sizeof(sendBuf));
    sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
    }

  • #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    { 
        //创建用户数据报套接字
        int sockfd = socket(AF_INET,SOCK_DGRAM,0);
        //接收方地址指定为组播地址 指定端口信息 224.10.10.10
        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        saddr.sin_port   = htons(8848);
        saddr.sin_addr.s_addr = inet_addr("224.10.10.10");
        //发送数据包
        char sendBuf[32] = {0};
        while(1)
        {
            read(0,sendBuf,sizeof(sendBuf));
            sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
        }
    
        return 0;
    } 

接收方

  • 创建用户数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM,0);

  • 加入多播组
    /*
    struct ip_mreq {
    struct in_addr imr_multiaddr; /* IP multicast address of group */
    struct in_addr imr_interface; /* local IP address of interface */
    };
    */
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
    mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
    setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

  • 绑定IP地址(加入组的IP或0.0.0.0)和端口(绑定的端口必须和发送方指定的端口相同)
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));

  • 接收数据
    char recvBuf[32] = {0};
    while(1)
    {
    recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
    printf("recvBuf:%s\n",recvBuf);
    memset(recvBuf,0,sizeof(recvBuf));
    }

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

int main(int argc, char *argv[])
{ 
    //创建用户数据报套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    //加入多播组
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
    mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
    setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
    //绑定IP地址(加入组的组IP或0.0.0.0)和端口 绑定的端口必须和发送方指定的端口相同
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    //等待接收数据
    char recvBuf[32] = {0};
    while(1)
    {
        recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
        printf("recvBuf:%s\n",recvBuf);
        memset(recvBuf,0,sizeof(recvBuf));
    }

    return 0;
} 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值