【Linux】Socket编程UDP

📌 相关专栏


文章目录

  • 一、套接字的种类
    • [1. 流式套接字 (SOCK_STREAM)](#1. 流式套接字 (SOCK_STREAM))
    • [2. 数据报套接字 (SOCK_DGRAM)](#2. 数据报套接字 (SOCK_DGRAM))
    • [3. 原始套接字 (SOCK_RAW)](#3. 原始套接字 (SOCK_RAW))
    • [4. Unix域套接字 (Unix Domain Socket)](#4. Unix域套接字 (Unix Domain Socket))
  • 二、再来认识一下UDP
    • [1. 核心特性(对比 TCP )](#1. 核心特性(对比 TCP ))
  • 三、UDP编程
    • [1. 服务端](#1. 服务端)
    • [2. 客户端](#2. 客户端)
    • 实施步骤
      • 1.连接并确认环境
      • [2. 创建代码文件](#2. 创建代码文件)
      • [3. 写入代码(代码在上面)](#3. 写入代码(代码在上面))
      • [4. 编译](#4. 编译)
      • [5. 运行测试](#5. 运行测试)
      • [6. 运行结果](#6. 运行结果)
      • 7.可能遇到的问题
      • [7. 验证是否通过](#7. 验证是否通过)
      • [8. 测试脚本](#8. 测试脚本)

一、套接字的种类

1. 流式套接字 (SOCK_STREAM)

  • 协议:基于 TCP,提供面向连接、可靠的数据传输服务。
  • 特点:保证数据按顺序到达且无差错,类似打电话。适用于网页浏览、文件下载、邮件收发等对数据准确性要求高的场景。

2. 数据报套接字 (SOCK_DGRAM)

  • 协议:基于 UDP,提供无连接、不可靠的服务。
  • 特点:每个数据包独立发送,不保证顺序或可靠到达,但传输效率高。类似寄信。适用于实时性要求高的场景,如视频会议、在线游戏、DNS查询。

3. 原始套接字 (SOCK_RAW)

  • 协议:允许直接访问和操作底层协议(如IP、ICMP)。
  • 特点:可以构造自定义的数据包或读取网络上的原始数据包。主要用于网络诊断(如Ping命令)和网络安全工具开发(如Wireshark、Nmap)。

4. Unix域套接字 (Unix Domain Socket)

  • 协议:不基于TCP/UDP网络协议,专门用于同一台设备上不同进程间的通信(IPC)。
  • 特点:效率极高,比网络套接字更快。通常通过文件系统中的一个文件来表示(例如 /var/run/docker.sock)。常用于数据库(如MySQL)、Docker守护进程等高性能本地通信。

二、再来认识一下UDP

UDP(User Datagram Protocol,用户数据报协议)是 TCP 的"简单粗暴"版兄弟。用一句话概括:它是"只管发,不管到"的明信片服务。

1. 核心特性(对比 TCP )

特性 UDP TCP
连接状态 无连接(直接发) 面向连接(先握手)
可靠性 不可靠(发完就忘) 可靠(确认+重传)
顺序保证 不保证(可能乱序) 保证按序到达
数据边界 有边界(数据报) 无边界(字节流)
速度 快(无开销) 慢(握手、确认、拥塞控制)
头部大小 8 字节 20-60 字节
流量控制
拥塞控制
单次发送上限 约 64KB 无限制(流式)

三、UDP编程

1. 服务端

所需类型:

c 复制代码
int _sockfd;				//创建套接字对应的文件描述符
uint_16t _port;				//端口号
string _ip;					//服务端的IP地址		bind 0 表示绑定任意地址
bool _isrunning;			//判断服务端是否在进行

示例:最简单的UDP服务端(接收数据并回显
这里我用的是xshell

powershell 复制代码
// udp_server.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(8888), .sin_addr.s_addr = INADDR_ANY};
    bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));

    char buf[1024];
    struct sockaddr_in client_addr;
    socklen_t len = sizeof(client_addr);
    recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&client_addr, &len);
    printf("收到: %s\n", buf);
    sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&client_addr, len);
    close(sockfd);
    return 0;
}

2. 客户端

powershell 复制代码
// client.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in server_addr = {.sin_family = AF_INET, .sin_port = htons(8888)};
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

    char *msg = "Hello UDP";
    sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));

    char buf[1024];
    socklen_t len = sizeof(server_addr);
    recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&server_addr, &len);
    printf("收到回复: %s\n", buf);
    close(sockfd);
    return 0;
}

实施步骤

1.连接并确认环境

bash 复制代码
# 连上后确认 GCC 是否安装
gcc --version

# 如果没有,安装 GCC(Ubuntu/Debian 用 apt,CentOS 用 yum)
sudo apt update && sudo apt install gcc -y   # Ubuntu/Debian

# sudo yum install gcc -y                    # CentOS/RedHat

这里不懂的可以看前面的博客文章:https://blog.csdn.net/2502_91546643/article/details/160417745?spm=1011.2415.3001.10575&sharefrom=mp_manage_link

2. 创建代码文件

  • touch:先创建一个空白文件
  • vim 文件名:
    • 如果文件不存在,就自动帮你新建一个空文件,并直接进入编辑;
    • 如果文件已存在,就直接进入编辑
bash 复制代码
# 创建两个文件		//这里用touch
touch udp_server.c udp_client.c

3. 写入代码(代码在上面)

bash 复制代码
#因为上面已经创建了这两个文件,所以是直接进入编辑
vim udp_server.c
vim udp_client.c

i进入编辑模式,按ESC退回命令模式,在输入:wq保存退出

4. 编译

bash 复制代码
# 生成服务端和客户端程序
gcc udp_server.c -o server
gcc udp_client.c -o client

5. 运行测试

bash 复制代码
./udp_server & ./udp_client		//这是只有一个Xhsell窗口的情况下

6. 运行结果

7.可能遇到的问题

问题1:端口被占用

bash 复制代码
# 换个端口,修改代码里的 8888 为其他数字(如 9999)
# 改完重新编译

问题2:收不到数据

bash 复制代码
# 检查防火墙(云服务器安全组要放行 UDP 端口)
sudo ufw status          # 查看防火墙状态
sudo ufw allow 8888/udp  # 开放 UDP 8888 端口

# 如果是云服务器(阿里云/腾讯云等),还需要在控制台安全组规则中放行 UDP 8888

问题3:想停掉后台服务端

bash 复制代码
# 查找进程并杀掉
ps aux | grep server
kill <进程ID>

7. 验证是否通过

即上面的运行结果:

8. 测试脚本

(1)创建一个 test.sh 文件

bash 复制代码
touch test.sh

(2)对test.sh文件进行编辑:

bash 复制代码
vim test.sh

输入以下内容:

bash 复制代码
gcc udp_server.c -o server && gcc udp_client.c -o client
echo "编译成功,请运行 ./server 和 ./client"

(3)赋予执行权限(普通用户没有该执行权限)

赋予权限前:

赋予权限后:输入chmod +x test.sh

相关推荐
枕星而眠2 小时前
C++ String类精讲:从基础用法到进阶底层原理
开发语言·c++·后端·学习方法
江屿风2 小时前
【C++笔记】模板初阶流食般投喂
开发语言·c++·笔记
Shadow(⊙o⊙)2 小时前
qt信号和槽链接的接入与断开
开发语言·前端·c++·qt·学习
想你依然心痛2 小时前
HarmonyOS 6 悬浮导航 + 沉浸光感:打造鸿蒙智能体驱动的沉浸式编程学习伴侣
学习·华为·ar·harmonyos·智能体
AI玫瑰助手2 小时前
Python运算符:逻辑运算符(and/or/not)的短路特性
开发语言·python·信息可视化
m0_474606782 小时前
JAVA - 使用Apache POI 自定义报表字段手写导出(支持-合并单元格)
java·开发语言·apache
肩上风骋2 小时前
C++基本知识点积累之d指针,invokemethod函数(一)
开发语言·c++·d指针·invokemethod()
明志数科2 小时前
具身智能数据标注工具对比评测:6大平台横向测评
开发语言·python
念何架构之路2 小时前
Go pprof性能剖析
开发语言·后端·golang