【Linux】Socket阻塞和非阻塞、同步与异步

创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
🔥Linux系列专栏:Linux基础 🔥

给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ

在这里插入图片描述


目录

  • 阻塞
  • 非阻塞
  • 同步和异步

阻塞

阻塞模式下,send函数返回时,只代表需要发送的数据已经被拷贝到内核的发送缓冲区

并且如果发送缓冲区有足够的空间,数据可能已经开始从发送缓冲区发送到网络上。但是并不代表数据已经成功地被接收方接收

当发送缓冲区空间不够大的时候,等到发送缓冲区空间足够大再发送

调用recv函数并且套接字没有数据可读时,recv函数会阻塞当前线程,直到有数据可读或者出现错误。

如果 recv 函数返回,返回值代表内核的接收缓冲区中的数据已经被拷贝到用户空间

/* Windows下UDP阻塞socket*/#include <iostream>
#include <WinSock2.h>
using namespace std;#pragma comment(lib,"Ws2_32.lib")int main()
{//1.加载库,相当于将dll拷贝到exe路径下WORD wVersion = MAKEWORD(2, 2);WSADATA wsadata;int errcode = 0;errcode = WSAStartup(wVersion, &wsadata);//1.1判断WSAStartup是否成功if (errcode != 0){cout << "WSAStartup error:" << errcode << endl;return -1;}//1.2判断版本是否正确if (LOBYTE(wsadata.wVersion)!= 2 || HIBYTE(wsadata.wVersion) != 2){cout << "WSAStartup wVersion error" << endl;WSACleanup();			return -1;	}else //库和版本都加载成功{cout << "WSAStartup success!" << endl;}//2.创建套接字SOCKET sock;sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//2.1判断套接字是否创建成功if (sock == INVALID_SOCKET)		//INVALID无效的{cout << "set socket error:" << WSAGetLastError() << endl;WSACleanup();return -1;}else   //套接字创建成功{cout << "set socket success!" << endl;}//3.绑定ip和端口号struct sockaddr_in addrServer;addrServer.sin_family = AF_INET;addrServer.sin_addr.S_un.S_addr = INADDR_ANY;addrServer.sin_port = htons(8080);	//htons将端口号转换为大端模式errcode = bind(sock, (sockaddr*)&addrServer, sizeof(addrServer));//3.1判断绑定是否成功if (errcode == SOCKET_ERROR){cout << "bind error:" << WSAGetLastError() << endl;//关闭套接字closesocket(sock);//卸载库WSACleanup();return -1;}else{cout << "bind success!" << endl;}//4.循环接收发送消息int recvNum = 0;int sendNum = 0;char recvbuf[1024] = "";char sendbuf[1024] = "";struct sockaddr_in addrClient;int addrClientSize = sizeof(addrClient);while (true){//接收消息recvNum = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (sockaddr*)&addrClient, &addrClientSize);//判断接收成功if (recvNum > 0){//打印收到的数据//192.168.1.1——十进制四等分字符串类型ip地址:inet_addr//ulong类型ip地址:inet_ntoacout << "来自ip:" << inet_ntoa(addrClient.sin_addr) << " 的消息: " << recvbuf << endl;}else if (recvNum == 0)		//连接关闭{cout << "connection closed" << endl;break;}else                        //接收错误{cout << "recvfrom error:" << WSAGetLastError() << endl;break;}//发送消息gets_s(sendbuf);sendNum = sendto(sock, sendbuf, sizeof(sendbuf), 0, (sockaddr*)&addrClient, addrClientSize);//判断发送成功if (sendNum != 0){cout << "send success!" << endl;}else{cout << "sendto error:" << WSAGetLastError() << endl;}}//5.关闭套接字closesocket(sock);//6.卸载库WSACleanup();return 0;
}

阻塞 IO 开发简单,但不适合多个客户端高并发


非阻塞

在非阻塞模式下,send函数将数据放入内核的发送缓冲区,并立即返回

但是,如果发送缓冲区没有足够的空间来容纳全部数据,send函数会返回已经成功拷贝到发送缓冲区的字节数,有多少空间就往里拷贝多少内容,而不是全部要发送的数据

当发送缓冲区空间不够大的时候,有多少空间就往里拷贝多少内容,剩下的数据应用程序自己处理

当调用recv函数并且套接字没有数据可读时,recv函数会立即返回一个错误(EWOULDBLOCK或EAGAIN),而不是阻塞当前线程。

/* Windows下UDP非阻塞socket*/
#include <iostream>
#include <WinSock2.h>
using namespace std;#pragma comment(lib,"Ws2_32.lib")int main()
{//1.加载库,相当于将dll拷贝到exe路径下WORD wVersion = MAKEWORD(2, 2);WSADATA wsadata;int errcode = 0;errcode = WSAStartup(wVersion, &wsadata);//1.1判断WSAStartup是否成功if (errcode != 0){cout << "WSAStartup error:" << errcode << endl;return -1;}//1.2判断版本是否正确if (LOBYTE(wsadata.wVersion)!= 2 || HIBYTE(wsadata.wVersion) != 2){cout << "WSAStartup wVersion error" << endl;WSACleanup();			return -1;	}else //库和版本都加载成功{cout << "WSAStartup success!" << endl;}//2.创建套接字SOCKET sock;sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//Windows下设置socket为非阻塞u_long val = 1;ioctlsocket(sock, FIONBIO, &val);//Linux下://int flags = fcntl(sock, F_GETFL, 0);//fcntl(sock, F_SETFL, flags | O_NONBLOCK);//2.1判断套接字是否创建成功if (sock == INVALID_SOCKET)		//INVALID无效的{cout << "set socket error:" << WSAGetLastError() << endl;WSACleanup();return -1;}else   //套接字创建成功{cout << "set socket success!" << endl;}//3.绑定ip和端口号struct sockaddr_in addrServer;addrServer.sin_family = AF_INET;addrServer.sin_addr.S_un.S_addr = INADDR_ANY;addrServer.sin_port = htons(8080);	//htons将端口号转换为大端模式errcode = bind(sock, (sockaddr*)&addrServer, sizeof(addrServer));//3.1判断绑定是否成功if (errcode == SOCKET_ERROR){cout << "bind error:" << WSAGetLastError() << endl;//关闭套接字closesocket(sock);//卸载库WSACleanup();return -1;}else{cout << "bind success!" << endl;}//4.循环接收发送消息int recvNum = 0;int sendNum = 0;char recvbuf[1024] = "";char sendbuf[1024] = "";struct sockaddr_in addrClient;int addrClientSize = sizeof(addrClient);while (true){//接收消息recvNum = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (sockaddr*)&addrClient, &addrClientSize);//判断接收成功if (recvNum > 0){//打印收到的数据//192.168.1.1——十进制四等分字符串类型ip地址:inet_addr//ulong类型ip地址:inet_ntoacout << "来自ip:" << inet_ntoa(addrClient.sin_addr) << " 的消息: " << recvbuf << endl;}else if (recvNum == 0)		//连接关闭{cout << "connection closed" << endl;break;}else if (WSAGetLastError() != 10035) {		//非阻塞{cout << "recvfrom error:" << WSAGetLastError() << endl;break;}}//5.关闭套接字closesocket(sock);//6.卸载库WSACleanup();return 0;
}

同步和异步

  • 同步

同步模型:一个操作必须等待前一个操作完成后才能进行。比如说,当客户端向服务器发送一个请求并期望得到响应时,它会处于阻塞状态,直到服务器返回响应

read(), write(), recv(), send()


  • 异步

异步模型则打破了这种顺序执行的限制。在异步 I/O 中,客户端发送请求后不会被阻塞,而是可以继续执行其他操作。当服务器的响应准备好时,通过回调函数、事件机制或者消息队列等方式通知客户端

异步模型的优点在于能够极大地提高系统的并发性和响应性。它能够充分利用系统资源,避免了因等待而造成的资源浪费

同步和异步的区分:是否是用户自己写代码实现的将数据从内核缓冲区拷贝到用户缓冲区,如果不是自己写代码实现的,通过回调函数、事件通知或其他机制告知用户 就是异步


在这里插入图片描述

大家的点赞、收藏、关注将是我更新的最大动力! 欢迎留言或私信建议或问题。
大家的支持和反馈对我来说意义重大,我会继续不断努力提供有价值的内容!如果本文哪里有错误的地方还请大家多多指出(●'◡'●)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/859888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java项目生成的api文档

生成Java项目API文档的方法 在进行Java项目开发时&#xff0c;编写良好的API文档对于团队合作和后续维护非常重要。生成API文档不仅可以提高团队协作效率&#xff0c;还可以方便其他开发人员了解项目结构和接口调用方式。在本文中&#xff0c;我们将介绍如何通过Java工具生成A…

WPF与Winform,你的选择是?

概述 在桌面应用的发展历程中&#xff0c;Winform和WPF作为微软推出的两大框架&#xff0c;各自承载着不同的设计理念和技术特色。Winform以其稳定、成熟的技术基础&#xff0c;长期占据着企业级应用开发的重要地位。而WPF&#xff0c;作为后来者&#xff0c;以其现代化的UI设计…

【ajax核心02】底层原理-Promise对象

目录 一&#xff1a;promise对象是什么 二&#xff1a;语法&#xff08;Promise使用步骤&#xff09; 三&#xff1a;Promise-三种状态 一&#xff1a;promise对象是什么 Promise 对象代表异步操作最终的完成&#xff08;或失败&#xff09;以及其结果值。 即Promise对象是…

CentOS7系统的软件源更改为阿里云源-3

要将您的CentOS系统的软件源更改为阿里云源&#xff0c;您可以按照以下步骤操作&#xff1a; 打开终端。 首先&#xff0c;备份原始的 CentOS-Base.repo 文件&#xff0c;以防出现问题时可以恢复&#xff1a; sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cen…

SAP系统中的总账会计(知识点总结)

总账会计 财务报表的组织结构 Company Code: 公司代码&#xff0c;an independent accounting entity&#xff0c; 一个独立的会计实体, 存储的数据为 T001。针对同一个公司代码会有Parallel Financial Reporting&#xff08;平行帐&#xff09;的要求&#xff0c;为了实现平…

基于springboot的图书管理系统源码数据库

当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。传统的图书管理信息管理模式&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以人力为主的管理模式已然落后。本人结合使用主流的…

两个模型划分的瓦片数不同,可以把同一物体的两个模型(各有优缺点)就行融合修模吗?

答&#xff1a;网格大师可以针对模型瓦块名称&#xff0c;原点&#xff0c;大小不统一的数据进行融合 网格大师是一款能够解决实景三维模型空间参考、原点、瓦块大小不统一&#xff0c;重叠区域处理问题的工具“百宝箱”&#xff0c;集格式转换、坐标转换、轻量化、瓦片重划分…

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来&#xff0c;无需把原生代码转换为uniapp&#xff0c;可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录&#xff0c;原生入口…

java基于ssm+jsp 医院远程诊断系统

1前台首页功能模块 医院远程诊断系统&#xff0c;在系统首页可以查看首页、医生信息、论坛信息、我的、跳转到后台、客服等内容&#xff0c;如图1所示。 图1前台首页功能界面图 用户登录&#xff0c;在用户登录页面可以填写用户名、密码、等信息进行用户登录&#xff0c;如图2…

【Linux基础】-- 日志系统syslog与logger的使用方法整理

系统日志配置与使用指南 一、syslog 的使用 syslog 是一种标准用于记录程序运行日志信息的协议。以下是一些基本使用方法&#xff1a; 检查 syslogd 进程 确保 syslogd 进程正在运行。可以通过以下命令检查&#xff1a; ps | grep syslogd如果没有看到 syslogd 进程在运行…

安装Django Web框架

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Django是基于Python的重量级开源Web框架。Django拥有高度定制的ORM和大量的API&#xff0c;简单灵活的视图编写&#xff0c;优雅的URL&#xff0c;适…

kafka 集群的数据顺序写入和零拷贝技术设计实现原理

kafka 集群的数据顺序写入和零拷贝技术设计实现原理 Kafka 是一种高吞吐量、分布式消息系统,其高性能设计得益于数据顺序写入和零拷贝技术。 下面详细介绍这两种技术在 Kafka 中的实现原理。 1. 数据顺序写入设计原理 顺序写入的优势 顺序写入是 Kafka 实现高性能的关键技…

近2年时间,华为手机上的卫星通信功能发展成怎样了?

自从Mate 50 系列支持北斗卫星短报文功能以来&#xff0c;已经过去了近2年的时间&#xff0c;卫星相关的功能也从最开始的摸索、罕见&#xff0c;逐渐变得成熟、在各品牌旗舰机上常见起来。 那么&#xff0c;这近两年的发展&#xff0c;卫星相关的功能都有了怎样的变化呢&…

史上最全整合nacos单机模式整合哈哈哈哈哈

Nacos 是阿里巴巴推出的一个新开源项目&#xff0c;它主要是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos提供了一组简单易用的特性集&#xff0c;帮助用户快速实现动态服务发现、服务配置、服务元数据及流量管理。 Nacos 的关键特性包括&#x…

简过网:公务员报班和不报班的有区别吗?

很多备考公务员的朋友可能都会有这种纠结&#xff0c;到底要不要报个培训班呢&#xff0c;报班了怕没什么用&#xff0c;不报班又怕自己考不上&#xff0c;如果你也有这个疑问&#xff0c;那么不妨来看看这篇文章&#xff01; ​ 先说一下&#xff0c;公务员报班和不报班的有区…

3110. 字符串的分数

给你一个字符串 s 。一个字符串的 分数 定义为相邻字符 ASCII 码差值绝对值的和。 请你返回 s 的 分数 。 示例 1&#xff1a; 输入&#xff1a;s "hello" 输出&#xff1a;13 解释&#xff1a; s 中字符的 ASCII 码分别为&#xff1a;h 104 &#xff0c;e 1…

python项目使用pre-commit确保代码规范

1. 安装pre-commit (建议直接使用pipx全局安装&#xff0c;无需每个项目单独安装&#xff09; pipx install pre-commit 2. 模板&#xff1a; 一、需要兼容3.10以下版本的&#xff1a; # See https://pre-commit.com for more information # See https://pre-commit.com/h…

平方根的三种求法(袖珍计算器算法,二分查找,牛顿迭代)

一、袖珍计算器 袖珍计算器方法主要运用到了我们高数上所学的关于e底数转化的思想&#xff0c;即 一种用指数函数 exp⁡ 和对数函数 ln⁡ 代替平方根函数的方法 : 1、exp函数&#xff1a; exp是 C 标准库 <math.h> 中的一个函数&#xff0c;用于计算 e 的 x 次幂&…

微服务(服务治理)

服务远程调用时存在的问题 注册中心原理 服务治理中的三个角色分别是什么&#xff1f; 服务提供者&#xff1a;暴露服务接口&#xff0c;供其它服务调用服务消费者&#xff1a;调用其它服务提供的接口注册中心&#xff1a;记录并监控微服务各实例状态&#xff0c;推送服务变更信…

【乐吾乐2D可视化组态编辑器】图表动态显示

1. 添加数据 乐吾乐2D可视化组态编辑器地址&#xff1a;https://2d.le5le.com/ 图表动态展示是指一个图表图元的数据属性&#xff08;一般是dataY&#xff09;绑定多个变量&#xff0c;建立通信后数据动态变化展示。 官网默认Echarts图表拖拽到画布中是已经添加了图元的da…