Socket编程UDP

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于

文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地

址呢?

  • 网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址.

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下

库函数做网络字节序和主机字节序的转换。

htons/htonl/ntohl/ntohs

c 复制代码
#include<arpa/inet.h>
unit32_t htonl(unit32_t hostlong);
  • 参数:hostlong:主机字节序的32位无符号整数
  • 返回值:网络字节序的32位整数
c 复制代码
#include<arpa/inet.h>
unit16_t htons(unit16_t hostlong);
  • 参数:hostshort:主机字节序的16位无符号整数
  • 返回值:网络字节序的16位整数
c 复制代码
#include<arpa/inet.h>
uint16_t ntohs(uint16_t netshort);
  • 参数: netshort: 网络字节序的16位整数
  • 返回值:网络字节序的16位整数
c 复制代码
#include<arpa/inet.h>
uint32_t ntohl(uint32_t netlong);
  • 参数:netlong: 传入网络字节序的32位整数
  • 返回值:网络字节序的16位整数

函数 功能 含义 适用场景
htons 主机序 → 网络序,16 位 host to network short 端口号 (uint16_t)
htonl 主机序 → 网络序,32 位 host to network long IPv4 整型地址 (uint32_t)
ntohs 网络序 → 主机序,16 位 network to host short 从 sockaddr 取出端口解析
ntohl 网络序 → 主机序,32 位 network to host long 从 sockaddr 取出 ip 整型解析

记忆规则

  1. h 开头:h(ost) → n(etwork) 主机转网络,用于填sockaddr结构体,准备发包
  2. n 开头:n(etwork) → h(ost) 网络转主机,用于从sockaddr取出数据,程序内打印/计算
  3. s = short 16位 → 端口
  4. l = long 32位 → IPv4地址

使用示例

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

int main() {
    // 端口号转换(16位)
    uint16_t host_port = 8080;
    uint16_t net_port = htons(host_port);
    printf("Host port: %u -> Network port: %u\n", host_port, net_port);
    
    // IP地址转换(32位)
    uint32_t host_ip = 0xC0A80101;  // 192.168.1.1
    uint32_t net_ip = htonl(host_ip);
    printf("Host IP: 0x%08X -> Network IP: 0x%08X\n", host_ip, net_ip);
    
    // 从网络序转回主机序
    uint16_t back_port = ntohs(net_port);
    uint32_t back_ip = ntohl(net_ip);
    
    return 0;
}

socket

c 复制代码
#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(本地)
type 套接字类型 SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、SOCK_RAW(原始)
protocol 协议(通常为 0) 0(自动选择)、IPPROTO_TCP、IPPROTO_UDP
  • domain:和一个结构体有关------struct sockaddr,本地选择AF_UNIX网络通信选AF_INET

sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX

Domain Socket. 然而, 各种网络协议的地址格式并不相同.

  • IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的
    首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的
    内容.
  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样
    的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构
    体指针做为参数;

sockaddr结构

sockaddr_in结构

虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in;

这个结构里主要有三部分信息: 地址类型, 端口号, IP地址.

in_addr结构

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数;

bind

bind() 的作用是 给套接字绑定一个本地地址(IP + 端口),即告诉操作系统这个套接字在哪个地址上监听或发送数据

c 复制代码
#include <sys/socket.h>

int bind(int socket, const struct sockaddr *address, socklen_t address_len);
参数 类型 说明
socket int 由 socket() 函数返回的文件描述符
address const struct sockaddr * 指向套接字地址结构的指针(需强制转换)
address_len socklen_t address 所指结构的大小(字节数)

bzero() 函数详解

bzero() 将内存区域 s 的前 n 个字节全部设置为零(\0)。

c 复制代码
#include <strings.h>

void bzero(void *s, size_t n);
参数 类型 说明
s void * 指向要清零的内存区域的指针
n size_t 要清零的字节数

recvfrom

recvfrom() 的主要作用是 从无连接套接字接收数据,并获取发送方的地址。

c 复制代码
#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 int 套接字文件描述符
buf void * 接收数据的缓冲区指针
len size_t 缓冲区大小(字节数)
flags int 接收标志(通常设为 0)
src_addr struct sockaddr * 输出参数:存储发送方地址信息,可为 NULL
addrlen socklen_t * 输入输出参数:传入地址结构大小,返回实际地址长度
  • sockfd:是socket接口的返回值。

sendto

sendto() 的主要作用是 通过套接字向指定目标地址发送数据 ,特别适用于 无连接的通信协议(如 UDP)。

c 复制代码
#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 int 套接字文件描述符
buf const void * 指向要发送数据的缓冲区
len size_t 要发送的字节数
flags int 发送选项标志(通常为 0)
dest_addr const struct sockaddr * 目标地址结构指针
addrlen socklen_t dest_addr 结构的大小
相关推荐
Zenova EdgeOS10 小时前
C++ 工业边缘 libcurl HTTP 客户端实战
开发语言·c++·网络协议·边缘计算
后台模板学习10 小时前
2026最新面试真题:到达用英语怎么说背后的逻辑与源码剖析
面试·职场和发展·php
时空节拍AI数字人10 小时前
AI 数字人为什么需要“3D”?2D 不够用吗
人工智能·网络协议·tcp/ip·3d·信息可视化
小白羊丨11 小时前
HTTP/2 如何缓解 HTTP/1.1 阻塞;长连接对 Nginx 有什么影响?
网络协议·nginx·http
少陽君12 小时前
Python 并发编程:IO 等待用线程/asyncio,CPU 计算才用进程
数据库·python·php
盛世宏博智慧档案14 小时前
高速 ETC 门架外场机房温湿度远程监测解决方案
服务器·数据库·php·高度·高速·温湿度
我的小卷呀15 小时前
Linux ip 命令底层逻辑与实战指南
linux·运维·c语言·网络协议·tcp/ip·网络安全
祁白_15 小时前
防御引擎绕过方法
笔记·web安全·php·防御引擎
Soonyang Zhang16 小时前
使用wintun构建tcp中转服务
网络·网络协议·tcp/ip
evans在进步17 小时前
IP 网络基础详解:路由、ICMP、NAT、子网与 VLAN
网络·tcp/ip·php