当前位置: 首页>編程日記>正文

【服务器系统设计】socket的阻塞模式和非阻塞模式总结

【服务器系统设计】socket的阻塞模式和非阻塞模式总结

前言

对socket在阻塞和非阻塞模式下各个socket函数的表现进行深入理解,是掌握网络编程的基本要求之一,也是重点和难点。
在阻塞和非阻塞模式下,我们常常讨论的具有不同行为表现的socket函数一般有connect,accept,send和recv。

定义

阻塞模式:指的是当某个函数执行成功的条件当前不满足时,该函数会阻塞当前执行线程,程序执行流在超时时间到达或执行成功的条件满足后恢复继续执行。
非阻塞模式:即使某个函数执行成功的条件不满足,该函数也不会阻塞当前执行线程,而是立即返回,继续执行程序流。

如何将socket设置为非阻塞模式

无论是在Windows还是Linux,默认创建的socket都是阻塞模式的。
在Linux上,可以通过使用fcntl函数或者ioctl函数给创建的socket增加O_NONBLOCK标志来将socket设置为非阻塞模式,示例代码如下:

int oldSocketFlag = fcntl(socketfd, F_GETFL, 0);
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
fcntl(socketfd, F_SETFL, newSocketFlag);

当然,Linux上的socket函数也可以在创建时将socket设置为非阻塞模式,socket函数签名如下:

int socket(int domain, int type, int protocol);

只要给type参数增加一个SOCK_NONBLOCK标志即可,例如:

int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

不仅如此,在Linux上利用accept函数返回的代表与客户端通信的socket也提供了一个扩展函数accept4,直接将accept函数返回的socket设置为非阻塞的:

int accept(int sockfd, struct sockaddr* addr, socklen_t *addrlen);
int accept(int sockfd, struct sockaddr* addr, socklen_t *addrlen, int flags);

只需要将accept4函数最后一个参数设置为SOCK_NONBLOCK即可。如下:

socklen_t addrlen = sizeof(clientaddr);
int clientfd = accept4(listenfd, &clientaddr, &addrlen, SOCK_NONBLOCK);

send函数和recv函数在阻塞和非阻塞模式下的表现

我们先来想一个问题,当程序调用了send函数,是不是就意味着将数据成功发送到网络上了?
其实,send和recv函数的命名其实有一种误导效果。

  • send函数从本质上来说并不是向网络发送数据,而是将应用层发送缓冲区的数据拷贝到内核缓冲区中,至于数据什么时候会从网卡缓冲区中真正地发送到网络中,要根据TCP/IP的协议栈的行为来确定。如果socket设置了TCP_NODELAY选项(即禁用nagel算法),存放到内核缓冲区的数据就会被立即发送出去;反之,一次放入内核缓冲区的数据包如果太小,则系统会在多个小的数据包凑成一个足够大的数据包后才会将数据发送出去。
  • recv函数在本质上并不是从网络收取数据,而是将内核缓冲区中的数据拷贝到应用程序的缓冲区中,当然,拷贝完成后会将内核缓冲区中的该部分的数据移除。

那么我们来想一种情况,假如说,有一个应用程序A跟应用程序B建立了TCP通信,而应用程序不断调用send函数,那么数据将会不断地拷贝到对应的内核缓冲区中,如果应用程序一直不调用recv函数,那么在应用程序B的内核缓冲区被填满后,应用程序A的内核缓冲区也会被填满,此时应用程序A继续调用send函数会是什么结果呢?具体的结果取决于socket是否是阻塞模式
(1)当socket是阻塞模式时,继续调用send/recv函数,程序会阻塞在send/recv调用处
(2)当socket是非阻塞模式时,继续调用send/recv函数,send/recv函数不会阻塞程序执行流,而是立即出错并返回,在Linux上会返回一个EWOULDBLOCK或者EAGAIN(两个错误码值相同)错误码。

非阻塞模式下如何正确地调用send/recv函数

由于非阻塞模式会让程序的执行流变得复杂,不像阻塞模式下那么简单明了。
以send函数为例,有人可能会写出这样的程序:

int n = send(socket, buf, buf_length, 0);
if(n == buf_length)
{std::cout << "send data succ!" << std::endl;
}

其实这种写法是不推荐的,正确地写法应该这样:

bool sendData(const char* buf, int buf_length)
{int send_bytes = 0; //已发送的字节数int ret = 0;while(true){ret = send(socket_, buf + send_bytes, buf_length - send_bytes, 0);if(ret == -1){if(errno == EWOULDBLOCK){//缓存尚未发送出去的数据break;}else if(errno == EINTR){continue;}else{return false;}}else if(ret == 0){return false;}send_bytes += ret;if(send_bytes == buf_length){break;	}}return true;
}

阻塞与非阻塞模式socket各自的应用场景

阻塞的socket函数在调用send、recv、connect、accept等函数时,如果条件不满足,就会阻塞其调用线程直至超时,非阻塞的socket则会立即返回。但这并不意味着非阻塞模式一定比阻塞模式好,两者各有优缺点。
非阻塞一般用于需要支持高并发的场景,但这种模式会让程序的执行流变得复杂,相反,阻塞模式的使用逻辑十分简单,程序结构简单明了,可以用在一些特殊场景中。
适合非阻塞模式的应用场景:

  • 需要支持高并发程序,如服务端程序

适合阻塞模式下的应用场景:

  • 某程序需要临时发送一个文件,文件分段发送,每发送一段,对端都会给予一个响应。
  • 程序A和程序B之间的通信只有问答模式,即A端每发送给B端一个请求,B端必定会给A端一个响应,除此之外,B端不会向A端推送任何数据,此时A端就可以采用阻塞模式。


https://www.fengoutiyan.com/post/15835.html

相关文章:

  • socket阻塞和非阻塞的区别
  • websocket多服务器
  • socket服务器搭建
  • socket非阻塞
  • mqtt服务器哪个好
  • socket没有阻塞吗
  • java socket服务器
  • php websocket服务器
  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機