手写Linux C UDP通信

复制代码
int main(int argc,char const *argv[])
{
    int socket_fd=socket(AF_INET,SOCK_DGRAM,0);
    if(-1==socket_fd){
        perror("socket error");
        return -1;
    }
    struct sockaddr_in dest_addr={0};
    int addr_len=sizeof(struct sockaddr_in);
    dest_addr.sin_family=AF_INET;
    dest_addr.sin_port=htons(65000);
    dest_addr.sin_addr.s_addr=inet_addr("192.168.10.100");


    char *msg=calloc(128,1);
    struct sockaddr_in from_addr;
    

    while(1){
        printf("请输入:\n");
      fgets(msg,128,stdin);
    int ret_val=sendto(socket_fd,msg,strlen(msg),0,
    (struct sockaddr *)&dest_addr,addr_len);
    if(-1==ret_val){
        perror("send to error");
        continue;
    }
    else{
        printf("send succeed, sent %d bytes\n", ret_val);
    }


    }
    return 0;
    
}

好,这段是UDP 客户端发送程序 ,我给你来一份老师上课那种逐行注释版,顺便把每一步"在干嘛 + 为啥要这么干"讲清楚。你照着看一遍,UDP 就基本通了 👍


复制代码
int main(int argc, char const *argv[])
{
  • 程序入口

  • argc / argv:命令行参数,这个程序里没用到


复制代码
    int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  • 创建一个 UDP socket

  • AF_INET:IPv4

  • SOCK_DGRAM:数据报 → UDP

  • 0:协议号,UDP 会自动匹配

📌 一句话:向操作系统申请一个"UDP 通信的文件描述符"


复制代码
    if (-1 == socket_fd) {
        perror("socket error");
        return -1;
    }
  • 判断 socket 是否创建成功

  • -1 说明失败

  • perror 会打印系统错误原因


复制代码
    struct sockaddr_in dest_addr = {0};
  • 定义 目标地址结构体

  • {0}:全部清零(好习惯,防止脏数据)


复制代码
    int addr_len = sizeof(struct sockaddr_in);
  • 地址结构体长度

  • sendto() 需要用到


复制代码
    dest_addr.sin_family = AF_INET;
  • 地址类型:IPv4

  • 必须和 socket(AF_INET, ...) 对应


复制代码
    dest_addr.sin_port = htons(65000);
  • 设置 目标端口号

  • htons:主机字节序 → 网络字节序

    (网络通信统一使用大端序

📌 如果你不 htons,对方收到的端口会是错的


复制代码
    dest_addr.sin_addr.s_addr = inet_addr("192.168.10.100");
  • 设置 目标 IP 地址

  • inet_addr:把字符串 IP 转成网络可用的 32 位整数

📌 这里就是:要把 UDP 数据发给谁


复制代码
    char *msg = calloc(128, 1);
  • 分配 128 字节的发送缓冲区

  • calloc

    • 分配内存

    • 自动清零

  • 用来存你输入的字符串


复制代码
    struct sockaddr_in from_addr;
  • 定义"对方地址"

  • ⚠️ 这里其实没用到

  • 一般用于 recvfrom() 接收数据时保存"谁发来的"


复制代码
    while (1) {
  • 死循环

  • 表示可以一直发送数据


复制代码
        printf("请输入:\n");
  • 提示用户输入

复制代码
        fgets(msg, 128, stdin);
  • 从标准输入读一行

  • 最多 127 个字符 + \0

  • 会把回车 \n 一起读进来

📌 比 scanf 安全,不容易溢出


复制代码
        int ret_val = sendto(
            socket_fd,
            msg,
            strlen(msg),
            0,
            (struct sockaddr *)&dest_addr,
            addr_len
        );

这是核心一句,拆开说:

参数 含义
socket_fd UDP socket
msg 要发送的数据
strlen(msg) 数据长度
0 flags,一般填 0
&dest_addr 目标 IP + 端口
addr_len 地址长度

📌 UDP 特点

  • 不用 connect

  • 每次 sendto 都要带目标地址


复制代码
        if (-1 == ret_val) {
            perror("send to error");
            continue;
        }
  • 发送失败

  • 打印错误

  • continue:跳过本轮,继续下一次发送


复制代码
        else {
            printf("send succeed, sent %d bytes\n", ret_val);
        }
  • 发送成功

  • ret_val实际发送的字节数


复制代码
    }
  • while(1) 结束(但实际上不会出来)

复制代码
    return 0;
}
  • 正常结束(理论上执行不到)

🔥 整体一句话总结

这是一个:

UDP 客户端程序

不断从键盘读字符串 → 通过 UDP 发给
192.168.10.100 : 65000


⚠️ 几个你迟早会问的问题(我先帮你答)

1️⃣ 为什么不用 bind()

  • 客户端一般不需要固定端口

  • 系统会自动分配一个临时端口


2️⃣ 对方怎么接收?

对方要:

复制代码
socket(AF_INET, SOCK_DGRAM, 0);
bind(65000);
recvfrom();

3️⃣ 为什么 UDP 不用 connect?

  • UDP 无连接

  • 每个包都是"独立快递"


4️⃣ from_addr 为什么没用?

  • 因为你只发不收

  • 如果加 recvfrom(),它就派上用场了


复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc,char const *argv[])
{
    int socket_fd=socket(AF_INET,SOCK_DGRAM,0);
    if(-1==socket_fd){
        perror("socket error");
        return -1;
    }
    struct sockaddr_in my_addr={0};
    int addr_len=sizeof(struct sockaddr_in);
    my_addr.sin_family=AF_INET;
    my_addr.sin_port=htons(65000);
    my_addr.sin_addr.s_addr=inet_addr("192.168.10.100");




   
    int ret_val=bind(socket_fd,(struct sockaddr*)&my_addr,
                    sizeof(my_addr));
    if(-1==ret_val){
        perror("bind error");
        return -1;

    }
    char *msg=calloc(128,1);
    struct sockaddr_in from_addr;
    

    while(1){
        ret_val=recvfrom(socket_fd,msg,128,0,(struct sockaddr *)&from_addr,&addr_len);
        if(ret_val==-1){
            printf("recv error");
            continue;
        }
        else{
            printf("recv succeed,msg:%s\n",msg);
        }
    }


    return 0;
}

好,这个就是UDP 接收端(服务器)了,而且你这个写法基本是对的 👍

我继续按你要的------逐行 + 顺带点坑位的"老师黑板版"来讲。


一、整体一句话先给你

这个程序做的事是:
绑定本机 192.168.10.100:65000,不断接收 UDP 数据并打印出来


二、逐行注释(重点解释"为什么")

复制代码
int main(int argc,char const *argv[])
{
  • 程序入口

  • argc / argv 依然没用到


复制代码
    int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  • 创建 UDP socket

  • IPv4 + UDP


复制代码
    if (-1 == socket_fd) {
        perror("socket error");
        return -1;
    }
  • 创建失败直接退出

复制代码
    struct sockaddr_in my_addr = {0};
  • 定义 本地地址结构体

  • {0}:清零,防止未初始化字段


复制代码
    int addr_len = sizeof(struct sockaddr_in);
  • 地址结构体长度

  • ⚠️ 后面 recvfrom() 里会被当成 "输入 + 输出参数"


复制代码
    my_addr.sin_family = AF_INET;
  • IPv4

复制代码
    my_addr.sin_port = htons(65000);
  • 绑定的本地端口

  • 必须 htons


复制代码
    my_addr.sin_addr.s_addr = inet_addr("192.168.10.100");
  • 绑定的 本机 IP

  • ⚠️ 这个 IP 必须是你这台机器真实拥有的

👉 如果写错:

  • bind error

  • 或者客户端发了你也收不到


复制代码
    int ret_val = bind(
        socket_fd,
        (struct sockaddr*)&my_addr,
        sizeof(my_addr)
    );
  • 把 socket 和本地 IP + 端口绑定

  • UDP 接收端 必须 bind

  • 不 bind,数据不知道往哪儿送


复制代码
    if (-1 == ret_val) {
        perror("bind error");
        return -1;
    }
  • 绑定失败(端口占用 / IP 不存在 / 权限问题)

复制代码
    char *msg = calloc(128, 1);
  • 接收缓冲区

  • 128 字节

  • 清零,方便直接当字符串打印


复制代码
    struct sockaddr_in from_addr;
  • 保存 发送方地址

  • recvfrom() 会把"谁发来的"填进这里


复制代码
    while (1) {
  • 死循环接收数据

复制代码
        ret_val = recvfrom(
            socket_fd,
            msg,
            128,
            0,
            (struct sockaddr *)&from_addr,
            &addr_len
        );

🔥 核心函数 recvfrom

参数 含义
socket_fd UDP socket
msg 接收缓冲区
128 最大接收字节数
0 flags
from_addr 对方 IP + 端口(输出)
&addr_len 地址结构体长度

📌 阻塞行为

  • 没数据 → 程序卡在这儿等

  • 一来数据 → 立刻返回


复制代码
        if (ret_val == -1) {
            printf("recv error");
            continue;
        }
  • 接收失败

  • 正常情况下很少失败


复制代码
        else {
            printf("recv succeed, msg:%s\n", msg);
        }
  • 接收成功

  • 直接按字符串打印

📌 ret_val收到的字节数


复制代码
    }
  • 无限接收

复制代码
    return 0;
}
相关推荐
小龙报6 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
小武编程6 小时前
基于JL700N可视化SDK的MAC地址应用
c语言·tws耳机·杰理jl700n
wdfk_prog6 小时前
[Linux]学习笔记系列 -- [drivers][tty]sysrq
linux·笔记·学习
c++逐梦人6 小时前
Linux基础IO
linux·操作系统·io
blueSatchel6 小时前
U-Boot载入到DDR过程的代码分析
linux·开发语言·u-boot
专注VB编程开发20年6 小时前
vb.net datatable新增数据时改用数组缓存
java·linux·windows
石去皿7 小时前
【嵌入式就业10】Linux内核深度解析:从启动流程到驱动框架的工业级实践
linux·运维·服务器
954L7 小时前
CentOs7执行yum update出现链接404问题
linux·centos·yum·vault
Trouvaille ~7 小时前
【Linux】应用层协议设计实战(二):Jsoncpp序列化与完整实现
linux·运维·服务器·网络·c++·json·应用层
EmbedLinX7 小时前
嵌入式之协议解析
linux·网络·c++·笔记·学习