Linux網絡編程四、UDP,廣播和組播


 一、UDP

  UDP:是一個支持無連接的傳輸協議,全稱是用戶數據包協議(User Datagram Protocol)。UDP協議無需像TCP一樣要建立連接后才能發送封裝的IP數據報,也是因此UDP相較於TCP效率更高一些,但是由於沒有建立連接,UDP只管發送數據,不管數據是否被接收,所以UDP傳輸數據是不安全的,容易丟包。

  通信流程:

  服務端

    1、創建通信用套接字:socket(AF_INET, SOCK_DGRAM, 0);   和TCP不同之處在於第二個參數改為SOCK_DGRAM。

    2、綁定套接字:bind(...);

    3、通信:接收數據,recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);。發送數據,sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, const socklen_t *addrlen);  第五個參數都是另一端的信息,src_addr是傳出參數。

  客戶端同服務端。

二、廣播

  廣播:在IP子網內廣播數據包,所有在子網內部的主機都將收到這些數據包。廣播的使用范圍僅在本地子網中,通過路由器控制廣播的傳輸。廣播地址:xxx.xxx.xxx.255。

  通信流程:

    1、創建並綁定套接字,同UDP。

    2、初始化客戶端信息,主要是設置客戶端ip為廣播地址。

    3、開放服務器的廣播權限:int flag = 1;   setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));

    4、給客戶端(子網內的主機)發送數據。

  客戶端同UDP,不能向服務器發送數據。

//server//
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <arpa/inet.h> int main(int argc, const char* argv[]) { // 創建套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket error"); exit(1); } // 綁定server的iP和端口 struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_port = htons(8787); // server端口 serv.sin_addr.s_addr = htonl(INADDR_ANY); int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv)); if(ret == -1) { perror("bind error"); exit(1); } // 初始化客戶端地址信息 struct sockaddr_in client; memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(6767); // 客戶端要綁定的端口 // 使用廣播地址給客戶端發數據 inet_pton(AF_INET, "192.168.123.255", &client.sin_addr.s_addr); // 給服務器開放廣播權限 int flag = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag)); // 通信 while(1) { // 一直給客戶端發數據 static int num = 0; char buf[1024] = {0}; sprintf(buf, "hello, udp == %d\n", num++); int ret = sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client)); if(ret == -1) { perror("sendto error"); break; } printf("server == send buf: %s\n", buf); sleep(1); } close(fd); return 0; }
//client//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket error");
        exit(1);
    }

    // 綁定iP和端口
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767);  
    inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
    int ret  = bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
        perror("bind error");
        exit(1);
    }

    // 接收數據
    while(1)
    {
        char buf[1024] = {0};
        int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
        if(len == -1)
        {
            perror("recvfrom error");
            break;
        }
        
        printf("client == recv buf: %s\n", buf);
    }

    close(fd);
    
    return 0;
}

三、組播

  組播:在發送者和每一接收者之間實現點對多點網絡連接。如果一台發送者同時給多個接收者傳輸相同的數據,也只需復制一份相同的數據包。它提高了數據傳送效率,減少了骨干網絡出現擁塞的可能性。組播不同於廣播的地方在於其不局限於局域網,而且其效率比廣播更高。

  組播地址:224.0.0.0~224.0.0.255,預留組播地址(永久組地址),224.0.0.0保留不做分配,其它地址供路由器協議使用。224.0.1.0~224.0.1.255,公用組播地址,可以用於Internet,需要申請。224.0.2.0~238.255.255.255,用戶可用組播地址(臨時組地址),全網有效。239.0.0.0~239.255.255.255,本地管理組播地址, 僅在特定的本地范圍內有效。

  通信流程:

    1、創建並綁定套接字,同UDP。

    2、初始化客戶端地址信息,設置組播地址和客戶端要綁定的端口。

    3、開放組播權限

// 給服務器開放組播權限
    struct ip_mreqn flag;
    // init flag
    inet_pton(AF_INET, "239.0.0.10", &flag.imr_multiaddr.s_addr);   // 組播地址
    inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr);    // 本地IP
    flag.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag));

    客戶端,綁定端口要與服務端設置的相一致

    客戶端加入到組播地址

// 加入到組播地址
    struct ip_mreqn fl;
    inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr);
    inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
    fl.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl));
//server//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, const char* argv[])
{
    // 創建套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket error");
        exit(1);
    }

    // 綁定server的iP和端口
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family  = AF_INET;
    serv.sin_port = htons(8787);    // server端口
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
        perror("bind error");
        exit(1);
    }

    // 初始化客戶端地址信息
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767);  // 客戶端要綁定的端口
    // 使用組播地址給客戶端發數據
    inet_pton(AF_INET, "239.0.0.10", &client.sin_addr.s_addr);

    // 給服務器開放組播權限
    struct ip_mreqn flag;
    // init flag
    inet_pton(AF_INET, "239.0.0.10", &flag.imr_multiaddr.s_addr);   // 組播地址
    inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr);    // 本地IP
    flag.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag));

    // 通信
    while(1)
    {
        // 一直給客戶端發數據
        static int num = 0;
        char buf[1024] = {0};
        sprintf(buf, "hello, udp == %d\n", num++);
        int ret = sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client));
        if(ret == -1)
        {
            perror("sendto error");
            break;
        }
        
        printf("server == send buf: %s\n", buf);

        sleep(1);
    }
    
    close(fd);

    return 0;
}
//client//
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, const char* argv[])
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket error");
        exit(1);
    }

    // 綁定iP和端口
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767); // ........ 
    inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
    int ret  = bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
        perror("bind error");
        exit(1);
    }

    // 加入到組播地址
    struct ip_mreqn fl;
    inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr);
    inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
    fl.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl));

    // 接收數據
    while(1)
    {
        char buf[1024] = {0};
        int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
        if(len == -1)
        {
            perror("recvfrom error");
            break;
        }
        
        printf("client == recv buf: %s\n", buf);
    }

    close(fd);
    
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM