欢迎光临
我们一直在努力

关于UDP客户端给服务器发消息,服务器端显示收到消息的代码详细注释(linux)

一、服务器端代码

/* UDP 服务器实现 */
#include <stdio.h> // 标准输入输出(如printf)
#include <stdlib.h> // 标准库函数(如exit)
#include <string.h> // 字符串操作(如memset)
#include <unistd.h> // POSIX系统调用(如close)
#include <sys/socket.h> // 套接字相关函数(如socket, bind)
#include <sys/types.h> // 系统数据类型(如socklen_t)
#include <fcntl.h> // 文件控制(如open,但本代码未使用)
#include <sys/stat.h> // 文件状态(未实际使用)
#include <netinet/in.h> // 网络地址结构(如sockaddr_in)
#include <arpa/inet.h> // IP地址转换(如inet_addr)

#define IP "192.168.53.128" // 服务器监听的IP地址
#define PORT 5555 // 服务器监听的端口号

int main(int argc,char *argv[]) {
// (已注释掉)原命令行参数检查,现使用宏定义IP/PORT
// if(argc!=3){
// printf("Usage:%s ip port\\n",argv[0]);
// exit(0);
// }

// 1. 创建UDP套接字
// AF_INET: IPv4协议族
// SOCK_DGRAM: UDP协议
// 0: 自动选择协议(UDP固定为0)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1){ // 创建失败处理
perror("socket"); // 打印错误信息(如权限不足)
exit(-1); // 异常退出
}

// 2. 绑定IP和端口号
struct sockaddr_in addr; // IPv4地址结构体
addr.sin_family = AF_INET; // 协议族:IPv4
addr.sin_port = htons(PORT); // 端口号转网络字节序
addr.sin_addr.s_addr = inet_addr(IP); // IP地址转网络格式

// 绑定套接字到指定IP和端口
int res = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
if(res == -1){ // 绑定失败处理
perror("bind"); // 打印错误(如端口被占用)
exit(-1);
}

// 3. 通信循环
char buf[128] = {}; // 接收缓冲区(初始化为0)
struct sockaddr_in send_addr; // 存储客户端地址信息
socklen_t len = sizeof(send_addr); // 地址结构体长度

while(1){ // 无限循环处理客户端消息
// 接收数据:
// sockfd: 套接字描述符
// buf: 接收缓冲区
// sizeof(buf): 缓冲区大小
// 0: 默认标志位
// send_addr: 发送方地址(输出参数)
// len: 地址结构体长度(输入输出参数)
res = recvfrom(sockfd, buf, sizeof(buf), 0,
(struct sockaddr *)&send_addr, &len);
if(res == -1){ // 接收失败处理
perror("recvfrom");
exit(-1);
}

// 打印客户端信息:
// inet_ntoa: 将IP转为点分十进制字符串
// ntohs: 端口号转主机字节序
printf("%s %hu说:%s\\n",
inet_ntoa(send_addr.sin_addr), // 客户端IP
ntohs(send_addr.sin_port), // 客户端端口
buf); // 接收的消息

memset(buf, 0, sizeof(buf)); // 清空缓冲区
}

close(sockfd); // 关闭套接字(实际不会执行到此处)
return 0; // 程序结束
}

这段代码实现了一个 UDP 服务器 的基本功能,主要作用是接收客户端发送的消息并显示消息来源信息。以下是它的核心功能分解:


1. 核心功能

功能说明
创建 UDP 套接字 使用 socket(AF_INET, SOCK_DGRAM, 0) 创建一个 UDP 协议的通信端点。
绑定 IP 和端口 将套接字绑定到固定 IP (192.168.53.128) 和端口 (5555),等待客户端连接。
接收客户端消息 通过 recvfrom() 持续接收客户端发送的数据,并打印客户端 IP、端口和消息内容。
实时显示消息 每收到一条消息,立即在终端打印格式化的信息(如 192.168.1.100 12345说: Hello)。

2. 技术细节

  • 协议类型:UDP(无连接、不可靠但高效,适合局域网通信)。

  • 硬编码配置:IP 和端口通过宏定义(#define)固定,需手动修改代码调整。

  • 数据接收:

    • 使用 recvfrom() 获取数据 及客户端地址(无需提前建立连接)。

    • 缓冲区大小固定为 128 字节,超出部分会被截断。

  • 错误处理:对关键操作(如 socket、bind、recvfrom)进行错误检查,失败时打印错误信息并退出。


3. 典型使用场景

  • 局域网聊天室

    • 多个客户端向该服务器发送消息,服务器集中显示所有消息来源和内容。

  • 传感器数据收集

    • IoT 设备(如温度传感器)通过 UDP 上报数据,服务器记录并显示。

  • 简单网络调试

    • 测试网络连通性或端口是否开放。


  • 4. 代码局限性

    问题可能的影响改进建议
    硬编码 IP/端口 每次修改需重新编译代码 改用命令行参数传递(如 ./server IP PORT)
    无数据回显功能 服务器不能回复客户端 添加 sendto() 向客户端发送响应
    单线程阻塞接收 无法同时处理多个客户端的高并发请求 使用多线程或 select() 模型
    缓冲区固定大小 长消息会被截断 动态分配缓冲区或循环接收

    5. 扩展功能建议

    • 日志记录:将收到的消息写入文件(如 syslog)。

    • 消息广播:将某个客户端的消息转发给其他所有客户端。

    • 简单协议:定义消息格式(如 JSON),便于解析结构化数据。


    总结

    这段代码是一个 基础的 UDP 服务器框架,适合学习网络编程或快速搭建简单的本地网络服务。如需实际应用,需根据需求扩展错误处理、并发支持和协议设计。


    二、客户端代码

    /* UDP 客户端实现 */
    #include <stdio.h> // 标准输入输出(如printf、fgets)
    #include <stdlib.h> // 标准库函数(如exit)
    #include <string.h> // 字符串操作(如strlen、strtok)
    #include <unistd.h> // POSIX系统调用(如close)
    #include <sys/socket.h> // 套接字相关函数(如socket、sendto)
    #include <sys/types.h> // 系统数据类型(如socklen_t)
    #include <fcntl.h> // 文件控制(本代码未使用)
    #include <sys/stat.h> // 文件状态(本代码未使用)
    #include <netinet/in.h> // 网络地址结构(如sockaddr_in)
    #include <arpa/inet.h> // IP地址转换(如inet_addr)

    #define IP "192.168.53.128" // 目标服务器的IP地址(需修改为实际地址)
    #define PORT 5555 // 目标服务器的端口号(需修改为实际端口)

    int main(int argc, char *argv[]) {
    // (已注释掉)原命令行参数检查,现使用宏定义IP/PORT
    // if(argc!=3){
    // printf("Usage:%s ip port\\n",argv[0]);
    // exit(0);
    // }

    // 1. 创建UDP套接字
    // AF_INET: IPv4协议
    // SOCK_DGRAM: UDP协议
    // 0: 自动选择协议(UDP固定为0)
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) { // 创建失败处理
    perror("socket"); // 打印错误(如权限不足)
    exit(-1);
    }

    // 2. 配置目标服务器地址
    struct sockaddr_in addr; // IPv4地址结构体
    addr.sin_family = AF_INET; // 协议族:IPv4
    addr.sin_port = htons(PORT); // 端口号转网络字节序
    addr.sin_addr.s_addr = inet_addr(IP); // IP地址转网络格式

    // 3. 通信循环
    char buf[128] = {}; // 发送缓冲区(初始化为0)
    while (1) {
    printf("请输入:"); // 提示用户输入
    fgets(buf, sizeof(buf), stdin); // 从标准输入读取一行(含换行符)

    // 移除输入末尾的换行符(\\n)
    strtok(buf, "\\n");

    // 发送数据到服务器:
    // sockfd: 套接字描述符
    // buf: 发送的数据
    // strlen(buf)+1: 数据长度(包含字符串结束符\\0)
    // 0: 默认标志位
    // (struct sockaddr*)&addr: 目标服务器地址
    // sizeof(addr): 地址结构体长度
    sendto(sockfd, buf, strlen(buf) + 1, 0,
    (struct sockaddr *)&addr, sizeof(addr));
    }

    close(sockfd); // 关闭套接字(实际不会执行到此处)
    return 0; // 程序结束
    }

    UDP 客户端功能概述

  • 核心功能:向指定的 UDP 服务器 (IP:PORT) 发送用户输入的消息。

  • 通信方式:无连接(UDP),直接通过 sendto() 发送数据。

  • 特点:

    • 持续等待用户输入(while(1) 循环)。

    • 硬编码服务器地址(需提前修改代码中的 IP 和 PORT)。

  • 关键功能说明

    代码部分功能说明
    socket(AF_INET, SOCK_DGRAM, 0) 创建 UDP 套接字(无连接,不可靠但高效)。
    addr.sin_port = htons(PORT) 将端口号转换为 网络字节序(大端模式),确保跨平台兼容性。
    inet_addr(IP) 将点分十进制IP(如 "192.168.1.100")转换为32位网络字节序整数。
    fgets(buf, sizeof(buf), stdin) 从用户输入读取一行文本(包含换行符 \\n),存入缓冲区 buf。
    strtok(buf, "\\n") 移除缓冲区末尾的换行符(避免发送多余字符)。
    sendto(…) 向目标服务器发送数据,无需提前建立连接(UDP特性)。

    使用示例

  • 运行客户端:

    bash

    ./udp_client

  • 输入消息:

    bash

    请输入: Hello Server!

  • 服务器端:会显示接收到的消息和客户端地址。


  • 注意事项

  • 硬编码问题:

    • 需手动修改代码中的 IP 和 PORT 以匹配服务器地址。

    • 改进建议:改用命令行参数(如 ./client <IP> <PORT>)。

  • 数据完整性:

    • UDP 不保证消息到达顺序或是否丢失,适合对可靠性要求不高的场景。

  • 缓冲区限制:

    • 输入超过 128 字节会被截断,需动态扩展缓冲区或循环发送。

  • 无错误处理:

    • sendto() 的返回值未检查,实际应用中需处理网络错误(如目标不可达)。

  • 扩展建议

    • 添加回复功能:在 sendto 后调用 recvfrom 接收服务器响应。

    • 多线程输入:分离用户输入和网络接收逻辑,避免阻塞。

    • 协议设计:定义消息头(如长度、类型)以支持复杂数据交换。


    三、终端效果:

    赞(0)
    未经允许不得转载:171主机测评 » 关于UDP客户端给服务器发消息,服务器端显示收到消息的代码详细注释(linux)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址