文章目录
-
网络的体系结构 (Network Architecture) 是计算机网络的各层及其协议的集合,就是这个计算机网络及其构件所应完成的功能的精确定义(不涉及实现)
-
实现 (implementation) 是遵循这种体系结构的前提下,用何种硬件或软件完成这些功能的问题
Socket套接字

latex
┌─────────────────┐
│ 应用程序 │
├─────────────────┤
│ Socket API │ ← 网络编程接口
├─────────────────┤
│ 传输层(TCP/UDP) │
├─────────────────┤
│ 网络层(IP) │
├─────────────────┤
│ 链路层/物理层 │
└─────────────────┘
- 套接字属于一种特殊的文件描述符
- UNIX域套接字用于进程间通信
Scoket概念
- 定义:应用层与TCP/IP协议族通信的中间软件抽象层,是一组API
- 作用:网络通信的端点,包含IP地址 + 端口号 + 协议三元组
- IP地址:标识计算机
- 端口号:标识计算机当中的进程
- 协议:指定数据传输的方式
- 本质:特殊的文件描述符,可以通过文件I/O函数(read/write)操作
常见的网络编程接口
- Berkeley Socket:UNIX/Linux标准,POSIX规范
- Windows Socket (Winsock):Windows平台的socket实现
- TLI (Transport Layer Interface):AT&T UNIX的传输层接口
Socket地址结构
通用地址结构(用于类型转换)
c
#include <sys/socket.h>
// 通用地址结构体(所有专用结构体都要转换为这个类型)
struct sockaddr {
sa_family_t sa_family; // 地址族:AF_XXX
char sa_data[14]; // 地址数据
};
- AF_UNIX:使用本地域套接字的地址结构,用于本地通信
- AF_INET: 使用IPv4的通信地址结构
- AF_INET6:使用IPv6的通信地址结构
IPv4专用地址结构(最常用)
c
#include <netinet/in.h>
// IPv4地址结构体
struct sockaddr_in {
sa_family_t sin_family; // 地址族:AF_INET
in_port_t sin_port; // 端口号(网络字节序)
struct in_addr sin_addr; // IPv4地址
};
// IPv4地址(32位)
struct in_addr {
uint32_t s_addr; // IPv4地址(网络字节序)
};
IPv6专用地址结构
c
#include <netinet/in.h>
// IPv6地址结构体
struct sockaddr_in6 {
sa_family_t sin6_family; // 地址族:AF_INET6
in_port_t sin6_port; // 端口号(网络字节序)
uint32_t sin6_flowinfo; // IPv6流信息
struct in6_addr sin6_addr; // IPv6地址
uint32_t sin6_scope_id; // 作用域ID
};
// IPv6地址(128位)
struct in6_addr {
unsigned char s6_addr[16]; // IPv6地址
};
套接字类型

三种主要类型
| 类型 | 常量 | 协议 | 特点 | 适用场景 |
|---|---|---|---|---|
| 流式套接字 | SOCK_STREAM |
TCP | 可靠、面向连接、字节流 | 文件传输、HTTP、SSH |
| 数据报套接字 | SOCK_DGRAM |
UDP | 不可靠、无连接、数据报 | DNS、音视频流、实时游戏 |
| 原始套接字 | SOCK_RAW |
直接IP层 | 直接操作底层协议 | 网络工具开发(ping/traceroute) |
选择原则
c
// TCP套接字(嵌入式服务器常用)
int tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
// UDP套接字(嵌入式传感器数据上报)
int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
// 原始套接字(网络诊断工具)
int raw_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
TCP通信实现框架

- 通信之前,客户端和服务器端先创建套接字
- 服务器端调用 bind,把端口号和本地 IP 地址填写到已创建的套接字中
- 服务器端调用 listen(收听),把套接字设置为被动方式,以便随时接受客户的服务请求。UDP 服务器不使用 listen 系统调用
- 服务器端调用 accept(接受),以便把远地客户进程发来的连接请求提取出来。UDP 服务器不使用 accept 系统调用
- 客户端进程调用 connect,以便和远地服务器建立连接
- 客户端和服务器在 TCP 连接上使用 write传送数据,使用 read接收数据
- 客户端或服务器通信结束,调用 close 释放连接和撤销套接字
三次握手在框架中的体现
latex
客户端 服务器端
│ │
│ SYN=1 │
├───────────────────>│ socket() + bind() + listen()
│ │
│ SYN=1, ACK=1 │
│<───────────────────┤ accept()阻塞等待连接
│ │
│ ACK=1 │
├───────────────────>│ accept()返回,连接建立
│ │
│ 数据交换 │
│<──────────────────>│