Linux 网络编程基础:从 TCP/UDP 到 Socket 编程

在网络通信领域,Linux 提供了强大的编程接口,使得开发者能够高效地构建各种网络应用。本文将围绕 TCP/UDP 协议对比、端口号作用、字节序处理以及 Socket 编程核心步骤展开,帮助读者建立 Linux 网络编程的基础框架

一、TCP 与 UDP:两种核心传输协议的对比

1. 连接特性

  • TCP:面向连接(类似电话通信,需先建立连接),通过三次握手确保连接可靠。
  • UDP:无连接(类似写信,直接发送数据),无需提前建立连接,适合实时性场景(如 IP 电话、视频会议)。

2. 可靠性

  • TCP:提供可靠交付,保证数据无差错、不丢失、不重复且按序到达,通过确认机制、重传机制实现。
  • UDP:尽最大努力交付,不保证可靠性,适合对实时性要求高但允许少量丢包的场景。

3. 数据形式

  • TCP:面向字节流,将数据视为无结构的字节序列,适合传输大量连续数据。
  • UDP:面向报文,每个数据报独立传输,保留报文边界,适合小数据量交互。

4. 通信模式

  • TCP:仅支持点到点通信,一对一连接。
  • UDP:支持一对一、一对多、多对一、多对多的多播通信。

5. 首部开销

  • TCP:首部固定 20 字节,包含序列号、确认号、窗口大小等复杂字段。
  • UDP:首部仅 8 字节,包含源端口、目的端口、长度、校验和,简洁高效。

二、端口号:区分服务的 “网络房间号”

  • 作用:一台主机通过 IP 地址提供多种服务(如 Web、FTP、SMTP),需通过 “IP 地址 + 端口号” 唯一标识不同服务。端口号是 16 位无符号整数(0-65535),其中:
    • 知名端口(0-1023):系统预留,如 FTP(21)、Telnet(23)、HTTP(80)、HTTPS(443)。
    • 注册端口(1024-49151):用户程序注册使用,如 MySQL(3306)、Redis(6379)。
    • 动态端口(49152-65535):临时分配给客户端,避免端口冲突。

三、字节序:数据在内存中的存储顺序

1. 两种字节序

  • 小端序(Little Endian):低字节存放在内存低地址(如 x86 架构),例如 0x01020304 在内存中存储为04 03 02 01
  • 大端序(Big Endian):高字节存放在内存低地址(如网络传输标准),存储为01 02 03 04

2. 网络字节序

网络通信统一采用大端序,避免不同架构主机间的字节序冲突。Linux 提供以下 API 实现主机字节序与网络字节序的转换:

#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);   // 主机短整型→网络字节序
uint32_t htonl(uint32_t host32bitvalue);   // 主机长整型→网络字节序
uint16_t ntohs(uint16_t net16bitvalue);    // 网络短整型→主机字节序
uint32_t ntohl(uint32_t net32bitvalue);    // 网络长整型→主机字节序

四、Socket 编程核心步骤:从创建到数据交互

(一)服务器端开发流程

1. 创建套接字(socket)
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • domain:协议族,如AF_INET(IPv4)、AF_INET6(IPv6)。
  • type:套接字类型,SOCK_STREAM(TCP)或SOCK_DGRAM(UDP)。
  • protocol:协议类型,通常为 0(自动选择对应 type 的默认协议)。
2. 绑定地址(bind)

将 IP 地址和端口号绑定到套接字:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);          // 端口号转为网络字节序
server_addr.sin_addr.s_addr = INADDR_ANY;    // 绑定所有可用IP
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
3. 监听连接(listen)

TCP 服务器需监听客户端连接请求:

int listen(int sockfd, int backlog);          // backlog为等待连接队列长度
4. 接受连接(accept)

阻塞等待客户端连接,返回新的套接字描述符用于数据交互:

struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
5. 数据交互(read/write 或 send/recv)
  • TCP 字节流:使用read(connfd, buf, len)读取数据,write(connfd, buf, len)发送数据。
  • UDP 数据报:使用recvfromsendto,需指定对端地址。
6. 关闭套接字(close)
close(sockfd);
close(connfd);

 

(二)客户端开发流程

1. 创建套接字(同服务器)
2. 连接服务器(connect)
struct sockaddr_in server_addr;
inet_aton("192.168.1.100", &server_addr.sin_addr);  // 字符串IP转网络格式
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 

3. 数据交互(同服务器)
4. 关闭套接字

五、关键 API 总结与最佳实践

  • 地址转换工具inet_aton(字符串 IP→网络字节序)和inet_ntoa(网络字节序→字符串 IP)简化 IP 处理。
  • 协议选择:需可靠性选 TCP,需实时性选 UDP;UDP 需自行处理丢包和重传。
  • 错误处理:所有 Socket 函数需检查返回值,处理errno错误码(如EAGAIN表示资源暂时不可用)。

六、总结

Linux 网络编程的核心是理解 TCP/UDP 的差异、合理使用端口号、处理字节序转换,并掌握 Socket 编程的基本流程。从创建套接字到数据交互,每个步骤都需关注细节(如地址结构对齐、网络字节序转换),才能构建稳定高效的网络应用。无论是开发服务器端程序还是客户端工具,扎实的基础都是解决复杂网络问题的关键。通过实践不同场景(如并发服务器、UDP 广播),可进一步提升网络编程能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值