Lập trình mạng nhúng - Triển khai Broadcast và Multicast

Mục lục

  1. Broadcast
    1. Broadcast là gì?
    2. Địa chỉ Broadcast
    3. Triển khai Broadcast
  2. Multicast
    1. Phân loại địa chỉ IP
    2. Địa chỉ IP Multicast
    3. Triển khai Multicast

Broadcast

Broadcast là gì?

Phương thức gửi gói dữ liệu chỉ có một bên nhận được được gọi là Unicast (gửi đơn).

Nếu gửi đồng thời cho tất cả các máy trong mạng cục bộ, đó được gọi là Broadcast (phát).

Chỉ socket giao thức người dùng (sử dụng giao thức UDP) mới có thể thực hiện broadcast.

Địa chỉ Broadcast

  • Địa chỉ IP có địa chỉ mạng bất kỳ và địa chỉ máy toàn bộ là 1 là địa chỉ broadcast
  • Gói dữ liệu gửi đến địa chỉ này sẽ được tất cả các máy chủ nhận
  • 255.255.255.255 là địa chỉ broadcast trên tất cả các mạng

Triển khai Broadcast

Mã nguồn gửi (sender.c)

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

#define XuatLoi(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr DiaChi;
typedef struct sockaddr_in DiaChi_in;

int main(int argc, char *argv[])
{
    int socket_desc = -1;
    DiaChi_in dia_chi_nhan;
    socklen_t kich_thuoc_dia_chi = sizeof(dia_chi_nhan);
    char buffer[BUFSIZ] = {};
    
    /*Kiểm tra tham số đầu vào*/
    if(argc < 3){
        fprintf(stderr, "%s<dia_chi_broadcast><port>", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    /*Tạo socket*/
    if((socket_desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        XuatLoi("socket");

    /*Cho phép phát broadcast*/
    int phep_broad = 1;
    setsockopt(socket_desc, SOL_SOCKET, SO_BROADCAST, &phep_broad, sizeof(phep_broad));

    /*Cấu trúc kết nối*/
    dia_chi_nhan.sin_family = AF_INET;
    dia_chi_nhan.sin_port = htons(atoi(argv[2]));
    if(!inet_aton(argv[1], &dia_chi_nhan.sin_addr)){
        fprintf(stderr, "Địa chỉ không hợp lệ\n");
        exit(EXIT_FAILURE);
    }
    
    while(1){
        fgets(buffer, BUFSIZ, stdin);
        sendto(socket_desc, buffer, strlen(buffer)+1, 0, (DiaChi *)&dia_chi_nhan, kich_thuoc_dia_chi);
    }
    return 0;
}

Mã nguồn nhận (receiver.c)

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

#define XuatLoi(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr DiaChi;
typedef struct sockaddr_in DiaChi_in;

int main(int argc, char *argv[])
{
    int socket_desc = -1;
    DiaChi_in dia_chi_toi, dia_chi_nguoi_gui;
    socklen_t kich_thuoc_dia_chi = sizeof(dia_chi_nguoi_gui);
    char buffer[BUFSIZ] = {};
    
    /*Kiểm tra tham số đầu vào*/
    if(argc < 3){
        fprintf(stderr, "%s<dia_chi><port>", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    /*Tạo socket*/
    if((socket_desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        XuatLoi("socket");
    
    /*Cấu trúc kết nối*/
    dia_chi_toi.sin_family = AF_INET;
    dia_chi_toi.sin_port = htons(atoi(argv[2]));
    if(!inet_aton(argv[1], &dia_chi_toi.sin_addr)){
        fprintf(stderr, "Địa chỉ không hợp lệ\n");
        exit(EXIT_FAILURE);
    }
    
    /*Gắn kết cấu trúc*/
    if(bind(socket_desc, (DiaChi *)&dia_chi_toi, sizeof(DiaChi_in)))
        XuatLoi("bind");
    
    while(1){
        recvfrom(socket_desc, buffer, BUFSIZ, 0, (DiaChi *)&dia_chi_nguoi_gui, &kich_thuoc_dia_chi);
        printf("[%s:%d]%s\n", inet_ntoa(dia_chi_nguoi_gui.sin_addr), ntohs(dia_chi_nguoi_gui.sin_port), buffer);
    }
    return 0;
}

Multicast

Phân loại địa chỉ IP

Địa chỉ IP được phân thành nhiều loại, trong đó địa chỉ D Class (224.0.0.0 - 239.255.255.255) được dành riêng cho multicast.

Địa chỉ IP Multicast

  • Gói dữ liệu đa hướng cần địa chỉ đích là định danh của nhóm multicast.
  • Định danh của nhóm multicast chính là địa chỉ D Class (địa chỉ multicast). Phạm vi: 224.0.0.0 ~ 239.255.255.255
  • Mỗi địa chỉ D Class đại diện cho một nhóm multicast.
  • Địa chỉ multicast chỉ có thể được sử dụng làm địa chỉ đích, không thể làm địa chỉ nguồn.

Triển khai Multicast

  1. Tạo socket giao thức người dùng (datagram socket)
  2. Tham gia vào nhóm multicast
  3. Gắn địa chỉ IP multicast và cổng
  4. Chờ nhận dữ liệu
struct ip_mreqn {
    struct in_addr imr_multiaddr;  /*Địa chỉ nhóm multicast*/
    struct in_addr imr_address;   /*Địa chỉ IP của giao diện cục bộ*/
    int                   imr_ifindex;   /*Mã số của card mạng cục bộ*/
}
if(setsockopt(socket_desc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0){
    perror("setsockopt");
    exit(0);
}

Mã nguồn gửi (sender.c)

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

#define XuatLoi(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr DiaChi;
typedef struct sockaddr_in DiaChi_in;

int main(int argc, char *argv[])
{
    int socket_desc = -1;
    DiaChi_in dia_chi_nhan;
    socklen_t kich_thuoc_dia_chi = sizeof(dia_chi_nhan);
    char buffer[BUFSIZ] = {};
    
    /*Kiểm tra tham số đầu vào*/
    if(argc < 3){
        fprintf(stderr, "%s<dia_chi_multicast><port>", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    /*Tạo socket*/
    if((socket_desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        XuatLoi("socket");
    
    /*Cấu trúc kết nối*/
    dia_chi_nhan.sin_family = AF_INET;
    dia_chi_nhan.sin_port = htons(atoi(argv[2]));
    if(!inet_aton(argv[1], &dia_chi_nhan.sin_addr)){
        fprintf(stderr, "Địa chỉ không hợp lệ\n");
        exit(EXIT_FAILURE);
    }
    
    while(1){
        fgets(buffer, BUFSIZ, stdin);
        sendto(socket_desc, buffer, strlen(buffer)+1, 0, (DiaChi *)&dia_chi_nhan, kich_thuoc_dia_chi);
    }
    return 0;
}

Mã nguồn nhận (receiver.c)

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

#define XuatLoi(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr DiaChi;
typedef struct sockaddr_in DiaChi_in;

int main(int argc, char *argv[])
{
    int socket_desc = -1;
    DiaChi_in dia_chi_toi, dia_chi_nguoi_gui;
    socklen_t kich_thuoc_dia_chi = sizeof(dia_chi_nguoi_gui);
    struct ip_mreqn mreq;
    char buffer[BUFSIZ] = {};
    
    /*Kiểm tra tham số đầu vào*/
    if(argc < 3){
        fprintf(stderr, "%s<dia_chi><port>", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    /*Tạo socket*/
    if((socket_desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        XuatLoi("socket");
    
    /*Tham gia nhóm multicast*/
    bzero(&mreq, sizeof(mreq));
    if(!inet_aton(argv[1], &mreq.imr_multiaddr)){
        fprintf(stderr, "Địa chỉ không hợp lệ\n");
        exit(EXIT_FAILURE);
    }
    
    if(setsockopt(socket_desc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0){
        perror("setsockopt");
        exit(0);
    }
    
    /*Cấu trúc kết nối*/
    dia_chi_toi.sin_family = AF_INET;
    dia_chi_toi.sin_port = htons(atoi(argv[2]));
    if(!inet_aton(argv[1], &dia_chi_toi.sin_addr)){
        fprintf(stderr, "Địa chỉ không hợp lệ\n");
        exit(EXIT_FAILURE);
    }
    
    /*Gắn kết cấu trúc*/
    if(bind(socket_desc, (DiaChi *)&dia_chi_toi, sizeof(DiaChi_in)))
        XuatLoi("bind");
    
    while(1){
        recvfrom(socket_desc, buffer, BUFSIZ, 0, (DiaChi *)&dia_chi_nguoi_gui, &kich_thuoc_dia_chi);
        printf("[%s:%d]%s\n", inet_ntoa(dia_chi_nguoi_gui.sin_addr), ntohs(dia_chi_nguoi_gui.sin_port), buffer);
    }
    return 0;
}

Thẻ: embedded-networking broadcast multicast UDP socket-programming

Đăng vào ngày 3 tháng 7 lúc 09:33