socket与udp
网络编程-socket&UDP网络程序
01. 基础知识
1.1 IP地址
IP地址
互联网协议地址,用于标识网络中的设备。通俗来说,IP地址
就像你家的门牌号,它能让网络中的数据准确找到要去的设备。比如,当你在手机上访问一个网站时,你的手机会有一个 IP地址
,网站服务器也有一个IP地址
,数据就是通过这两个地址在设备之间传递的。
1.1.1 IPv4
- 32位地址(4字节),点分十进制表示(192.168.1.1)
- 地址分类:A类(1-126)、B类(128-191)、C类(192-223)
1.1.2 IPv6
- 128位地址,冒号分隔十六进制表示,用来解决
IPv4
地址枯竭问题
1.2 端口号
端口号是由16位无符号整数(0-65535),用来标识主机上的特定服务。同一主机上的不同服务通过端口号区分
- 分类:
- 0-1023:知名端口(
HTTP:80
,HTTPS:443
,SSH:22
,...
) - 1024-49151:注册端口(
MySQL:3306
,…) - 49152-65535:动态/私有端口(客户端临时使用)
- 0-1023:知名端口(
1.3 端口号与进程PID
端口号用于标识进程,进程PID
也是用于标识进程,为什么在网络中,不直接使用进程PID
呢?
- 进程号(PID):由系统动态分配,不同主机上大概率不同,难以基于此实现跨主机通信。
- 端口号:网络协议的一部分,是主机通过网卡通信的必经软通道,有固定约定(如80、23、443),基于固定值建立通信更直接可靠。
- Windows开发约定:避免使用1024以前的端口,建议使用1024-65535区间的端口号。
- 并不是所有的进程都需要进行网络通信,如果端口号、,无疑会影响网络管理的效率
PID
都使用同一个解决方案,会影响网络管理效率。
1.4 传输层协议
- TCP:
- 面向连接、可靠传输,字节流
- 三次握手建立连接,四次挥手断开连接
- 流量控制、拥塞控制
- 适用场景:文件传输、网页浏览、邮件
- TCP 流程:
socket()
→bind()
→listen()
→accept()
(服务器);socket()
→connect()
(客户端);之后用send()
/recv()
通信。
- UDP:
- 无连接、不可靠传输,数据报
- 低延迟、无拥塞控制
- 适用场景:视频流、DNS查询、游戏实时数据
- UDP 流程:
socket()
→bind()
(可选);用sendto()
/recvfrom()
直接通信。
1.5 网络字节序
由于不同CPU架构使用不同字节序(大端/小端)。所以TCP/IP
协议规定网络中传输的数据,统一采用大端存储方案,也就是网络字节序,现在大端/小端称为主机字节序。
1.5.1 字节序转换函数
#include <arpa/inet.h>// 16位转换
uint16_t htons(uint16_t hostshort); //short常用于端口号 主机->网络
uint16_t ntohs(uint16_t netshort); //long常用于 IP 地址 网络->主机// 32位转换
uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);
1.5.2 IP地址转换函数
// 将点分十进制 IPv4 字符串转为网络字节序整数。
in_addr_t inet_addr(const char *cp);
int inet_pton(int af, const char *src, void *dst);// 将网络字节序 IPv4 整数转为点分十进制字符串(线程不安全)。
char *inet_ntoa(struct in_addr in);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
02. socket 套接字
socket 套接字提供了下面这一批常用接口,用于实现网络通信。
2.1 socket 常见API
2.1.1 socket()
创建一个socket
描述符,用于后续网络操作。
int socket(int domain, int type, int protocol);
- 参数:
domain
:协议族,AF_INET
(IPv4)、AF_INET6
(IPv6)…type
:socket 类型,SOCK_STREAM
、SOCK_DGRAM
protocol
:协议类型,通常为 0
- 返回值:成功返回socket描述符即文件描述符,失败返回
-1
2.1.2 bind()
将 socket 与特定的IP
和port
绑定(主要用于服务器)。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 参数:
sockfd
:socket()
返回的文件描述符addr
:指向sockaddr
或sockaddr_in
的指针,包含要绑定的地址信息addrlen
:addr
结构体的大小
- 返回值:成功
0
,失败-1
注意: bind()
接收 sockaddr*
类型,需将 sockaddr_in*
转换为 sockaddr*
如:
struct sockaddr_in serv_addr;
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
2.1.3 sendto()
和 recvfrom()
-
sendto():向指定地址发送数据。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
dest_addr
:目标主机的地址信息。
-
recvfrom():从指定地址接收数据。
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
src_addr
:输出参数,存储发送方的地址信息(可设为NULL
)。
2.1.4close()
关闭 socket 描述符,释放资源。
int close(int fd);
2.2 sockaddr 结构体详解
struct sockaddr {sa_family_t sa_family; // 地址族char sa_data[14]; // 地址数据(变长,依地址族而定)
};
socket
网络通信标准隶属于POSIX
通信标准,该标准的设计初衷就是为了实现 可移植性,程序可以直接在使用该标准的不同机器中运行,但有的机器使用的是网络通信,有的则是使用本地通信,socket套接字
为了能同时兼顾这两种通信方式,提供了sockaddr
结构体
由sockaddr
结构体衍生出了两个不同的结构体:sockaddr_in
网络套接字、sockaddr_un
域间套接字,前者用于网络通信,后者用于本地通信
sockaddr
是通用的地址结构体。- 可以根据16位地址类型,判断是网络通信,还是本地通信
- 在进行网络通信时,需要提供
IP
、port
等网络通信必备项,本地通信只需要提供一个路径名,通过文件读写的方式进行通信(类似于命名管道)
socket
提供的接口参数为sockaddr*
,我们既可以传入&sockaddr_in
进行网络通信,也可以传入&sockaddr_un
进行本地通信,传参时将参数进行强制类型转换即可,这是使用 C语言实现多态的典型做法,确保该标准的通用性。
2.2.1 sockaddr _in定义
sockaddr_in
定义在 <netinet/in.h>
头文件中,其核心作用是存储 IPv4 协议的地址信息,包括IP
、port
、协议族
等。在 socket 编程中,很多函数(如 bind()
、connect()
、recvfrom()
等)需要接收一个 sockaddr
类型的指针作为参数,而 sockaddr_in
是 sockaddr
针对IPv4
的 “具体化” 实现。
2.2.2 sockaddr _in结构体成员
struct sockaddr_in {sa_family_t sin_family; // 地址族(必须为 AF_INET)in_port_t sin_port; // 端口号(网络字节序)struct in_addr sin_addr; // IPv4 地址(网络字节序)char sin_zero[8]; // 填充字段,使结构体大小与 sockaddr 一致
};
2.2.3 sin_addr
struct in_addr
(嵌套结构体,用于存储 IPv4 地址)。s_addr
存储 32 位 IPv4 地址。
struct in_addr {in_addr_t s_addr; // IPv4 地址(32位整数,网络字节序)
};
注意:必须使用网络字节序。
- 直接赋值:
sin_addr.s_addr = inet_addr("192.168.1.1");
(inet_addr()
自动转换为网络字节序)。 - 绑定任意地址:
sin_addr.s_addr = INADDR_ANY;
(表示监听本机所有网卡的IP地址
)。
sockaddr_in
是 sockaddr
针对IPv4
的专用版本,两者大小相同(16 字节),可通过强制类型转换互相兼容。
03. 网络程序
加载中…