Bootstrap

深入UDP收发数据(上)

问题

如何进行一对多的 UDP 数据发送?

UDP 通信中的广播

广播是向同一网络中的所有主机传输数据的方法

广播类型

  • 直接广播: IP 地址中除网络地址外,其余主机地址均设置为1
  • 本地广播: 无须知道网络地址,255.255.255.255作为 IP 地址使用

区别:

  • 本地广播数据不经过路由器寻址,直接发送到本地主机

本地广播应用应用案例: DHCP

DHCP (动态主机配置协议) 是一个局域网的网络协议 (基于 UDP 协议)

  • 本地主机可自动获取到服务器分配的 IP 地址和子网掩码

DHCP 采用 客户端/服务器 模型,地址的动态分配由网络主机驱动

工作方式:

  • 当 DHCP 服务器接收到来自网络主机的目标申请时,会向网络主机发送相关的地址配置信息,以实现网络主机地址信息的动态配置

本地主机想要获取 IP 地址,首先会在本地广播一个数据包,源IP地址为0.0.0.0,目标IP地址为255.255.255.255,DHCP 服务器收到此数据包后,会回复本地主机;本地主机获取到的 IP 地址是有期限的,快到期限的时候,本地主机会继续广播,请求继续使用此 IP 地址。

预备工作 => socket 属性设置 (option)

socket 的本质是对本机网络资源的一种标识

socket 本身有各种属性 (不同的连接,属性可能不同)

通过 setsockopt() / getsockopt() 可存取指定 socket 的属性值

socket 属性的改变可造成 socket 数据收发行为的改变

TCP 编程中涉及的用法

setsockopt() / getsockopt() 属性存取函数

UDP 数据广播

编程实验

client.c

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

int main()
{
    int server = 0;
    struct sockaddr_in addr = {0};
    struct sockaddr_in remote = {0};
    char buf[128] = "D.T.SoftWare\n";
    int len = 0;
    int brd = 1;

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8888);

    remote.sin_family = AF_INET;
    remote.sin_addr.s_addr = inet_addr("192.168.197.255");
    // remote.sin_addr.s_addr = 0xFFFFFFFF;
    remote.sin_port = htons(6666);

    server = socket(PF_INET, SOCK_DGRAM, 0);

    if(server < 0)
    {
        printf("server socket error\n");

        return -1;
    }

    if(bind(server, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    {
        printf("udp server bind error\n");

        return -1;
    }

    setsockopt(server, SOL_SOCKET, SO_BROADCAST, &brd, sizeof(brd));

    printf("udp server start success!\n");

    while(1)
    {
        len = sizeof(remote);

        sendto(server, buf, strlen(buf), 0, (struct sockaddr*)&remote, len); 

        sleep(1);     
    }

    close(server);

    return 0;
}

server.c

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

int main()
{
    int sock = 0;
    struct sockaddr_in remote = {0};
    struct sockaddr_in addr = {0};
    char buf[128] = {0};
    int r = 0;
    socklen_t len = 0;

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(6666);

    if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        printf("client socket error\n");

        return -1;
    }

    if(bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        printf("udp client bind errpr\n");

        return -1;
    }

    while(1)
    {
       len = sizeof(remote);

        r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);

        if(r > 0)
        {
            buf[r] = 0;

            printf("Receive: %s\n", buf);
        }
    }

    close(sock);
}

192.168.197.xxx网段下的所有6666端口的进程都能够收到广播。

思考

UDP 是否还有其他一对多的数据发送方式? 

;