# 使用listen()和accept()函数

对于服务器端程序，使用 bind() 绑定套接字后，还需要使用 listen() 函数让套接字进入被动监听状态，再调用 accept() 函数，就可以随时响应客户端的请求了。

## listen() 函数

在 Linux 下使用 `<sys/socket.h>`头文件中 listen() 函数可以让套接字进入被动监听状态，它的原型为：

```c
int listen(int sock, int backlog);
```

sock 为需要进入监听状态的套接字，backlog 为请求队列的最大长度。

> 第二个参数backlog 是队列的大小，等于未完成连接队列(正在等待完成相应的TCP三路握手过程) + 已完成连接队列(已经完成相应的TCP三路握手过程)

所谓被动监听，是指当没有客户端请求时，套接字处于“睡眠”状态，只有当接收到客户端请求时，套接字才会被“唤醒”来响应请求。

> 转换成监听状态之后，才能够接受连接
>
> 调用完listen函数后，这个套接字就变成了被动套接字，否则默认是主动套接字
>
> 主动套接字是用来发起连接的，connect
>
> 被动套接字是用来接受连接的， accept

### 请求队列

当套接字正在处理客户端请求时，如果有新的请求进来，套接字是没法处理的，只能把它放进缓冲区，待当前请求处理完毕后，再从缓冲区中读取出来处理。如果不断有新的请求进来，它们就按照先后顺序在缓冲区中排队，直到缓冲区满。这个缓冲区，就称为请求队列（Request Queue）。

缓冲区的长度（能存放多少个客户端请求）可以通过 listen() 函数的 backlog 参数指定，但究竟为多少并没有什么标准，可以根据你的需求来定，并发量小的话可以是10或者20。

如果将 backlog 的值设置为 SOMAXCONN，就由系统来决定请求队列长度，这个值一般比较大，可能是几百，或者更多。

图示：

![](/files/-LfnTGSDK9E0JF09EgZ6)

一旦调用了accept返回后，将这个条目从已完成连接队列移除，以便有更多的客户端能够发起连接。

## accept() 函数

当套接字处于监听状态时，可以通过 accept() 函数来接收客户端请求。它的原型为：

```c
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
```

它的参数与 listen() 和 connect() 是相同的：sock 为服务器端套接字，addr 为 sockaddr\_in 结构体变量，addrlen 为参数 addr 的长度，可由 sizeof() 求得。

> 从已完成连接队列返回第一个连接，如果已完成连接队列为空，则阻塞。
>
> 填充对方的地址，和对方的信息
>
> 成功返回已连接套接字，并变为主动套接字

**注意: accept() 返回一个新的套接字来和客户端通信，addr 保存了客户端的IP地址和端口号，而 sock 是服务器端的套接字，注意区分。**

后面和客户端通信时，要使用这个新生成的套接字，而不是原来服务器端的套接字。

最后需要说明的是：listen() 只是让套接字进入监听状态，并没有真正接收客户端请求，listen() 后面的代码会继续执行，直到遇到 accept()。accept() 会阻塞程序执行（后面代码不能被执行），直到有新的请求到来。


---

# 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://xiaoxiami.gitbook.io/linux-server/socket/socket-xiang-guan-han-shu/shi-yong-listen-he-accept-han-shu.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.
