从缓冲上看阻塞与非阻塞socket在发送接收上的区别

合集下载

sock的知识点总结

sock的知识点总结

sock的知识点总结1. Sock 的概念和作用Sock 是 Socket 的简称,它是在网络编程中非常重要的概念,它提供了一种通信机制,使得计算机之间可以进行数据交换。

Sock 的主要作用包括:建立连接、传输数据、断开连接等。

它为应用层提供了数据传输的能力,同时也可以实现基于 TCP 或 UDP 的各种协议。

2. Sock 的类型Sock 可分为两种类型,分别是面向连接的 Socket 和面向无连接的 Socket。

面向连接的Socket 是指通过建立连接来进行数据传输,它使用 TCP 协议进行通信;而面向无连接的Socket 是指不需要事先建立连接,可以直接进行数据传输,它使用 UDP 协议进行通信。

面向连接的 Socket 保证了数据的可靠传输,但是会有一定的延迟;而面向无连接的Socket 则具有高效的特点,但是不保证数据的可靠性。

3. Sock 的地址在网络通信中,Sock 的地址包括主机地址和端口号。

主机地址用来标识网络中的计算机,而端口号则用来标识计算机上的不同进程。

主机地址和端口号组合在一起,就可以唯一确定一台计算机上的一个进程。

在建立 Sock 连接时,需要指定对方的主机地址和端口号,以便进行通信。

4. Sock 的创建和使用在编程中,要使用 Sock 进行网络通信,需要经过一系列的步骤来创建和使用 Sock。

首先需要创建一个 Sock,然后绑定地址和端口号,接着监听连接请求或者发起连接请求,最后进行数据传输和断开连接。

在 C 语言中,可以使用 socket() 函数来创建 Sock,bind() 函数来绑定地址和端口号,listen() 函数来监听连接请求,accept() 函数来接受连接请求,connect() 函数来发起连接请求,send() 函数和recv() 函数来进行数据传输,close() 函数来断开连接。

5. Sock 的通信模式Sock 的通信模式包括客户端-服务端模式和对等通信模式。

recv函数阻塞_socket缓冲区以及阻塞模式详解

recv函数阻塞_socket缓冲区以及阻塞模式详解

recv函数阻塞_socket缓冲区以及阻塞模式详解在网络编程中,阻塞函数是一种常见的方式,以等待数据的到来或发送完成。

其中,recv函数是在TCP套接字中用来从套接字中接收数据的函数之一、本文将详细介绍recv函数的阻塞特性以及相关的概念,例如套接字缓冲区和阻塞模式。

首先,我们先了解一下套接字缓冲区。

套接字缓冲区是指用于存储发送和接收的数据的内存区域。

发送方将数据放入发送缓冲区,而接收方从接收缓冲区中读取数据。

套接字缓冲区有两种,分别是发送缓冲区和接收缓冲区。

发送缓冲区:当应用程序使用套接字发送数据时,数据会首先被复制到发送缓冲区中,然后由操作系统发送给对方。

如果发送缓冲区已满,应用程序会被阻塞,直到有足够的空间来存放待发送的数据。

接收缓冲区:当数据到达套接字时,数据会存储在接收缓冲区中,等待应用程序读取。

如果接收缓冲区为空,应用程序会阻塞,直到有数据可读。

接下来,我们来看看阻塞模式。

套接字有两种工作模式,分别是阻塞模式和非阻塞模式。

阻塞模式:在阻塞模式下,对套接字的操作会导致调用线程阻塞,直到操作完成或超时。

在调用recv函数时,如果接收缓冲区为空,调用线程会被阻塞,直到有数据可读。

同样地,如果发送缓冲区已满,调用线程会被阻塞,直到有足够的空间来存放待发送的数据。

非阻塞模式:与阻塞模式相反,在非阻塞模式下,对套接字的操作不会阻塞调用线程,无论操作是否能够立即完成。

在调用recv函数时,如果接收缓冲区为空,函数会立即返回一个错误码,而不是阻塞等待数据到来。

如果发送缓冲区已满,函数会立即返回一个错误码,而不是阻塞等待空间释放。

需要注意的是,尽管非阻塞模式下可以提高响应速度,但也可能导致一些问题。

因为调用线程不会阻塞,所以需要使用循环来反复调用recv函数,以确保数据完全接收。

此外,在非阻塞模式下,可能需要处理缓冲区已满或为空的情况。

总结起来,recv函数是一个在TCP套接字中用于接收数据的函数,具有阻塞特性。

socet发送端发送缓冲区满,接收端接收缓冲区为空,收不到数据 -回复

socet发送端发送缓冲区满,接收端接收缓冲区为空,收不到数据 -回复

socet发送端发送缓冲区满,接收端接收缓冲区为空,收不到数据-回复socet发送端发送缓冲区满,接收端接收缓冲区为空,收不到数据。

Socket(套接字)是计算机网络中的一种通信机制,它提供了一种通过网络进行数据通信的方式。

在数据传输过程中,发送端将数据写入发送缓冲区,接收端从接收缓冲区读取数据。

然而,在某些情况下,发送端的发送缓冲区可能会因为满了无法再继续发送数据,而接收端的接收缓冲区可能会因为空了无法从缓冲区中获取数据。

这种情况下,接收端将无法收到数据。

接下来,我们将一步一步回答这个问题,解释为什么发送端发送缓冲区满,接收端接收缓冲区为空,导致无法收到数据,并提供解决方法。

首先,我们来解释发送缓冲区和接收缓冲区的概念。

发送缓冲区是发送端内存中用于存放待发送数据的区域,它可以看作是发送端和网络之间的一个缓冲区。

接收缓冲区是接收端内存中用于存放接收到的数据的区域,它可以看作是网络和接收端之间的一个缓冲区。

当发送端需要发送数据时,数据将被写入发送缓冲区。

发送端会将数据从应用程序复制到发送缓冲区中,然后发送缓冲区逐步将数据发送到网络中。

如果发送缓冲区满了,即发送缓冲区的空间已经全部被占用,发送端将无法继续向发送缓冲区写入数据,进而无法发送数据到网络中。

当接收端接收数据时,数据将被读取到接收缓冲区。

接收端会从网络中接收数据,并将接收到的数据存放到接收缓冲区中。

如果接收缓冲区为空,即没有数据存放在接收缓冲区中,接收端无法从接收缓冲区中获取数据,进而无法得知发送端发送的数据。

现在,我们来探讨一下为什么发送缓冲区会满而接收缓冲区会空。

发送缓冲区满的原因可以有多种,包括以下几个方面:1. 发送速度过快:如果发送端的发送速度超过了网络传输的速度,发送缓冲区就会很快被填满。

这通常发生在发送端发送的数据量大于接收端接收的数据量的情况下。

2. 网络拥塞:如果网络中的数据传输带宽有限或者网络拥塞,发送端的发送速度可能会受到限制,导致发送缓冲区满而无法发送数据。

python socket recv工作原理

python socket recv工作原理

python socket recv工作原理一、概述在Python网络编程中,Socket是一种非常重要的接口,用于在不同的计算机或应用程序之间进行通信。

Socket API提供了许多方法,其中recv方法是其中一个非常重要的方法,用于从Socket中接收数据。

本文将详细介绍Python Socket recv的工作原理。

二、Socket recv的基本原理Socket recv方法用于从Socket中接收数据,它属于阻塞IO操作。

当调用recv方法时,程序会一直等待,直到有数据可接收或者发生错误。

recv方法会阻塞等待,直到接收到数据或者超时或者出错为止。

在正常情况下,recv方法会一直阻塞等待,直到接收到数据为止。

三、如何接收数据在Socket recv中,数据接收的方式取决于连接的类型。

对于TCP连接,数据是连续的字节流,可以使用recv方法直接接收数据。

对于UDP连接,数据是独立的消息包,需要使用recvfrom方法接收数据,同时需要指定缓冲区大小。

四、缓冲区的作用在Python Socket recv中,缓冲区是一个重要的概念。

recv方法会将接收到的数据存储在指定的缓冲区中,因此缓冲区的大小直接影响接收数据的效率。

如果缓冲区太小,会导致频繁的内存分配和释放操作,影响性能;如果缓冲区太大,会导致内存浪费。

因此,选择合适的缓冲区大小非常重要。

五、阻塞与非阻塞IO在Python Socket编程中,阻塞IO和非阻塞IO是最常见的两种模式。

阻塞IO模式下,recv方法会一直等待直到接收到数据或者发生错误;而非阻塞IO模式下,recv方法会在没有数据可接收时立即返回。

在实际应用中,需要根据具体情况选择合适的IO模式。

六、异常处理在Python Socket编程中,异常处理是非常重要的一部分。

当Socket连接发生错误或者超时时,recv方法会抛出异常。

因此,需要使用try/except块来捕获异常并进行处理。

Socket调用方式(同步,异步,阻塞,非阻塞)

Socket调用方式(同步,异步,阻塞,非阻塞)

Socket调⽤⽅式(同步,异步,阻塞,⾮阻塞)同步:我调⽤⼀个功能,该功能没有结束前,我死等结果。

异步:当⼀个异步过程调⽤发出后,调⽤者不能⽴刻得到结果。

该功能在完成后,通过状态、通知和回调来通知调⽤者。

同步和⾮同步关注的是调⽤者是否等待等待调⽤结果。

举个通俗的例⼦:你打电话问书店⽼板有没有《分布式系统》这本书,如果是同步通信机制,书店⽼板会说,你稍等,”我查⼀下",然后开始查啊查,等查好了(可能是5秒,也可能是⼀天)告诉你结果(返回结果)。

⽽异步通信机制,书店⽼板直接告诉你我查⼀下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。

然后查好了,他会主动打电话给你。

在这⾥⽼板通过“回电”这种⽅式来回调。

阻塞:调⽤我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。

⾮阻塞:调⽤我(函数),我(函数)⽴即返回通知调⽤者以最常⽤的send和recv两个函数为例⽐如你调⽤send函数发送⼀定的Byte,在系统内部send做的⼯作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执⾏成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有⾜够的可⽤缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和⾮阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有⾜够的空间把你要发送的数据Copy过去以后才返回,⽽对于⾮阻塞的socket来说send会⽴即返回WSAEWOULDDBLOCK告诉调⽤者说:"发送操作被阻塞了!!!你想办法处理吧..."对于recv函数,同样道理,对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知⼀个结果给它它就⼀直不返回:耗费着系统资源....对于⾮阻塞模式的socket该函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头再来看看"阻塞I/O模型:⾮阻塞I/O模型:阻塞和⾮阻塞关注的是调⽤者在等待调⽤结果时的状态。

Linux网络编程socket错误码分析

Linux网络编程socket错误码分析

Linux网络编程socket错误分析socket错误码:EINTR:4阻塞的操作被取消阻塞的调用打断。

如设置了发送接收超时,就会遇到这种错误。

只能针对阻塞模式的socket。

读,写阻塞的socket时,-1返回,错误号为INTR。

另外,如果出现EINTR即errno为4,错误描述Interrupted system call,操作也应该继续。

如果recv 的返回值为0,那表明连接已经断开,接收操作也应该结束。

ETIMEOUT:1101、操作超时。

一般设置了发送接收超时,遇到网络繁忙的情况,就会遇到这种错误。

2、服务器做了读数据做了超时限制,读时发生了超时。

3、错误被描述为“connect time out”,即“连接超时”,这种情况一般发生在服务器主机崩溃。

此时客户TCP 将在一定时间内(依具体实现)持续重发数据分节,试图从服务TCP 获得一个ACK 分节。

当最终放弃尝试后(此时服务器未重新启动),内核将会向客户进程返回ETIMEDOUT 错误。

如果某个中间路由器判定该服务器主机已经不可达,则一般会响应“destination unreachable”-“目的地不可达”的ICMP消息,相应的客户进程返回的错误是EHOSTUNREACH 或ENETUNREACH。

当服务器重新启动后,由于TCP 状态丢失,之前所有的连接信息也不存在了,此时对于客户端发来请求将回应RST。

如果客户进程对检测服务器主机是否崩溃很有必要,要求即使客户进程不主动发送数据也能检测出来,那么需要使用其它技术,如配置SO_KEEPALIVE Socket 选项,或实现某些心跳函数。

EAGAIN:1、Send返回值小于要发送的数据数目,会返回EAGAIN和EINTR。

2、recv 返回值小于请求的长度时说明缓冲区已经没有可读数据,但再读不一定会触发EAGAIN,有可能返回0表示TCP连接已被关闭。

3、当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,可以做延时后再重试.4、在Linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno 代码为11(EAGAIN),表明在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。

非阻塞IO与阻塞IO区别

非阻塞IO与阻塞IO区别

⾮阻塞IO与阻塞IO区别⼀、介绍1、阻塞⽅式:1) 写进程未退出,read阻塞,等待写端的输⼊2) 写进程终⽌了或关闭了该FIFO,read⾮阻塞,为FIFO的读进程产⽣⼀个⽂件结束标志,read的返回值为0。

2、⾮阻塞⽅式:假设⼀个进程以⾮阻塞读⽅式打开⼀个FIFO.该FIFO之前已经被以写⽅式被其他进程打开,但⽆数据被写⼊,那么此时读进程需要⽴刻返回,那么应该返回什么呢?我们知道如果 read()读数据时第⼀个读到的是⽂件结束标志,那么就返回0。

如果像我们想的那样没有数据读应该返回0 ,那么这个0就具有⼆义性。

因为我们不知道是没有数据造成的返回0还是写端关闭造成的返回0.所以POSIX.1要求,对⼀个⾮阻塞的描述符如果⽆数据可读,则read返回-1,⽽且 errno被设置为 EAGAIN。

1) 如果在随后调⽤read函数之前,如果另⼀个进程已经以写⽅式打开了该FIFO,并写⼊了数据,那么正常读取数据。

2) 如果在随后调⽤read函数之前,如果另⼀个进程已经以写⽅式打开了该FIFO,但是并未写⼊数据,read调⽤会⽴刻出错返回-1,并设置errnno为EAGAIN。

3)如果在随后调⽤read函数之前,没有其他进程以写⽅式打开该FIFO,或是曾经有但是在read读时已经关闭了,那么read返回0,表⽰读到⽂件结束标志。

⼆、mkfifo介绍#include <sys/types.h>#include <sys/stat.h>int mkfifo( const char*pathname, mode_t mode);参数:pathname:FIFO的路径名+⽂件名。

mode:mode_t类型的权限描述符,同open的参数。

返回值:成功:返回0失败:如果⽂件已经存在,则会出错且返回-1。

三、操作FIFO⽂件时的特点:系统调⽤的I/O函数都可以作⽤于FIFO,如open、close、read、write等。

socket的receive方法

socket的receive方法

(原创实用版4篇)编制人员:_______________审核人员:_______________审批人员:_______________编制单位:_______________编制时间:____年___月___日序言下面是本店铺为大家精心编写的4篇《socket的receive方法》,供大家借鉴与参考。

下载后,可根据实际需要进行调整和使用,希望能够帮助到大家,谢射!(4篇)《socket的receive方法》篇1Socket 的接收方法主要包括以下几种:1. synchronous receive 方法:阻塞方法,等待客户端发送数据后才进行接收,适用于数据量较小且传输速度较慢的情况。

使用方法为:socket.receive(byte[] buffer, int length, SocketTimeout timeout);2. asynchronous receive 方法:异步方法,可以不等待客户端发送数据就进行接收,适用于数据量较大或传输速度较快的情况。

使用方法为:socket.begin_receive(byte[] buffer, int length, SocketAsyncEventHandler callback);3. overlapped receive 方法:重叠方法,可以在多个操作之间重叠执行,提高性能,但需要支持 Windows API。

使用方法为:socket.overlapped_receive(byte[] buffer, int length, SocketOverlappedEventHandler callback);其中,synchronous receive 方法和 asynchronous receive 方法都可以使用 select 或 poll 方法实现阻塞或非阻塞接收,而 overlapped receive 方法则需要在 Windows 系统上使用。

阻塞IO和非阻塞IO,同步IO和异步IO

阻塞IO和非阻塞IO,同步IO和异步IO

阻塞IO和⾮阻塞IO,同步IO和异步IO⼀、阻塞io我这个进程调⽤了⼀个功能需要磁盘io,那么我整个进程就会被阻塞住,在做完磁盘io之前我都不能动。

当内核把数据就绪之后,内核会将数据拷贝到⽤户线程,并返回结果给⽤户线程,⽤户线程才解除block状态。

⼆、⾮阻塞io我调⽤了⼀个磁盘io,但是我不⽤等他io完,我可以去进⾏别的东西,只要他io完就会通知我去读取数据;三、同步IO⾮阻塞io在进⾏磁盘io的时候,虽然不需要等磁盘io这个过程,但是当磁盘io完成之后,他还需要把数据从内核空间移动到⽤户空间,这个时间也是阻塞的,这就是同步.四、异步IO我调⽤了磁盘io,我会创建⼀个新的线程去处理这整个io,我只需要调⽤read,随后发⽣的什么时候,我创建了⼀个新的线程去帮我处理,等他处理完,我再回来接收已经准备好的数据.完全不⽤花费时间在等待,可以做别的事情。

这⾥粗略地举个栗⼦,⽐如你要玩英雄联盟。

阻塞IO就是,游戏登录进去之后你要先匹配队友(磁盘IO),匹配完队友后,你还要⾃⼰玩排位(把数据从内核复制到⽤户空间)。

⽽⾮阻塞IO就是你下课回到宿舍,让你室友先帮你排队(磁盘IO),你先去⼲点别的事情,⽐如上厕所,等你⼲完别的时候回来,发现游戏已经进⼊了,你可以直接选⽤英雄开始打了。

同步IO就是虽然你让你室友帮你匹配了队友,但是你还是得⾃⼰打游戏才能上分(把数据从内核复制到⽤户空间),这个时间段你也⽆法做别的事情。

⽽异步IO就是,你请⼀个代练,你只需要告诉他,我要上王者100点,那么他就会把所有事情都做得明明⽩⽩(磁盘io并且把数据从内核复制到⽤户空间),你拿到⼿的时候就已经是⼀个段位为王者的号了。

五、Socket1.⽂件标识符fd每⼀个程序都有⼀个基础流,⽂件标识符0、1、2,输⼊流、输出流、错误流。

如果这个进程监听了⼀个端⼝,那就会多⼀个3,是socket2.当服务端监听了某个端⼝只有监听了端⼝才会有3socket3.当客户端与服务端链接时服务端的⽂件标识符会变成4个,3是服务端监听了⼀个端⼝,就会创建这个socket,当客户端跟服务端链接的时候,就会多了⼀个socket,表⽰已经跟客户端建⽴了链接4.看源码nc localhost 8080 (建⽴连接的命令⾏)read() 读⽂件标识符accept() 当客户端想要跟你连接时,接收到⼀个fd,然后建⽴链接六、IO的内存模型时间⽚:当时间到了,调⽤进程调度,回调collBack,切换另⼀个进程所以进程越多,对CPU的性能压⼒越⼤切换的⽅式是利⽤晶振的规律震动,这⾥可以扩展到Redis的知识点,Redis是单线程, 采⽤单线程,避免了不必要的上下⽂切换.七、IO的发展1.阻塞模型如果fd4在read()阻塞了,此时如果有另外⼀个fd5,即使建⽴了连接,但是因为scoket在fd4阻塞住了.[缺点]:会发⽣阻塞2.抛出线程,阻塞在线程但是仍然有缺点,因为线程多了起来,线程的切换也需要消耗很⼤性能3.⾮阻塞I/O(NIO)只需要设置⼀下read,调⽤了read函数之后,不需要等待磁盘io,它会先返回⼀个结果,这样⼦不会阻塞,也不需要抛出线程.减少了线程的切换.但是仍然还有缺点:因为即使进程不需要等到磁盘io,但是磁盘读取完数据之后,我们还是需要把数据从内核空间复制到⽤户空间,这样⼦也会消耗性能.(因为read是对系统调⽤的⽅法)并且,如果有⼀万个客户端发来信息,但是我们每次去调⽤read的时候,是需要遍历1万个fd,才能发现哪个fd有事件(event),这是⼀个时间复杂度特别⾼的事情.⽽且⼀万个fd⾥⾯可能只有⼏个fd有事件,这就造成了浪费.4.多路复⽤在内核上进⾏优化,因为我们之前每次都是要把fd传到内核空间,然后再调⽤read判断它有没有事件,所以我们包装了⼀个select(),假设有⼀万个fd,我们⼀次性把fd传到内核⾥⾯,内核把这⼀万个fd遍历⼀遍,然后再把有事件的fd返回出去.在这⾥read 只需要调⽤有事件的fd次数,⽐如只有5个fd有事件发⽣,那么read只需要调⽤5次.但是仍然还有缺点,因为每⼀次调⽤read,都要在内核空间⾥⾯循环⼀万个fd,查看有没有事件(select),⽽且每次都要把fds这个集合复制到内核空间,这样⼦也会浪费资源.5.epoll所以我们在内核空间划出⼀块空间,把整个fds集合放在内核空间⾥⾯,这样⼦每此调⽤read的时候就不⽤涉及到内核态和⽤户态的切换了.客户端数据到达就会产⽣中断,然后查找⼀下这个终端号是那个fd的,然后返回给read就可以了⼋、NIO1.特点①、是基于流的形式,但⼜采⽤了缓冲区和管道来处理数据的;②、NIO是双向的;③、NIO是使⽤多路复⽤的IO模型.2.管道是什么?通道是对原 I/O 包中的流的模拟。

linux下recvsend阻塞非阻塞区别和用法

linux下recvsend阻塞非阻塞区别和用法

linux下recv、send阻塞、非阻塞区别和用法非阻塞IO 和阻塞IO:在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:基本概念:阻塞IO::socket 的阻塞模式意味着必须要做完IO 操作(包括错误)才会返回。

非阻塞IO::非阻塞模式下无论操作是否完成都会立刻返回,需要通过其他方式来判断具体操作是否成功。

(对于connect,accpet操作,通过select判断,对于recv,recvfrom,send,sendto 通过返回值+错误码来判断)IO模式设置:SOCKET对于一个socket 是阻塞模式还是非阻塞模式的处理方法::方法::用fcntl 设置;用F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;同时,recv,send 时使用非阻塞的方式读取和发送消息,即flags设置为MSG_DONTWAIT实现fcntl 函数可以将一个socket 句柄设置成非阻塞模式:flags = fcntl(sockfd, F_GETFL, 0);//获取文件的flags值。

fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //设置成非阻塞模式;flags = fcntl(sockfd,F_GETFL,0);fcntl(sockfd,F_SETFL,flags&amp;~O_NONBLOCK); //设置成阻塞模式;并在接收和发送数据时:将recv, send 函数的最后有一个flag 参数设置成MSG_DONTWAITrecv(sockfd, buff, buff_size,MSG_DONTWAIT); //非阻塞模式的消息发送send(scokfd, buff, buff_size, MSG_DONTWAIT); //非阻塞模式的消息接受普通文件对于文件的阻塞模式还是非阻塞模式::方法1、open时,使用O_NONBLOCK;方法2、fcntl设置,使用F_SETFL,flags|O_NONBLOCK;消息队列对于消息队列消息的发送与接受:://非阻塞msgsnd(sockfd,msgbuf,msgsize(不包含类型大小),IPC_NOWAIT)//阻塞msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);读阻塞与非阻塞读的区别: //阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回.读(read/recv/msgrcv):读的本质来说其实不能是读,在实际中, 具体的接收数据不是由这些调用来进行,是由于系统底层自动完成的。

c语言 tcpip 阻塞非阻塞用法

c语言 tcpip 阻塞非阻塞用法

在C语言中,TCP/IP套接字可以以阻塞(blocking)或非阻塞(non-blocking)模式运行。

这两种模式决定了套接字在进行网络通信时的行为。

1. 阻塞模式:在阻塞模式下,当套接字执行输入/输出操作时,程序会一直等待,直到操作完成或出现错误。

阻塞模式是默认的套接字行为。

例如,在阻塞模式下,如果调用recv()函数接收数据,但没有数据可供接收,程序将一直等待,直到有数据可用为止。

2. 非阻塞模式:在非阻塞模式下,当套接字执行输入/输出操作时,程序不会等待操作完成,而是立即返回。

如果操作无法立即完成,则返回一个错误代码(例如EWOULDBLOCK或EAGAIN),表示操作当前不可用。

程序可以通过轮询套接字状态或使用回调函数等方式来检查操作是否完成。

非阻塞模式可以让程序在等待网络操作期间能够处理其他任务,提高了程序的响应性能。

下面是一个简单的示例,演示了如何设置和使用阻塞和非阻塞套接字:```c#include <stdio.h>#include <sys/socket.h>#include <fcntl.h>int main() {int sockfd;// 创建套接字sockfd = socket(AF_INET, SOCK_STREAM, 0);// 设置为非阻塞模式int flags = fcntl(sockfd, F_GETFL, 0);fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);// 在非阻塞模式下进行操作int ret = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (ret == -1) {// 连接操作当前不可用if (errno == EINPROGRESS) {// 连接正在进行中,可以继续处理其他任务} else {// 发生错误perror("connect");return 1;}}// 恢复为阻塞模式fcntl(sockfd, F_SETFL, flags);// 在阻塞模式下进行操作ret = send(sockfd, buffer, sizeof(buffer), 0);if (ret == -1) {// 发生错误perror("send");return 1;}close(sockfd);return 0;}```在上面的示例中,首先创建了一个套接字,并将其设置为非阻塞模式。

socket阻塞和非阻塞的用法

socket阻塞和非阻塞的用法

在Python中,socket默认是阻塞的。

对于阻塞的socket,当调用recv()函数时,如果数据没有准备好,那么系统就会等待数据。

如果数据准备好后,系统会将数据从系统内核缓冲区复制到用户空间,然后该函数返回。

对于非阻塞的socket,当调用recv()函数时,即使数据没有准备好,也不会阻塞,而是直接返回。

以下是socket阻塞和非阻塞的用法示例:1. socket阻塞模式:```pythonimport socket# 创建一个socket对象s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 连接服务器s.connect()# 接收数据,如果数据没有准备好,就会一直等待data = s.recv(1024)2. socket非阻塞模式:```pythonimport socketimport select# 创建一个socket对象s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置socket为非阻塞模式s.setblocking(False)# 连接服务器s.connect()# 创建select对象,将socket对象添加进去r, w, e = select.select([s], [], [])# 接收数据,如果数据没有准备好,就会直接返回None data = s.recv(1024) if r else None注意:在非阻塞模式下,如果没有数据可读,recv()函数会立即返回None。

因此,在使用非阻塞模式时,需要不断循环检查是否有数据可读,直到接收到所有需要的数据。

socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

socket使⽤TCP协议时,send、recv函数解析以及TCP连接关闭的问题Tcp协议本⾝是可靠的,并不等于应⽤程序⽤tcp发送数据就⼀定是可靠的.不管是否阻塞,send发送的⼤⼩,并不代表对端recv到多少的数据.在阻塞模式下, send函数的过程是将应⽤程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存⼤⼩⽐请求发送的⼤⼩要⼤,那么send函数⽴即返回,同时向⽹络中发送数据;否则,send向⽹络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不⼀定要等待应⽤程序调⽤recv);在⾮阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区⽽已,如果缓存区可⽤空间不够,则尽能⼒的拷贝,返回成功拷贝的⼤⼩;如缓存区可⽤空间为0,则返回-1,同时设置errno为EAGAIN.linux下可⽤sysctl -a | grep net.ipv4.tcp_wmem查看系统默认的发送缓存⼤⼩:net.ipv4.tcp_wmem = 4096 16384 81920这有三个值,第⼀个值是socket的发送缓存区分配的最少字节数,第⼆个值是默认值(该值会被net.core.wmem_default覆盖),缓存区在系统负载不重的情况下可以增长到这个值,第三个值是发送缓存区空间的最⼤字节数(该值会被net.core.wmem_max覆盖).根据实际测试,如果⼿⼯更改了net.ipv4.tcp_wmem的值,则会按更改的值来运⾏,否则在默认情况下,协议栈通常是按net.core.wmem_default和net.core.wmem_max的值来分配内存的.应⽤程序应该根据应⽤的特性在程序中更改发送缓存⼤⼩:socklen_t sendbuflen = 0;socklen_t len = sizeof(sendbuflen);getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);printf("default,sendbuf:%d/n", sendbuflen);sendbuflen = 10240;setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len);getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);printf("now,sendbuf:%d/n", sendbuflen);需要注意的是,虽然将发送缓存设置成了10k,但实际上,协议栈会将其扩⼤1倍,设为20k.-------------------实例分析---------------在实际应⽤中,如果发送端是⾮阻塞发送,由于⽹络的阻塞或者接收端处理过慢,通常出现的情况是,发送应⽤程序看起来发送了10k的数据,但是只发送了2k到对端缓存中,还有8k在本机缓存中(未发送或者未得到接收端的确认).那么此时,接收应⽤程序能够收到的数据为2k.假如接收应⽤程序调⽤recv函数获取了1k的数据在处理,在这个瞬间,发⽣了以下情况之⼀,双⽅表现为:A. 发送应⽤程序认为send完了10k数据,关闭了socket:发送主机作为tcp的主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对⽅的ack),并且,发送缓存中的8k数据并不清除,依然会发送给对端.如果接收应⽤程序依然在recv,那么它会收到余下的8k数据(这个前题是,接收端会在发送端FIN_WAIT1状态超时前收到余下的8k数据.), 然后得到⼀个对端socket被关闭的消息(recv返回0).这时,应该进⾏关闭.B. 发送应⽤程序再次调⽤send发送8k的数据:假如发送缓存的空间为20k,那么发送缓存可⽤空间为20-8=12k,⼤于请求发送的8k,所以send函数将数据做拷贝后,并⽴即返回8192;假如发送缓存的空间为12k,那么此时发送缓存可⽤空间还有12-8=4k,send()会返回4096,应⽤程序发现返回的值⼩于请求发送的⼤⼩值后,可以认为缓存区已满,这时必须阻塞(或通过select等待下⼀次socket可写的信号),如果应⽤程序不理会,⽴即再次调⽤send,那么会得到-1的值, 在linux下表现为errno=EAGAIN.C. 接收应⽤程序在处理完1k数据后,关闭了socket:接收主机作为主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对⽅的ack).然后,发送应⽤程序会收到socket可读的信号(通常是 select调⽤返回socket可读),但在读取时会发现recv函数返回0,这时应该调⽤close函数来关闭socket(发送给对⽅ack);如果发送应⽤程序没有处理这个可读的信号,⽽是在send,那么这要分两种情况来考虑,假如是在发送端收到RST标志之后调⽤send,send将返回-1,同时errno设为ECONNRESET表⽰对端⽹络已断开,但是,也有说法是进程会收到SIGPIPE信号,该信号的默认响应动作是退出进程,如果忽略该信号,那么send是返回-1,errno为EPIPE(未证实);如果是在发送端收到RST标志之前,则send像往常⼀样⼯作;以上说的是⾮阻塞的send情况,假如send是阻塞调⽤,并且正好处于阻塞时(例如⼀次性发送⼀个巨⼤的buf,超出了发送缓存),对端socket关闭,那么send将返回成功发送的字节数,如果再次调⽤send,那么会同上⼀样.D. 交换机或路由器的⽹络断开:接收应⽤程序在处理完已收到的1k数据后,会继续从缓存区读取余下的1k数据,然后就表现为⽆数据可读的现象,这种情况需要应⽤程序来处理超时.⼀般做法是设定⼀个select等待的最⼤时间,如果超出这个时间依然没有数据可读,则认为socket已不可⽤.发送应⽤程序会不断的将余下的数据发送到⽹络上,但始终得不到确认,所以缓存区的可⽤空间持续为0,这种情况也需要应⽤程序来处理.如果不由应⽤程序来处理这种情况超时的情况,也可以通过tcp协议本⾝来处理,具体可以查看sysctl项中的:net.ipv4.tcp_keepalive_intvlnet.ipv4.tcp_keepalive_probesnet.ipv4.tcp_keepalive_time////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////thread-1446913-1-1.html发送成功只是表⽰发到了内核socket缓冲区此时如果close,正常情况会进⼊TIME_WAIT状态,在此状态,对端可以继续接收数据但是如果发送⽅的接收缓冲区还有未读数据,就会⾛异常close的途径,置RST,⽴刻结束连接,没有TIME_WAIT状态。

linux下串口的阻塞和非阻塞操作

linux下串口的阻塞和非阻塞操作

linux下串口的阻塞和非阻塞操作linux下串口的阻塞和非阻塞操作[cpp]有两个可以进行控制串口阻塞性(同时控制read和write):一个是在打开串口的时候,open函数是否带O_NDELAY;第二个是可以在打开串口之后通过fcntl()函数进行控制。

阻塞的定义:对于read,block指当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,移植到串口输入缓冲区中有数据可读取,read读到了需要的字节数之后,返回值为读到的字节数;对于write,block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将阻塞,一直到串口输出缓冲区中剩下的空间大于等于将要写入的字节数,执行写入操作,返回写入的字节数。

非阻塞的定义:对于read,no block指当串口输入缓冲区没有数据的时候,read函数立即返回,返回值为0。

对于write,no block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将进行写操作,写入当前串口输出缓冲区剩下空间允许的字节数,然后返回写入的字节数。

[cpp]static int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop) { struct termios newtio;struct termios oldtio;if(tcgetattr(fd,&amp;oldtio) != 0){ perror("SetupSerial 1"); return -1; }bzero(&amp;newtio,sizeof(newtio)); newtio.c_cflag |= CLOCAL |CREAD; newtio.c_cflag &amp;=~CSIZE; /***********数据位选择****************/ switch(nBits){ case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; }/***********校验位选择****************/switch(nEvent) { case 'O':newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); break; case 'E': newtio.c_iflag |= (INPCK |ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag &amp;= ~PARODD; break;case 'N': newtio.c_cflag &amp;= ~PARENB; break; } /***********波特率选择****************/ switch(nSpeed){ case 2400:cfsetispeed(&amp;newtio,B2400);cfsetospeed(&amp;newtio,B2400); break; case 4800: cfsetispeed(&amp;newtio,B4800); cfsetospeed(&amp;newtio,B4800); break; case 9600: cfsetispeed(&amp;newtio,B9600); cfsetospeed(&amp;newtio,B9600); break; case 57600: cfsetispeed(&amp;newtio,B57600); cfsetospeed(&amp;newtio,B57600); break; case 115200:cfsetispeed(&amp;newtio,B115200);cfsetospeed(&amp;newtio,B115200); break; case 460800:cfsetispeed(&amp;newtio,B460800);cfsetospeed(&amp;newtio,B460800); break; default: cfsetispeed(&amp;newtio,B9600); cfsetospeed(&amp;newtio,B9600);break; } /***********停止位选择****************/ if(nStop ==1){ newtio.c_cflag &amp;=~CSTOPB; } else if(nStop==2){ newtio.c_cflag |= CSTOPB; } newtio.c_cc[VTIME] = 1; newtio.c_cc[VMIN] = FRAME_MAXSIZE; //阻塞条件下有效tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&amp;newtio)) != 0){ perror("com set error"); return -1; } printf("set done!\n"); return 0; }[cpp] view plaincopy?static int open_port(int fd,int comport) { /***********打开串口1****************/if(comport == 1) { fd =open("/dev/ttyAT1",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return -1; } } /***********打开串口2****************/ else if(comport == 2) { fd =open("/dev/ttyAT2",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return-1; } } /***********打开串口3****************/ else if(comport == 3){ fd =open("/dev/ttyAT3",O_RDWR|O_NOCTTY|O_NDELAY);if(fd == -1){ perror("Can't Open Serial Port"); return-1; } } if(comport == 1) { if(fcntl(fd,F_SETFL,FNDELAY) &lt; 0)//非阻塞,覆盖前面open的属性{ printf("fcntl failed\n"); } else{ printf("fcntl=%d\n",fcntl(fd,F_SETFL,FN DELAY)); } } else{ if(fcntl(fd,F_SETFL,0) &lt; 0){ //阻塞,即使前面在open串口设备时设置的是非阻塞的,这里设为阻塞后,以此为准printf("fcntl failed\n"); } else{ printf("fcntl=%d\n",fcntl(fd,F_SETFL,0));} } if(isatty(STDIN_FILENO) == 0){ printf("standard input is not a terminal device\n"); }else{ printf("isattysucess!\n"); } printf("fd-open=%d\n",fd); return fd; }所以,linux的串口的阻塞性通过fcntl()函数进行设置即可。

阻塞线程和非阻塞线程

阻塞线程和非阻塞线程

阻塞线程和非阻塞线程阻塞线程和非阻塞线程是计算机领域中常用的概念,它们与多线程编程密切相关。

本文将详细介绍阻塞线程和非阻塞线程的概念、原理和应用。

一、阻塞线程在多线程编程中,阻塞线程是指当一个线程在执行过程中,因为某种原因无法继续执行,从而暂停线程的执行。

阻塞线程的主要原因包括等待用户输入、等待磁盘IO、等待网络IO等。

当线程被阻塞时,它会进入一个等待状态,直到满足某个条件后才能继续执行。

阻塞线程的特点是在等待某个操作完成期间,线程处于休眠状态,不会占用CPU资源。

这样可以提高系统的资源利用率,但同时也会造成程序的执行效率降低。

因此,在设计多线程程序时需要合理地使用阻塞线程,避免过多的阻塞操作,以提高程序的性能。

二、非阻塞线程与阻塞线程相对应的是非阻塞线程。

非阻塞线程是指在执行过程中,线程不会因为某个操作的阻塞而暂停执行,它会继续执行其他任务,而不是等待该操作的完成。

当一个非阻塞线程需要等待某个操作完成时,它会通过轮询或回调的方式来获知操作的结果,从而继续执行后续的任务。

非阻塞线程的特点是能够充分利用CPU资源,提高程序的执行效率。

但同时,非阻塞线程也会增加系统的负担,因为它需要不断地轮询或回调来获取操作结果,这可能会消耗大量的CPU资源。

因此,在使用非阻塞线程时需要权衡系统的负载和性能要求,选择合适的方式来处理。

1. 阻塞线程的应用:(1) 网络编程:在网络编程中,阻塞线程常用于接收和发送数据,等待网络IO的完成。

(2) 用户交互:在图形界面编程中,阻塞线程常用于等待用户输入,如等待按钮点击、等待输入框输入等。

(3) 文件操作:在文件操作中,阻塞线程常用于等待磁盘IO的完成,如读取文件、写入文件等。

2. 非阻塞线程的应用:(1) 服务器编程:在服务器编程中,非阻塞线程常用于处理并发请求,提高服务器的处理能力。

(2) GUI编程:在图形界面编程中,非阻塞线程常用于更新UI 界面,保持界面的流畅和响应性。

C#阻塞模式和非阻塞模式

C#阻塞模式和非阻塞模式

C#阻塞模式和⾮阻塞模式阻塞模式 Windows套接字在阻塞和⾮阻塞两种模式下执⾏I/O操作。

在阻塞模式下,在I/O操作完成前,执⾏的操作函数⼀直等候⽽不会⽴即返回,该函数所在的线程会阻塞在这⾥。

相反,在⾮阻塞模式下,套接字函数会⽴即返回,⽽不管I/O是否完成,该函数所在的线程会继续运⾏。

在阻塞模式的套接字上,调⽤任何⼀个Windows Sockets API都会耗费不确定的等待时间。

图所⽰,在调⽤recv()函数时,发⽣在内核中等待数据和复制数据的过程。

当调⽤recv()函数时,系统⾸先查是否有准备好的数据。

如果数据没有准备好,那么系统就处于等待状态。

当数据准备好后,将数据从系统缓冲区复制到⽤户空间,然后该函数返回。

在套接应⽤程序中,当调⽤recv()函数时,未必⽤户空间就已经存在数据,那么此时recv()函数就会处于等待状态。

Windows套接字程序使⽤“⽣产者-消费者”模式来解决上述问题。

在程序中,“⽣产者”读⼊数据,“消费者”根据需求对读⼊数据进⾏处理。

通常“⽣产者”和“消费者”存在于两个线程中,当“⽣产者”完成读⼊数据时,使⽤线程同步机制,例如设置⼀个事件通知“消费者”,“消费者”接收到这个事件后对读⼊的数据进⾏处理。

当使⽤socket()函数和WSASocket()函数创建套接字时,默认的套接字都是阻塞的。

这意味着当调⽤Windows Sockets API不能⽴即完成时,线程处于等待状态,直到操作完成。

并不是所有Windows Sockets API以阻塞套接字为参数调⽤都会发⽣阻塞。

例如,以阻塞模式的套接字为参数调⽤bind()、listen()函数时,函数会⽴即返回。

将可能阻塞套接字的Windows Sockets API调⽤分为以下四种:1.输⼊操作recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。

以阻塞套接字为参数调⽤该函数接收数据。

Socket详解之阻塞非阻塞

Socket详解之阻塞非阻塞

这里不打算系统地介绍socket或者WinSock的知识。

首先介绍WinSock API函数,讲解阻塞/非阻塞的概念;然后介绍socket的使用。

APISocket接口是网络编程(通常是TCP/IP协议,也可以是其他协议)的API。

最早的Socket 接口是Berkeley接口,在Unix小小操作系统中实现。

WinSock也是一个基于Socket模型的API,在Microsoft Windows操作系统类中使用。

它在Berkeley接口函数的基础之上,还增加了基于消息驱动机制的Windows扩展函数。

只支持TCP/IP网络,增加了对更多协议的支持。

这里,讨论TCP/IP网络上的API。

Socket接口包括三类函数:第一类是WinSock API包含的Berkeley socket函数。

这类函数分两部分。

第一部分是用于网络I/O的函数,如accept、Closesocket、connect、recv、recvfrom、Select、Send、Sendto。

另一部分是不涉及网络I/O、在本地端完成的函数,如bind、getpeername、getsockname、getsocketopt、htonl、htons、inet_addr、inet_nton、ioctlsocket、listen、ntohl、ntohs、setsocketopt、shutdow、socket等第二类是检索有关域名、通信服务和协议等Internet信息的数据库函数,如gethostbyaddr、gethostbyname、gethostname、getprotolbyname、getprotolbynumber、getserverbyname、getservbyport。

第三类是Berkekley socket例程的Windows专用的扩展函数,如gethostbyname对应的WSAAsynGetHostByName(其他数据库函数除了gethostname都有异步版本),select对应的WSAAsynSelect,判断是否阻塞的函数WSAIsBlocking,得到上一次Windsock API错误信息的WSAGetLastError,等等。

socket期末考试试题

socket期末考试试题

socket期末考试试题Socket期末考试试题一、简答题1. 什么是Socket?Socket是一种在计算机网络中实现通信的一种机制,它允许不同计算机之间通过网络传输数据。

通过Socket,可以实现客户端和服务器之间的双向通信。

2. Socket通信的基本流程是什么?Socket通信的基本流程包括以下几个步骤:- 服务器创建一个Socket,并绑定到指定的IP地址和端口号上;- 服务器开始监听客户端的连接请求;- 客户端创建一个Socket,并连接到服务器指定的IP地址和端口号上;- 客户端和服务器之间开始进行通信,可以通过Socket发送和接收数据。

3. TCP和UDP的区别是什么?TCP(Transmission Control Protocol)是一种可靠的、面向连接的协议,通过建立连接、数据传输和断开连接来实现通信。

TCP提供数据的可靠性和顺序性,但在传输效率上相对较低。

UDP(User Datagram Protocol)是一种不可靠的、无连接的协议,通过数据报形式进行通信。

UDP不保证数据的可靠性和顺序性,但在传输效率上相对较高。

4. Socket的阻塞和非阻塞模式有什么区别?阻塞模式下,Socket的操作会一直等待直到完成或发生错误,期间线程会被阻塞,无法执行其他任务。

非阻塞模式下,Socket的操作会立即返回,无论是否完成,线程可以继续执行其他任务。

5. 什么是多路复用?多路复用是指通过一种机制,使得一个进程能同时监听多个文件描述符,一旦某个文件描述符就绪(可读或可写),就能够立即处理该事件。

二、编程题请编写一个基于TCP的多人聊天室程序,要求实现以下功能:- 服务器可以同时接收多个客户端的连接请求,并将客户端的消息广播给其他客户端;- 客户端可以发送消息给服务器,并接收服务器转发的其他客户端的消息;- 客户端可以断开连接。

提示:1. 在服务器端,可以使用一个线程来监听客户端的连接请求,每当有新的连接请求到来时,创建一个新的线程来处理该连接;2. 在服务器端,可以使用一个线程来接收客户端的消息,并将消息广播给其他客户端;3. 在客户端,可以使用一个线程来接收服务器转发的其他客户端的消息;4. 在服务器端和客户端,可以使用Socket来实现网络通信。

非阻塞通信的基本概念-概述说明以及解释

非阻塞通信的基本概念-概述说明以及解释

非阻塞通信的基本概念-概述说明以及解释1.引言1.1 概述非阻塞通信是一种在计算机网络中常用的通信机制,它允许发送方在等待接收方响应时能够同时执行其他任务,从而提高系统的并发性和性能。

相对于阻塞通信,非阻塞通信能够更好地满足实时性要求高、资源利用率要求高的应用需求。

在阻塞通信中,发送方在发送消息后需要等待接收方的响应,这个等待过程会导致发送方的线程被阻塞,无法执行其他任务。

而非阻塞通信则通过使用异步通信模式,在发送消息后即使没有收到接收方的响应,发送方的线程也可以继续执行其他任务。

这种机制使得系统能够并发执行多个任务,提高整体的处理能力。

非阻塞通信的优势不仅表现在提高系统的并发性和性能上,还能够降低通信的延迟。

由于发送方无需一直等待接收方的响应,可以及时地处理其他任务,从而减少了消息传输的等待时间。

这对于实时性要求高的应用场景非常重要,例如在线游戏、金融交易等领域。

非阻塞通信在各个领域有着广泛的应用。

在计算机网络中,非阻塞通信被广泛应用于高性能计算、数据中心网络等场景中。

在分布式系统中,非阻塞通信被用于实现异步消息传递、事件驱动等机制。

在操作系统中,非阻塞通信被用于实现高效的进程间通信和线程间通信。

本文将深入探讨非阻塞通信的定义、原理、优势和应用,并对非阻塞通信的未来发展进行展望。

通过对非阻塞通信的基本概念的研究,我们可以更好地理解和应用非阻塞通信,在实际应用中提高系统的并发性和性能,满足各种实时性要求高的应用场景的需求。

1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分旨在介绍整篇文章的组织结构和各个章节的内容概要。

通过清晰地展示文章的框架,读者可以更好地理解文章的结构和逻辑关系。

本篇文章的结构主要分为引言、正文和结论三个部分。

引言部分(Introduction)将在文章开头引起读者的兴趣,概述非阻塞通信的基本概念和重要性。

该部分还将介绍文章的结构和目的。

正文部分(Main Body)是本文的核心部分,用于详细解释非阻塞通信的定义和原理,以及非阻塞通信的优势和应用。

阻塞队列与非阻塞队列

阻塞队列与非阻塞队列

阻塞队列与⾮阻塞队列阻塞队列阻塞队列(BlockingQueue)是⼀个⽀持两个附加操作的队列。

这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为⾮空。

当队列满时,存储元素的线程会等待队列可⽤。

阻塞队列常⽤于⽣产者和消费者的场景,⽣产者是往队列⾥添加元素的线程,消费者是从队列⾥拿元素的线程。

阻塞队列就是⽣产者存放元素的容器,⽽消费者也只从容器⾥拿元素。

⽅法\处理⽅式抛出异常返回特殊值⼀直阻塞超时退出插⼊⽅法add(e)offer(e)put(e)offer(e,time,unit)移除⽅法remove()poll()take()poll(time,unit)检查⽅法element()peek()不可⽤不可⽤抛出异常:是指当阻塞队列满时候,再往队列⾥插⼊元素,会抛出IllegalStateException(“Queue full”)异常。

当队列为空时,从队列⾥获取元素时会抛出NoSuchElementException异常。

返回特殊值:插⼊⽅法会返回是否成功,成功则返回true。

移除⽅法,则是从队列⾥拿出⼀个元素,如果没有则返回null⼀直阻塞:当阻塞队列满时,如果⽣产者线程往队列⾥put元素,队列会⼀直阻塞⽣产者线程,直到拿到数据,或者响应中断退出。

当队列空时,消费者线程试图从队列⾥take元素,队列也会阻塞消费者线程,直到队列可⽤。

超时退出:当阻塞队列满时,队列会阻塞⽣产者线程⼀段时间,如果超过⼀定的时间,⽣产者线程就会退出。

JDK7提供了7个阻塞队列。

分别是ArrayBlockingQueue :⼀个由数组结构组成的有界阻塞队列。

LinkedBlockingQueue :⼀个由链表结构组成的有界阻塞队列。

PriorityBlockingQueue :⼀个⽀持优先级排序的⽆界阻塞队列。

DelayQueue:⼀个使⽤优先级队列实现的⽆界阻塞队列。

SynchronousQueue:⼀个不存储元素的阻塞队列。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
立即返回。
关于立即返回大家都不会有异议。还是拿阻塞send的那个例子来看,当缓冲区只有192字节,但是却需要发送2000字节时,此时调用立即返回,并得到返回值为192。从中可以看到,非阻塞send仅仅是尽自己的能力向缓冲区拷贝尽可能多的数据,因此在非阻塞下send才有可能返回比你参数中的发送长度小的值。
首先socket在默认情况下是阻塞状态的(未指异步操作以及其它一些特殊用途下,直接默认为非阻塞),这就使得发送以及接收操作处于阻塞的状态,即调用不会立即返回,而是进入睡眠等待操作完成。下面把讨论点分为发送以及接收。
一.发送选用send(这里特指TCP)以及sendto(这里特指UDP)来描述
首先需要说明的是,不管阻塞还是非阻塞,在发送时都会将数据从应用缓冲区拷贝到内核缓冲区(SO_RCVBUF选项声明,除非缓冲区大小为0)。我在网络上看到某些人说,阻塞就是将数据真正发送给对方,并且阻塞是发生在需要把前面的所有数据全部发送出去,然后再发送本次的,而非阻塞则是拷贝到发送缓冲区。我不得不说,上面的这种说法是错误的。
从上面的过程不难看出,阻塞的send操作返回的发送大小,必然是你参数中的发送长度的大小。
在阻塞模式下的sendto操作不会阻塞。
关于这一点的原因在于:UDP并没有真正的发送缓冲区,它所做的只是将应用缓冲区拷贝给下层协议栈,在此过程中加上UDP头,IP头,所以实际不存在阻塞。
在阻塞模式下send操作将会等待所有数据均被拷贝到发送缓冲区后才会返回。
如果当前发送缓冲总大小为8192,已经拷贝到缓冲的数据为8000,那剩余的大小为192,现在需要发送2000字节数据,那阻塞发送就会等待缓冲区足够把所有2000字节数据拷贝进去,如第一次拷贝进192字节,当缓冲区成功发送出1808字节后,再把应用缓冲区剩余的1808字节拷贝到内核缓冲,而后send操作返回成功发送字节数。
如果缓冲区没有任何空间时呢?这时肯定也是立即返回,但是你会得到WSAEWOULDBLOCK/E WOULDBLOCK 的错误,此时表示你无法拷贝任何数据到缓冲区,你最好休息一下再尝试发送。
在非阻塞模式下sendto操作 不会阻塞(与阻塞一致,不作说明)。
二.接收选用recv(这里特指TCP)以及recvfrom(这里特指UDP)来描述
在阻塞模式下recv,recvfrom操作将会阻塞 到缓冲区里有至少一个字节(TCP)或者一个完整UDP数据报才返回。
在没有数据到来时,对它们的调用都将处于睡眠状态,不会返回。
在非阻塞模式下recv,recvfrom操作将会立即返回。
如果缓冲区 有任何一个字节数据(TCP)或者一个完整UDP数据报,它们将会返回接收到的数据大小。而如果没有任何数据则返回错误 WSAEWOULDBLOCK/E WOULDBLOCK。
相关文档
最新文档