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

合集下载

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 系统上使用。

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下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):读的本质来说其实不能是读,在实际中, 具体的接收数据不是由这些调用来进行,是由于系统底层自动完成的。

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。

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

BIO,NIO,AIO,Netty面试题 35道

BIO,NIO,AIO,Netty面试题 35道

BIO、NIO、AIO、Netty1. 什么是IOJava中I/O是以流为基础进行数据的输入输出的,所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。

简单来说就是java通过io流方式和外部设备进行交互。

在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据传输流,字符串流,对象流等等等。

比如程序从服务器上下载图片,就是通过流的方式从网络上以流的方式到程序中,在到硬盘中2. 在了解不同的IO之前先了解:同步与异步,阻塞与非阻塞的区别同步,一个任务的完成之前不能做其他操作,必须等待(等于在打电话)异步,一个任务的完成之前,可以进行其他操作(等于在聊QQ)阻塞,是相对于CPU来说的,挂起当前线程,不能做其他操作只能等待非阻塞,,无须挂起当前线程,可以去执行其他操作3. 什么是BIO10. 五种IO模型注意:我这里的用户空间就是应用程序空间1.阻塞BIO(blocking I/O)A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候不做其他的事情,十分专心。

只有鱼上钩的时,才结束掉等的动作,把鱼钓上来。

在内核将数据准备好之前,系统调用会一直等待所有的套接字,默认的是阻塞方式。

2.非阻塞NIO(noblocking I/O)B也在河边钓鱼,但是B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中,B也在做其他的事情(一会看看书,一会读读报纸,一会又去看其他人的钓鱼等),但B在做这些事情的时候,每隔一个固定的时间检查鱼是否上钩。

一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。

B在检查鱼竿是否有鱼,是一个轮询的过程。

3.异步AIO(asynchronous I/O)C也想钓鱼,但C有事情,于是他雇来了D、E、F,让他们帮他等待鱼上钩,一旦有鱼上钩,就打电话给C,C就会将鱼钓上去。

当应用程序请求数据时,内核一方面去取数据报内容返回,另一方面将程序控制权还给应用进程,应用进程继续处理其他事情,是一种非阻塞的状态。

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()函数进行设置即可。

socket的面试题

socket的面试题

socket的面试题一、Socket基础知识Socket是什么?Socket(套接字)是计算机网络中应用层与传输层之间的一组接口,用于实现网络上的不同计算机之间的通信。

通过Socket,应用程序可以通过网络发出请求并接受响应,实现数据的传输和交换。

Socket通信的基本原理是什么?Socket通信基于客户端-服务器模型。

客户端应用程序首先创建一个Socket,然后连接到服务器上的指定端口。

在建立连接之后,客户端可以通过Socket发送请求到服务器,并接收服务器响应的数据。

二、Socket面试题1. TCP和UDP的区别是什么?TCP(传输控制协议)和UDP(用户数据报协议)都是在传输层提供可靠数据传输的协议,但它们在工作方式和特点上有一些不同。

主要区别如下:- 连接性:TCP是面向连接的协议,通过建立连接和断开连接来实现可靠的数据传输;UDP是无连接的协议,不需要建立连接就可以直接发送数据包。

- 数据传输方式:TCP提供可靠的、字节流形式的数据传输;UDP以数据报形式传输,每个数据包都是独立的单位。

- 可靠性:TCP可靠性较高,通过确认、重传和拥塞控制等机制以确保数据完整性;UDP没有确认、重传和拥塞控制等机制,传输的数据可能会丢失或乱序。

- 速度:UDP传输速度较快,没有连接建立和断开等额外开销;TCP的连接建立和断开会导致一定的延迟。

2. Socket编程中,什么是阻塞和非阻塞?- 阻塞:当一个Socket进行I/O读写时,如果没有数据可读或没有足够的缓冲区可写入数据,该操作会一直阻塞,直到满足条件后才会返回。

- 非阻塞:当一个Socket进行I/O读写时,不论是否有数据可读或有足够的缓冲区可写入数据,该操作都会立即返回,可以继续进行其他操作。

3. Socket编程中,什么是同步和异步?- 同步:当一个Socket进行I/O读写时,应用程序需要等待Socket完成操作后才能继续执行下一条语句。

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,等等。

C#阻塞和非阻塞模式及其应用

C#阻塞和非阻塞模式及其应用

C#阻塞和非阻塞模式及其应用同步、异步、阻塞、非阻塞的概念:同步模式:客户端发送请求后,在发送下一个请求之前,必须从服务器获得响应。

此时,所有请求都在服务器上同步异步模式:客户端发送请求后,无需等待服务器的响应就可以发送下一个请求。

阻塞模式:指的是socket的调用函数直到得到结果才会返回。

在调用结果返回之前,当前线程会被挂起,即套接字在线程调用上已经被阻塞,不会执行下一条语句。

非阻塞模式:当执行socket的调用函数时,即使不能立即得到结果,函数也不会阻塞当前线程,而是立即返回。

同步和异步属于通信模式,阻塞和非阻塞属于套接字模式。

在实现结果方面,同步和阻塞是一致的,异步和非阻塞是一致的。

阻塞模式:1、阻塞写操作:write()、send()、sendto()、sendmsg()2、阻塞读操作:read()、recv()、recvfrom()、recvmsg()3、阻塞接收连接:accept()4、阻塞连接:connect()阻塞模式的特点:优点:1、结构简单2、通信双方比较容易保持同步3、编程逻辑简单,当函数成功返回时,则进程继续;否则,当函数返回错误时,检查错误类型,实施错误处理缺点:1.在读取操作期间,该过程可能会被永远阻塞。

在读取操作期间,如果另一台主机崩溃,该进程将无法接收任何数据,从而导致永久阻塞。

其他操作一般不会永远阻塞,但可能会阻塞很长时间。

2.工艺效率相对较低。

当一个进程在读取过程中被阻塞时,它必须等待读取操作的返回,在等待过程中不能执行任何其他操作。

如果一个进程同时从多个套接字读取数据,只能串行完成:首先读取第一个套接字,进程阻塞,等待套接字的数据到达。

在这个过程中,即使其他套接字的数据到达,也无法唤醒该进程,只能在第一个套接字的数据到达后唤醒。

解决阻塞模式的效率的方法:1、超时控制方法,能够防止进程阻塞时间过长。

常用的控制方法是使用套接字选项设置函数SetSockOption()。

socket 面试题

socket 面试题

socket 面试题在计算机网络中,Socket 是一种提供应用程序之间进行网络通信的接口。

Socket 编程是网络编程中常见的一种方式,通过 Socket 可以在不同的计算机之间建立网络连接,并进行数据传输。

Socket 面试题主要涵盖了 Socket 编程的一些基本知识和技巧。

下面将按照面试题的形式,逐个回答相关问题。

1. 什么是 Socket?Socket 是应用层与网络层之间的桥梁,是一种提供进程间通信的接口。

在网络编程中,Socket 的主要作用是建立连接并在连接中进行数据传输。

2. Socket 通信有几种类型?Socket 通信一般分为两种类型:TCP(传输控制协议)和 UDP(用户数据报协议)。

TCP 提供可靠的、面向连接的数据传输,而 UDP 则提供无连接的、不可靠的数据传输。

3. TCP 和 UDP 的区别是什么?TCP 是一种面向连接的传输协议,它提供可靠的、基于字节流的数据传输,确保数据的完整性和有序性。

而 UDP 则是一种无连接的传输协议,它不保证数据传输的可靠性,但传输速度较快。

4. Socket 建立连接的过程是怎样的?Socket 建立连接主要分为三个步骤:服务器端监听、客户端请求和服务端响应。

首先,服务器端在指定的端口上进行监听,等待客户端的连接请求;其次,客户端向服务器端发送连接请求;最后,服务器端接收到连接请求后,向客户端发送连接响应,建立连接。

5. Socket 编程中的阻塞和非阻塞模式有什么区别?在阻塞模式下,当 Socket 执行某个操作时,该操作会一直阻塞(即暂停执行),直到操作完成或出现错误。

而在非阻塞模式下,当Socket 执行某个操作时,如果该操作无法立即完成,Socket 不会等待,而是立即返回一个错误码或空值。

6. 如何保证 Socket 数据传输的可靠性?为了保证 Socket 数据传输的可靠性,可以采用以下几种方法:- 使用 TCP 协议,因为 TCP 提供可靠的、面向连接的数据传输。

阻塞的概念

阻塞的概念

阻塞的概念
阻塞是指当某个进程正在等待某个事件发生时,却被操作系统禁止在系统中执行任何操作的状态。

阻塞的发生是由于进程的执行需要等待某些事件发生,例如等待读取数据或者等待接受网络数据,但是在事件没有发生之前,进程是不能进行任何其他操作的。

这种状态通常被称为“阻塞状态”。

阻塞通常是由操作系统判断的。

操作系统会在程序执行时检查当前程序是否需要等待某些事件,如果需要等待,操作系统就会将进程置于阻塞状态。

阻塞状态的进程不会被CPU调度,直到所等待的事件发生或者其他进程通知它们。

阻塞状态有很多种原因,其中一些包括:
1. 等待输入输出操作
2. 等待进程资源
3. 等待信号处理
4. 等待网络事件
5. 等待同步事件
阻塞状态通常会影响程序的性能和响应时间。

如果阻塞状态持续太长时间,进程就可能会因超时而被终止。

因此,阻塞状态的处理非常重要,通常需要针对不同的阻塞原因采用不同的解决方案。

解决阻塞的方法:
1.非阻塞式IO:在这种方式下,当进程遇到IO操作时,它会继续执行其他任务,而不必等待IO操作完成。

但是它需要定期轮询IO操作是否完成,这样会浪费CPU时间。

2.多线程IO:这种方式下,当一个线程执行IO操作时,另外一个线程可继续执行其他任务。

3.异步IO:这种方式下,当IO操作完成时,系统会通知进程。

4.信号驱动IO:当IO操作被完成时,进程会接收到信号通知它。

总之,阻塞状态是计算机程序执行中的一种常见状态,遵循计算机的I/O机制。

阻塞会导致程序的性能变差、响应时间变慢,因此需要合理的方法来解决阻塞,从而保证程序的性能和可靠性。

阻塞队列与非阻塞队列

阻塞队列与非阻塞队列

阻塞队列与⾮阻塞队列阻塞队列阻塞队列(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:⼀个不存储元素的阻塞队列。

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块来捕获异常并进行处理。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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()函数。

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

阻塞和非阻塞

阻塞和非阻塞

阻塞和非阻塞
阻塞和非阻塞指的是调用者(程序)在等待返回结果(或输入)时的状态。

阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。

非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。

因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。

阻塞就是干不完不准回来,
非阻塞就是你先干,我现看看有其他事没有,完了告诉我一声
我们拿最常用的send和recv两个函数来说吧...
比如你调用send函数发送一定的Byte,在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执行成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和非阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有足够的空间把你要发送的数据Copy过去以后才返回,而对于非阻塞的socket来说send会立即返回WSAEWOULDDBLOCK告诉调用者说:"发送操作被阻塞了你想办法处理吧..."
对于recv函数,同样道理,该函数的内部工作机制其实是在等待
TCP/IP协议栈的接收缓冲区通知它说:嗨,你的数据来了.对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知一个结果给它它就一直不返回:耗费着系统资源....对于非阻塞模式的socket该
函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头在来看看"。

阻塞线程和非阻塞线程

阻塞线程和非阻塞线程

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

从缓冲上看阻塞与非阻塞socket在发送接收上的区别收藏
最近在网络上看到一些帖子以及回复,同时又搜索了一些网络上关于阻塞非阻塞区别的描述,发现很多人在描述两者的发送接收时操作返回以及缓冲区处理的区别时有不同程度的误解。

所以我想写一篇文章来纠正错误,并作为记录方便查阅,如有转载,注明作者(jwybobo2007)以及出处即可。

首先socket在默认情况下是阻塞状态的(未指异步操作以及其它一些特殊用途下,直接默认为非阻塞),这就使得发送以及接收操作处于阻塞的状态,即调用不会立即返回,而是进入睡眠等待操作完成。

下面把讨论点分为发送以及接收。

一.发送选用send(这里特指TCP)以及sendto(这里特指UDP)来描述
首先需要说明的是,不管阻塞还是非阻塞,在发送时都会将数据从应用缓冲区拷贝到内核缓冲区(SO_RCVBUF选项声明,除非缓冲区大小为0)。

我在网络上看到某些人说,阻塞就是将数据真正发送给对方,并且阻塞是发生在需要把前面的所有数据全部发送出去,然后再发送本次的,而非阻塞则是拷贝到发送缓冲区。

我不得不说,上面的这种说法是错误的。

在阻塞模式下send操作将会等待所有数据均被拷贝到发送缓冲区后才会返回。

如果当前发送缓冲总大小为8192,已经拷贝到缓冲的数据为8000,那剩余的大小为192,现在需要发送2000字节数据,那阻塞发送就会等待缓冲区足够把所有2000字节数据拷贝进去,如第一次拷贝进192字节,当缓冲区成功发送出1808字节后,再把应用缓冲区剩余的1808字节拷贝到内核缓冲,而后send操作返回成功发送字节数。

从上面的过程不难看出,阻塞的send操作返回的发送大小,必然是你参数中的发送长度的大小。

在阻塞模式下的sendto操作不会阻塞。

关于这一点的原因在于:UDP并没有真正的发送缓冲区,它所做的只是将应用缓冲区拷贝给下层协议栈,在此过程中加上UDP头,IP头,所以实际不存在阻塞。

在非阻塞模式下send操作调用会立即返回。

关于立即返回大家都不会有异议。

还是拿阻塞send的那个例子来看,当缓冲区只有192字节,但是却需要发送2000字节时,此时调用立即返回,并得到返回值为192。

从中可以看到,非阻塞send仅仅是尽自己的能力向缓冲区拷贝尽可能多的数据,因此在非阻塞下send才有可能返回比你参数中的发送长度小的值。

如果缓冲区没有任何空间时呢?这时肯定也是立即返回,但是你会得到WSAEWOULDBLOCK/E WOULDBLOCK的错误,此时表示你无法拷贝任何数据到缓冲区,你最好休息一下再尝试发送。

在非阻塞模式下sendto操作不会阻塞(与阻塞一致,不作说明)。

二.接收选用recv(这里特指TCP)以及recvfrom(这里特指UDP)来描述
在阻塞模式下recv,recvfrom操作将会阻塞到缓冲区里有至少一个字节(TCP)或者一个完整UDP数据报才返回。

在没有数据到来时,对它们的调用都将处于睡眠状态,不会返回。

在非阻塞模式下recv,recvfrom操作将会立即返回。

如果缓冲区有任何一个字节数据(TCP)或者一个完整UDP数据报,它们将会返回接收到的数据大小。

而如果没有任何数据则返回错
误WSAEWOULDBLOCK/E WOULDBLOCK。

以上是关于阻塞非阻塞发送接收的区别以及在缓冲区处理上的差别,希望给看到这篇文章的人一些帮助。

同时也想纠正网络上的某些错误观点,文章中表述如有错误,望大家指正,谢谢。

转载请注明作者:jwybobo2007
原文地址:
/jwybobo2007/archive/2011/01/26/6164362.aspx。

相关文档
最新文档