# 套接字

## 套接字（Sockets）

![](https://drawings.jvns.ca/drawings/sockets.jpeg)

### 什么是套接字？

套接字（Socket）是网络编程的基础，它是进程间通信的一种机制，允许不同主机上的进程进行通信。套接字提供了一个通用的接口，用于通过网络进行数据传输。

### 套接字类型

#### 1. 流套接字（SOCK\_STREAM）

* 提供面向连接的、可靠的数据传输
* 使用TCP协议
* 保证数据顺序和完整性
* 适用于文件传输、网页浏览等

#### 2. 数据报套接字（SOCK\_DGRAM）

* 提供无连接的、不可靠的数据传输
* 使用UDP协议
* 不保证数据顺序和完整性
* 适用于视频流、实时游戏等

#### 3. 原始套接字（SOCK\_RAW）

* 提供对底层网络协议的访问
* 需要root权限
* 适用于网络诊断、协议开发

### 基本套接字操作

```c
// 创建套接字
int socket_fd = socket(domain, type, protocol);

// 绑定地址
bind(socket_fd, (struct sockaddr*)&address, sizeof(address));

// 监听连接（服务器）
listen(socket_fd, backlog);

// 接受连接（服务器）
int client_fd = accept(socket_fd, NULL, NULL);

// 连接服务器（客户端）
connect(socket_fd, (struct sockaddr*)&address, sizeof(address));

// 发送数据
send(socket_fd, buffer, buffer_size, 0);

// 接收数据
recv(socket_fd, buffer, buffer_size, 0);

// 关闭套接字
close(socket_fd);
```

### 地址族

* `AF_INET` - IPv4地址族
* `AF_INET6` - IPv6地址族
* `AF_UNIX` - UNIX域套接字
* `AF_NETLINK` - 内核用户接口
* `AF_PACKET` - 底层包接口

### 套接字选项

```c
// 设置套接字选项
int optval = 1;
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

// 设置超时
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
```

### 常见错误处理

* `ECONNREFUSED` - 连接被拒绝
* `ETIMEDOUT` - 连接超时
* `ECONNRESET` - 连接被重置
* `ENOTCONN` - 套接字未连接

## UNIX域套接字

![](https://drawings.jvns.ca/drawings/unixdomain.jpeg)

### UNIX域套接字特点

UNIX域套接字（UNIX Domain Sockets）是一种特殊的套接字，用于同一主机上的进程间通信。

#### 优势

* **高性能**：不经过网络栈，直接在内核中传递数据
* **安全性**：基于文件系统权限
* **可靠性**：保证数据传输的完整性
* **低延迟**：没有网络开销

#### 使用场景

* 本地服务通信
* 数据库连接
* IPC（进程间通信）
* 微服务架构

#### 创建UNIX域套接字

```c
// 创建UNIX域套接字
int fd = socket(AF_UNIX, SOCK_STREAM, 0);

// 设置地址结构
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/socket_file");

// 绑定地址
bind(fd, (struct sockaddr*)&addr, sizeof(addr));

// 监听和接受连接
listen(fd, 5);
int client_fd = accept(fd, NULL, NULL);
```

#### 文件权限

UNIX域套接字的权限由文件系统权限控制：

```bash
# 设置套接字权限
$ chmod 660 /tmp/socket_file
$ chown user:group /tmp/socket_file
```

#### 客户端连接

```c
// 客户端连接
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/socket_file");
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
```

### 套接字最佳实践

1. **错误处理**：始终检查系统调用的返回值
2. **资源管理**：正确关闭套接字，避免资源泄漏
3. **超时设置**：为网络操作设置合理的超时时间
4. **缓冲区管理**：正确处理部分发送/接收的情况
5. **并发处理**：使用多线程或I/O多路复用处理并发连接

### 参考资料

* [套接字编程指南](https://beej.us/guide/bgnet/)
* [Linux套接字手册](https://man7.org/linux/man-pages/man7/socket.7.html)
* [Julia's Drawings: Sockets](https://drawings.jvns.ca/sockets/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/linux-an-quan/overview/socket.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
