📌 相关专栏
-
【测试专栏】
📌 相关文章推荐
文章目录
- 一、套接字的种类
-
- [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. 流式套接字 (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




