socket 的阻塞模式和非阻塞模式
1|01.socket 的阻塞模式和非阻塞模式
在阻塞和非阻塞模式下,常讨论的具有不同行为表现的 socket 函数一般有 connect、accept、send 和 recv。在 Linux 上对 socket 进行操作时也包括 write 函数和 read 函数。
在 Linux 上, 可以使用 fcntl 函数或 ioctl 函数给创建的 socket 增加 O NONBLOCK 标志来将 socket 设置为非阻塞模式。代码如下:
ioctl 函数与 fcntl 函数的使用方式基本一致。
Linux 上的 socket 函数也可以直接在创建时将 socket 设置为非阻塞模式,socket 函数签名如下:
同时,在 Linux 上利用 accept 函数返回的代表与客户端通信的 socket 也提供了一个扩展 accept4,直接将 accept 函数返回的 socket 设置为非阻塞的:
2|02.send 和 recv 函数在阻塞和非阻塞模式下的表现
- 当 socket 是阻塞模式时,继续调用 send/recv 函数,程序会阻塞在 send/recv 调用处;
- 当 socket 时非阻塞模式时,继续调用 send/recv 函数,send/recv 函数不会阻塞程序执行流,而是立即出错并返回,我们会得到一个相关的错误码,在 Linux 上该错误码为 EWOULDBLOCK 或 EAGAIN。
返回值 | 返回值的含义 |
---|---|
大于0 | 成功发送(send)或接收(recv)n 字节 |
0 | 对端关闭连接 |
小于0(-1) | 出错、被信号中断、对端 TCP 窗口太小导致数据发送不出去或者当前网卡缓冲区已经无数据可接收 |
返回值和错误码 | send函数 | recv函数 | 操作系统 |
---|---|---|---|
返回-1,错误码时EWOUDBLOCK或EAGAN | TCP窗口太小,数据暂时发不出去 | 在当前内核缓冲区无可读数据 | Linux |
返回-1,错误码时EINTR | 被信号中断,需要重试 | 被信号中断,需要重试 | Linux |
返回-1,错误码不是以上3种 | 出错 | 出错 | Linux |
非阻塞模式一般用于支持高并发多 QPS 的场景(如服务器程序),但是这种模式让程序的执行流和控制逻辑变得复杂。
使 send 函数的返回值为 0 的情况:
- 对端关闭连接时,我们正好尝试调用 send 函数发送数据
- 本端尝试调用 send 函数发送 0 字节数据。
recv 函数只有在对端关闭连接时才会返回 0,对端发送 0 字节数据,本段的 recv 函数时不会收到 0 字节数据的,即对端操作系统协议栈不会把 0 字节数据发送过来。
3|03.connect 函数在阻塞和非阻塞模式下的行为
在实际项目中,一般倾向于使用异步 connect 技术(非阻塞 connect),一般有如下步骤:
- 1.创建 socket,将 socket 设置为非阻塞模式。
- 2.调用 connect 函数,此时无论 connect 函数是否连接成功,都会返回;如果返回-1,则并不一定表示连接出错,如果此时错误码时 EINPROGRESS,则表示正在尝试连接。
- 3.调用 select 函数,在指定的时间内判断该 socket 是否可写,如果可写,则说明连接成功,反之认为连接失败。
按上述流程代码编写如下:
点击查看代码
在 Linux 上,一个 socket 在没有建立连接之前,用 select 函数检测其是否可写,我们也会得到可写的结果,所以,在 connect 之后,不仅要用 select 检测是否可写,还要调用 getsockopt 检测此时 socket 是否出错,通过错误码来检测和确定是否连接上,错误码为 0 时表示连接上,反之表示未连接上。可以使用 poll 函数代替 select 函数判断 socket 是否可写;
__EOF__

本文链接:https://www.cnblogs.com/ljx-0122/p/17849768.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理