当前位置: 首页 > news >正文

网络:2.Socket编程UDP

Socket编程UDP

一.接口补充

1. socket(系统调用)

作用:创建一个套接字的一端

函数原型

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • 参数
    • domain(协议族/地址族)
      • AF_INET : IPv4(常用)
      • AF_INET6: IPv6
      • AF_UNIX : 本地进程间通信(Unix 域)
    • type(套接字类型)
      • SOCK_DGRAM : 数据报(UDP)
      • SOCK_STREAM : 字节流(TCP)
    • protocol(协议编号)
      • 0就行,让系统按domain+type自动选择合适的协议.
  • 返回值
    • 成功:返回一个套接字的文件描述符
    • 失败:返回-1,并设置 errno

2. bind(系统调用)

作用:将创建好的套接字与本地的 IP 地址和端口号绑定在一起。(告诉操作系统:我这个 socket 要监听哪个本地地址和端口。)

函数原型

#include <sys/types.h>
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数

    • sockfd:套接字的文件描述符;

    • addr(地址信息结构体):

      • 用于指定要绑定的本地 IP 和端口号。

      • 对 IPv4 通常是 struct sockaddr_in 类型(需强转为 struct sockaddr*)。

      • 关键字段:

        struct sockaddr_in {sa_family_t    sin_family;   // 地址族,网络通信选AF_INET/AF_INET6,进程通信选AF_UNIXin_port_t      sin_port;     // 端口号(网络字节序)struct in_addr sin_addr;     // IP地址(网络字节序)
        };
        

        struct sockaddr_in需要的头文件:
        #include <sys/socket.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>

    • addrlen:地址结构体的大小:sizeof(struct sockaddr_in)

  • 返回值

    • 成功: 0
    • 失败: -1,并设置 errno

3. bzero(库函数)

作用: 将指定内存区域的前 n 个字节全部清零(置为 0); 常用于初始化结构体、数组或缓冲区。

函数原型

#include <strings.h>void bzero(void *s, size_t n);
  • 参数
    • s:要清零的内存起始地址(void 类型);*
    • n:要清零的字节数.

4. inet_addr(库函数)

作用: 将一个点分十进制的 IPv4 地址字符串(如 “192.168.1.1”)转换为网络字节序的32 位整数(in_addr_t(uint32_t)类型)。 常用于为 sockaddr_in.sin_addr.s_addr 赋值。

函数原型

#include <arpa/inet.h>in_addr_t inet_addr(const char *cp);
  • 参数

    • cp
      • C 风格字符串形式的 IPv4 地址,例如 "127.0.0.1""192.168.10.5";
      • 要求是 点分十进制格式(四个 0–255 的数字,用点分隔).
  • 返回值

    • 成功: 返回对应的 网络字节序 IP 地址(in_addr_t 类型,实质为 uint32_t);
    • 失败: 返回常量 INADDR_NONE(即 0xFFFFFFFF).

5. inet_ntoa(库函数)

作用: 将一个网络字节序的 IPv4 地址(struct in_addr 类型)转换为“点分十进制字符串。

函数原型

#include <arpa/inet.h>char *inet_ntoa(struct in_addr in);
  • 参数:in

    • struct in_addr 类型,表示一个 IPv4 地址
    • 通常从 sockaddr_in.sin_addr 成员获得;
  • 返回值

    • 成功: 返回一个 指向静态字符串 的指针,内容为点分十进制形式的 IPv4 地址;

    • 失败: 无特别错误返回,但注意:

      该字符串存放在静态内存区中,每次调用 inet_ntoa() 都会覆盖上一次的结果,非线程安全。


6. inet_pton(库函数)

作用:将“点分十进制”或“冒号分隔”的IP地址字符串(IPv4/IPv6)转换为网络字节序的二进制格式,是inet_addr()的现代、安全版本。

函数原型

#include <arpa/inet.h>int inet_pton(int af, const char *src, void *dst);
  • 参数
    • af(地址族):指定地址类型
      • AF_INET
      • AF_INET6
    • src(源字符串):C 字符串形式的 IP 地址;
    • dst(目标内存地址):转换后的结果将存放到此结构体地址中;
      • IPv4:&sockaddr_in.sin_addr
      • IPv6:&sockaddr_in6.sin6_addr
  • 返回值
    • 成功: 1;
    • **失败: **
      • IP地址非法:0
      • 出错:-1, 并设置 errno

7. inet_ntop(库函数)

作用:将一个网络字节序的二进制 IP 地址(IPv4 或 IPv6)转换为字符串形式(点分/冒号分隔)。是inet_ntoa()的可重入(线程安全)版本。

函数原型

#include <arpa/inet.h>const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
  • 参数
    • af(地址族):指定地址类型
      • AF_INET
      • AF_INET6
    • src(源地址):指向存放网络字节序IP地址的内存(结构体);
      • IPv4:&sockaddr_in.sin_addr
      • IPv6:&sockaddr_in6.sin6_addr
    • dst(目标缓冲区):用于保存转换后的字符串;
      • 一般定义为 char buf[INET_ADDRSTRLEN](IPv4)或 char buf[INET6_ADDRSTRLEN](IPv6)。
    • size(缓冲区大小)
  • 返回值

    • 成功: 返回指向 dst 的指针(即转换后的字符串);

    • **失败:errno置为EAFNOSUPPORT 或 ENOSPC) **


8. recvfrom(系统调用)

作用: 从一个 UDP 套接字中接收数据,同时获取发送方(客户端)的地址信息。(常用于 UDP 服务器端接收消息)

函数原型

#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  • 参数
    • sockfd:套接字文件描述符;
    • buf:用来接收数据的缓冲区首地址;
    • len缓冲区的大小(单位:字节);
    • flags:一般填 0 (阻塞IO,如果对方不发数据,该函数(进程)就会一直阻塞,等同与scanf; MSG_DONTWAIT 表示非阻塞接收);
    • src_addr:
      • 一个 struct sockaddr_in 类型的指针,用于存储发送方的地址信息(IP + 端口);
      • 如果不关心发送方,可以填 NULL;
    • addrlen:
      • 指向一个socklen_t类型的变量,socklen_t实际上是一个整数类型(可跨平台);
      • addrlen既是输入参数, 又是输出参数: 初始时应设置为 sizeof(struct sockaddr_in); 函数返回时,会被填入实际的地址长度.
  • 返回值
    • 成功: 返回接收到的字节数(ssize_t是有符号整数long int);
    • 失败: 返回 -1,并设置 errno.

9. sendto(系统调用)

作用: 向指定的目标地址发送一块数据(UDP 无连接发送)。(常用于 UDP 客户端发送,或服务器向收到的源地址回发数据)

函数原型

#include <sys/types.h>
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  • 参数
    • sockfd:套接字文件描述符;
    • buf:待发送数据的起始地址;
    • len:待发送数据的字节数;
    • flags:发送标志(一般填 0 阻塞发送; 常见可选:MSG_DONTWAIT 非阻塞发送,MSG_NOSIGNAL 发送失败不触发 SIGPIPE 等);
    • dest_addr:目标地址结构体指针
      • 服务器回包可直接用 recvfrom 得到的 src_addr 作为 dest_addr
    • addrlen:地址结构体(dest_addr)大小
  • 返回值
    • 成功: 返回实际发送的字节数;
    • 失败: 返回 -1,并设置 errno.

二.命令补充

1. netstat(系统命令)

作用: 显示网络连接、路由表、接口状态、端口监听情况等网络统计信息。

命令格式

netstat [选项]
  • 常用选项组合

    • -a:显示所有连接和监听端口(all)
    • -l:仅显示处于监听(listening)状态的端口
    • -n:以数字形式显示 IP 地址和端口号(不解析主机名)
    • -u:仅显示 UDP 协议连接
    • -t:仅显示 TCP 协议连接
    • -p:显示对应的进程号与程序名(需要 root 权限)
  • 常见用法举例

    netstat -anup
    

    作用:

    显示系统中所有 UDP 套接字(包括监听与已连接的),并显示使用这些端口的程序信息。

  • 输出示例

    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    udp        0      0 0.0.0.0:8080           0.0.0.0:*                           2314/udpserver
    udp        0      0 127.0.0.1:53           0.0.0.0:*                           924/dnsmasq
    udp6       0      0 :::68                  :::*                                652/systemd-network
    
  • 字段说明

    字段含义
    Proto协议类型(TCP/UDP)
    Recv-Q接收队列中尚未被应用读取的字节数
    Send-Q发送队列中尚未发送的字节数
    Local Address本地 IP + 端口号 (0.0.0.0 表示监听所有网卡)
    Foreign Address远端 IP + 端口号(UDP 无连接时显示为 *)
    State套接字状态(UDP 无状态,通常为空)
    PID/Program name占用该端口的进程号及程序名
  • 常用变体

    命令作用
    netstat -anup查看所有 UDP 端口与进程信息
    netstat -antp查看所有 TCP 连接与进程信息

三.知识补充

1. 客户端bind问题

  1. 问题:client要不要bind?需要bind.

    client要不要显式的bind?不要!首次发送消息,OS会自动给client进行bind,OS知道IP,端口号采用随机端口号的方式

  2. 为什么?一个端口号,只能被一个进程bind,为了避免client端口冲突

    client端的端口号是几,不重要,只要是唯一的就行!

2.本地环回

本地环回:127.0.0.1, 要求客户端和服务端必须在一台服务器上, 表明我们是本地通信, 客户端发送的数据不会被推送到网络,而是在OS内部转一圈直接交给对应的服务器端。经常用来进行网络代码的测试

3. 三个现象

(1).bind公网iP – 不能

公网IP其实没有配置到你的IP上。公网IP无法被直接bind!

(2).bind 127.0.0.1||内网IP – ok
(3).server bind内网IP,但是用127.0.0.1访问—访问不 (反过来也不行)

如果我们显式的进行地址bind,client未来访问的时候,就必须使用server端bind的地址信息!

  • 如何跨网络访问?

    server,不建议手动bind特定的

    struct sockaddr_in local;
    local.sin_addr.s_addr = INADDR_ANY; //任意IP地址bind/* Address to accept any incoming messages.  */
    //#define	INADDR_ANY		((in_addr_t) 0x00000000)
    

    这样的好处是: 只要发给这台机器bind指定的端口号的报文都可以接受。

http://www.dtcms.com/a/494840.html

相关文章:

  • Linux服务器编程实践45-UDP数据读写:recvfrom与sendto函数的使用实例
  • 基于SpringBoot+Vue的数码交流管理系统(AI问答、协同过滤算法、websocket实时聊天、Echarts图形化分析)
  • 设计模式篇之 状态模式 State
  • linux系统编程(十)RK3568 socket之 UDP的实现
  • MySQL事务隔离
  • 甜点的网站建设规划书长春市城乡建设局网站
  • C++ 多线程实战 11|如何系统性避免死锁
  • WAPR断网攻击天阶大法根基法之wifi爆破
  • 集群冗余:高可用的核心设计
  • Vue 3 完全指南:响应式原理、组合式 API 与实战优化
  • Netscape 浏览器
  • 笔记:TFT_eSPI不支持ESP32C6;ESP8266运行LVGL注意事项
  • 会网站开发没学历seo网络营销
  • 简述深度学习中的四种数据并行方法(DP,DDP,TP,PP)
  • YOLO-World 全面解析:实时开放词汇目标检测的新范式(附实践指南)
  • 西瓜网络深圳网站建设 东莞网站建设电商型网站
  • AI+大数据时代:时序数据库的生态重构与价值跃迁——从技术整合到行业落地
  • 设计素材网站图案免费建设银行社保卡网站在哪
  • 预告!星火社吕诚将推 “星星之火” 线上课堂,哲思 + 投资赋能公益新生态
  • 孟德尔随机化 哪个计算最消耗时间 在肠道菌群、代谢物和疾病三类数据中,**肠道菌群数据的处理通常最消耗时间**
  • 【Redis学习】持久化机制(RDB/AOF)
  • 栈式自编码器(Stacked Auto-Encoder)
  • 像wordpress一样的网站建设银行网站转账必须u盾吗
  • 让低端机也能飞:Canvas/WebGL/Viz 分层、降级渲染与数据抽样策略
  • 【grafana查询超时问题】
  • 广播系统配线-批量测量快速计算
  • 电商网站商品页的优化目标是什么?第一推是谁做的网站
  • 从零开始的C++学习生活 9:stack_queue的入门使用和模板进阶
  • docker 运行容器限制内存、限制磁盘 IO
  • Compose Multiplatform+Kotlin Multiplatfrom 第七弹跨平台 AI开源