C语言实现广播Echo通信

实验描述:

1 服务端发起广播

2 服务端设置超时等待10秒 如果没有收到回复 则再次广播

3 客户端启动后 将永久阻塞等待接听广播

4 客户端收到广播后 处理3秒 echo 服务器一条消息

5 服务器打印出这条消息

注意事项:

可复制多个客户端 观察现象

主要用于带有gnu_c 的unix-like系统 其他系统可能要对代码进行改造

服务端:

#define _GNU_SOURCE
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>

// 这是广播地址
#define BROADCAST_IP "192.168.142.255"
#define BROADCAST_PORT 55500
// 这是bind的服务器地址
#define SERVER_IP "192.168.142.132"
#define SERVER_PORT 55500
// 服务器
int main()
{
    int server_sockfd;
    struct sockaddr_in server_sockaddr, broadcast_sockaddr;
    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
    memset(&broadcast_sockaddr, 0, sizeof(broadcast_sockaddr));
    socklen_t broadcast_sockaddr_len = sizeof(broadcast_sockaddr);
    socklen_t server_sockaddr_len = sizeof(server_sockaddr);
    ssize_t send_bytes, recv_bytes;
    char send_buf[1024] = "server broadcast : How can I help you today ?";
    char recv_buf[1024] = {0};
    struct timeval tv = {0};
    tv.tv_sec = 10;
    tv.tv_usec = 0;
    server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    int optval = 1;
    // 允许server_sockfd发送广播
    setsockopt(server_sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
    // 无客户端连接的情况下 recvfrom 超时等待10秒
    setsockopt(server_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

    inet_pton(AF_INET, SERVER_IP, &server_sockaddr.sin_addr.s_addr);
    server_sockaddr.sin_port = htons(SERVER_PORT);
    server_sockaddr.sin_family = AF_INET;
    // 绑定上服务器自己的端口及地址,用于recvfrom
    bind(server_sockfd, (struct sockaddr *)&server_sockaddr, server_sockaddr_len);
    // 广播地址设置
    inet_pton(AF_INET, BROADCAST_IP, &broadcast_sockaddr.sin_addr.s_addr);
    broadcast_sockaddr.sin_port = htons(BROADCAST_PORT);
    broadcast_sockaddr.sin_family = AF_INET;

    while (1)
    {
        // 广播
        send_bytes = sendto(server_sockfd, send_buf, strlen(send_buf), 0,
                            (struct sockaddr *)&broadcast_sockaddr, broadcast_sockaddr_len);
        printf("%s\n", send_buf);
        // 等待回复,没收到回复则再次循环
        recv_bytes = recvfrom(server_sockfd, recv_buf, sizeof(recv_buf), 0, NULL, NULL);
        if (recv_bytes == -1)
        {
            if (errno == EAGAIN)
            {
                continue;
            }
        }
        if (recv_bytes > 0)
        {
            printf("%s\n", recv_buf);
            memset(recv_buf, 0, sizeof(recv_buf));
        }
    }
    close(server_sockfd);
    return 0;
}

客户端:

#define _GNU_SOURCE
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define BROADCAST_PORT 55500
// 客户端
int main()
{
    int client_sockfd;
    struct sockaddr_in server_sockaddr, client_sockaddr;
    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
    memset(&client_sockaddr, 0, sizeof(client_sockaddr));
    socklen_t client_sockaddr_len = sizeof(client_sockaddr);
    socklen_t server_sockaddr_len = sizeof(server_sockaddr);
    ssize_t send_bytes, recv_bytes;
    char send_buf[1024] = "kali : give me money !";
    char recv_buf[1024] = {0};
    // ipv4 udp
    client_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    int optval = 1;
    // 将client_sockfd绑定的地址及端口设为可重用,应对同一系统多进程多线程客户端
    setsockopt(client_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    client_sockaddr.sin_family = AF_INET;
    // 监听所有地址包括广播,指定到特定地址例如本机ip则无法监听广播
    client_sockaddr.sin_addr.s_addr = INADDR_ANY;
    // 监听广播端口
    client_sockaddr.sin_port = htons(BROADCAST_PORT);
    if (bind(client_sockfd, (struct sockaddr *)&client_sockaddr, client_sockaddr_len) == -1)
    {
        perror("bind");
    }
    while (1)
    {
        printf("-----UCP BROADCAST START-----\n");
        // server_sockaddr中包含真实服务器ip地址和广播端口号,不一定是是服务器bind的接收端口号,但这里设成了同一端口
        // 只有收到广播 recvfrom才返回
        recv_bytes = recvfrom(client_sockfd, recv_buf, sizeof(recv_buf), 0,
                              (struct sockaddr *)&server_sockaddr, &server_sockaddr_len);
        printf("%s\n", recv_buf);
        for (size_t i = 3; i > 0; i--)
        {
            printf("%zu\n", i);
            sleep(1);
        }
        // 因为获得了服务器的真实ip和同一端口,所以可以直接回复
        send_bytes = sendto(client_sockfd, send_buf, strlen(send_buf), 0,
                            (struct sockaddr *)&server_sockaddr, server_sockaddr_len);
        printf("%s\n", send_buf);
        printf("-----UCP BROADCAST END-------\n\n");
    }

    close(client_sockfd);
    return 0;
}

相关推荐

  1. C语言实现广播Echo通信

    2024-03-26 10:22:01       36 阅读
  2. C# 通过广播实现局域网自动连接

    2024-03-26 10:22:01       41 阅读
  3. C#实现简单同步Echo服务端和客户端

    2024-03-26 10:22:01       41 阅读
  4. C++网络编程——实现一个简单的echo服务器

    2024-03-26 10:22:01       35 阅读
  5. 在Linux中用C语言实现Socket通信

    2024-03-26 10:22:01       48 阅读
  6. 广义表-C语言

    2024-03-26 10:22:01       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-26 10:22:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-26 10:22:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-26 10:22:01       82 阅读
  4. Python语言-面向对象

    2024-03-26 10:22:01       91 阅读

热门阅读

  1. Rust 实战练习 - 4. 网络 TCP/UDP/Channel

    2024-03-26 10:22:01       34 阅读
  2. 在Cmakelist指令中,aux_source_directory 和 set 的区别

    2024-03-26 10:22:01       35 阅读
  3. ARM day8

    2024-03-26 10:22:01       30 阅读
  4. Linux配置elasticsearch开机自启

    2024-03-26 10:22:01       37 阅读
  5. 「Linux系列」Shell 函数详解

    2024-03-26 10:22:01       45 阅读
  6. android卡顿流程分析总结

    2024-03-26 10:22:01       42 阅读
  7. gstreamer udp rtp发送本地视频文件

    2024-03-26 10:22:01       38 阅读
  8. 4A架构:企业数字化转型的核心引擎

    2024-03-26 10:22:01       39 阅读
  9. vue2项目关联el-table和el-pagination

    2024-03-26 10:22:01       44 阅读
  10. 服务器为互联网发送数据出现丢包情况

    2024-03-26 10:22:01       46 阅读