导航:首页 > 编程系统 > linuxselect非阻塞

linuxselect非阻塞

发布时间:2021-10-26 05:56:26

linux 怎样实现非阻塞connect

1. 设置socket
int oldOption = fcntl(sockfd, F_GETFL);
int newOption = oldOption | O_NONBLOCK;
//设置sockfd非阻塞
fcntl(sockfd, F_SETFL, newOption);12345

2. 执行connect
如果返回0,表示连接成功,这种情况一般在本机上连接时会出现(否则怎么可能那么快)
否则,查看error是否等于EINPROGRESS(表明正在进行连接中),如果不等于,则连接失败
int ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == 0)
{
//连接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}
else if(errno != EINPROGRESS)
{
//连接没有立即返回,此时errno若不是EINPROGRESS,表明错误
perror("connect error != EINPROGRESS");
return -1;
}12345678910111213141516

3. 使用select,如果没用过select可以去看看
用select对socket的读写进行监听
那么监听结果有四种可能
1. 可写(当连接成功后,sockfd就会处于可写状态,此时表示连接成功)
2. 可读可写(在出错后,sockfd会处于可读可写状态,但有一种特殊情况见第三条)
3. 可读可写(我们可以想象,在我们connect执行完到select开始监听的这段时间内,
如果连接已经成功,并且服务端发送了数据,那么此时sockfd就是可读可写的,
因此我们需要对这种情况特殊判断)
说白了,在可读可写时,我们需要甄别此时是否已经连接成功,我们采用这种方案:
再次执行connect,然后查看error是否等于EISCONN(表示已经连接到该套接字)。
4. 错误

if(FD_ISSET(sockfd, &writeFds))
{
//可读可写有两种可能,一是连接错误,二是在连接后服务端已有数据传来
if(FD_ISSET(sockfd, &readFds))
{
if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
int error=0;
socklen_t length = sizeof(errno);
//调用getsockopt来获取并清除sockfd上的错误.
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
{
printf("get socket option failed\n");
close(sockfd);
return -1;
}
if(error != EISCONN)
{
perror("connect error != EISCONN");
close(sockfd);
return -1;
}
}
}
//此时已排除所有错误可能,表明连接成功
fcntl(sockfd, F_SETFL, oldOption);
return sockfd;
}0

4. 恢复socket
因为我们只是需要将连接操作变为非阻塞,并不包括读写等,所以我们吃醋要将socket重新设置。
fcntl(sockfd, F_SETFL, oldOption);关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html

❷ linux下设置recvfrom为非阻塞

可以使用
1 select pselect
2 poll

3可以使用fcntl给文件描述符添加O—UNBLOCK

❸ linux网络编程,为什么要将文件描述符设置成非阻塞模式

非阻塞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&~O_NONBLOCK); //设置成阻塞模式;
并在接收和发送数据时:
将recv, send 函数的最后有一个flag 参数设置成MSG_DONTWAIT
recv(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):
读的本质来说其实不能是读,在实际中, 具体的接收数据不是由这些调用来进行,是由于系统底层自动完成的。read 也好,recv 也好只负责把数据从底层缓冲 到我们指定的位置.
对于读来说(read, 或者recv) ::
阻塞情况下::
在阻塞条件下,read/recv/msgrcv的行为::
1、如果没有发现数据在网络缓冲中会一直等待,
2、当发现有数据的时候会把数据读到用户指定的缓冲区,但是如果这个时候读到的数据量比较少,比参数中指定的长度要小,read 并不会一直等待下去,而是立刻返回。
read 的原则::是数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待。
所以一般情况下::我们读取数据都需要采用循环读的方式读取数据,因为一次read 完毕不能保证读到我们需要长度的数据,
read 完一次需要判断读到的数据长度再决定是否还需要再次读取。
非阻塞情况下::
在非阻塞的情况下,read 的行为::
1、如果发现没有数据就直接返回,
2、如果发现有数据那么也是采用有多少读多少的进行处理.
所以::read 完一次需要判断读到的数据长度再决定是否还需要再次读取。

对于读而言:: 阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回.
recv 中有一个MSG_WAITALL 的参数::
recv(sockfd, buff, buff_size, MSG_WAITALL),
在正常情况下recv 是会等待直到读取到buff_size 长度的数据,但是这里的WAITALL 也只是尽量读全,在有中断的情况下recv 还是可能会被打断,造成没有读完指定的buff_size的长度。
所以即使是采用recv + WAITALL 参数还是要考虑是否需要循环读取的问题,在实验中对于多数情况下recv (使用了MSG_WAITALL)还是可以读完buff_size,
所以相应的性能会比直接read 进行循环读要好一些。

注意:: //使用MSG_WAITALL时,sockfd必须处于阻塞模式下,否则不起作用。
//所以MSG_WAITALL不能和MSG_NONBLOCK同时使用。
要注意的是使用MSG_WAITALL的时候,sockfd 必须是处于阻塞模式下,否则WAITALL不能起作用。



阻塞与非阻塞写的区别: //
写(send/write/msgsnd)::
写的本质也不是进行发送操作,而是把用户态的数据 到系统底层去,然后再由系统进行发送操作,send,write返回成功,只表示数据已经 到底层缓冲,而不表示数据已经发出,更不能表示对方端口已经接收到数据.
对于write(或者send)而言,
阻塞情况下:: //阻塞情况下,write会将数据发送完。(不过可能被中断)
在阻塞的情况下,是会一直等待,直到write 完,全部的数据再返回.这点行为上与读操作有所不同。
原因::
读,究其原因主要是读数据的时候我们并不知道对端到底有没有数据,数据是在什么时候结束发送的,如果一直等待就可能会造成死循环,所以并没有去进行这方面的处理;
写,而对于write, 由于需要写的长度是已知的,所以可以一直再写,直到写完.不过问题是write 是可能被打断吗,造成write 一次只write 一部分数据, 所以write 的过程还是需要考虑循环write, 只不过多数情况下一次write 调用就可能成功.

非阻塞写的情况下:: //
非阻塞写的情况下,是采用可以写多少就写多少的策略.与读不一样的地方在于,有多少读多少是由网络发送的那一端是否有数据传输到为标准,但是对于可以写多少是由本地的网络堵塞情况为标准的,在网络阻塞严重的时候,网络层没有足够的内存来进行写操作,这时候就会出现写不成功的情况,阻塞情况下会尽可能(有可能被中断)等待到数据全部发送完毕, 对于非阻塞的情况就是一次写多少算多少,没有中断的情况下也还是会出现write 到一部分的情况.

❹ 非阻塞select函数返回什么csdn

阻塞方式block,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回。
使用Select就可以完成非阻塞non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高。select能够监视我们需要监视的文件描述符的变化情况。

❺ windows下的socket如果设置为非阻塞,那么轮询,太耗费资源。有没有像linux下的,select或者说是epoll方法

可以用完成端口(等同于Linux下的epoll模型)来实现你的需求,以下是简介:

Win32重叠I/O(Overlapped I/O)机制允许发起一个操作,然后在操作完成之后接受到信息。对于那种需要很长时间才能完成的操作来说,重叠IO机制尤其有用,因为发起重叠操作的线程 在重叠请求发出后就可以自由的做别的事情了。在WinNT和Win2000上,提供的真正的可扩展的I/O模型就是使用完成端口(Completion Port)的重叠I/O.完成端口---是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不 可,还有设备内核对象、事件对象、告警I/0等。但是完成端口内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活的决定 线程个数,而且可以让减少线程调度的次数从而提高性能其实类似于WSAAsyncSelect和select函数的机制更容易兼容Unix,但是难以实现 我们想要的“扩展性”。而且windows的完成端口机制在操作系统内部已经作了优化,提供了更高的效率。所以,我们选择完成端口开始我们的服务器程序的 开发。

❻ linux非阻塞socket中select的问题

select是不断的监来听文件描述自符,肯定能探测到它已经关闭了,那么关闭的fd肯定就得从它的fd_set中退出来哇,退出来了,它自然就不监听这个fd了,然后就只有等到超时退出了·····我个人的理解,说的好就给个分···呵呵··

❼ linux 使用epoll主要目的是啥 为了实现非阻塞么

socket本来就有阻塞和非阻塞两种模式,与epoll无关。
epoll是针对多socket操作(从select升级内到poll再到epoll都是解决这个目容的)。
如果不用poll方法,在阻塞模式下,操作多socket,要么用多线程,要么用多进程,都会带来一定的开发复杂度和性能降低。在非阻塞模式下,就要使用轮询,浪费处理能力很厉害。

所以,epoll是为了让程序只在一个线程中就能操作大量socket而提供的一个核心功能,同时还提供了很高的处理性能

❽ 非阻塞select和阻塞select的区别

可以用WINDOWS完成端口(等同于Linux下的epoll模型)来实现你的需求,以下是简介:Win32重叠I/O(OverlappedI/O)机制允许发起一个操作,然后在操作完成之版后接受到信息。对于那种需要很长时间才能完成的操作来说,重叠IO机制尤其有用,因为发起重叠操作的线程在重叠请求发出后就可以自由的做别的事情了。在WinNT和Win2000上,提供的真正的可扩展的I/O模型就是使用完权成端口(CompletionPort)的重叠I/O.完成端口---是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不可,还有设备内核对象、事件对象、告警I/0等。但是完成端口内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活的决定线程个数,而且可以让减少线程调度的次数从而提高性能其实类似于WSAAsyncSelect和select函数的机制更容易兼容Unix,但是难以实现我们想要的“扩展性”。而且windows的完成端口机制在操作系统内部已经作了优化,提供了更高的效率。所以,我们选择完成端口开始我们的服务器程序的开发。

❾ linux 非阻塞connect errno什么情况下不为einprogress

当connect在非阻塞模式下,会出现返回-1值,错误码是EINPROGRESS,但如何判断connect是联通的呢?stevens书中说明要在connect后,继续判断该socket是否可写?

若可写,则证明链接成功。如何判断可写,有2种方案,一种是select判断是否可写,二用poll模型。

select:
int CheckConnect(int iSocket)
{
fd_set rset;

FD_ZERO(&rset);
FD_SET(iSocket, &rset);

timeval tm;
tm. tv_sec = 0;
tm.tv_usec = 0;

if ( select(iSocket + 1, NULL, &rset, NULL, &tval) <= 0)
{
close(iSocket);
return -1;
}

if (FD_ISSET(iSocket, &rset))
{
int err = -1;
socklen_t len = sizeof(int);
if ( getsockopt(iSocket, SOL_SOCKET, SO_ERROR ,&err, &len) < 0 )
{
close(iSocket);
printf("errno:%d %s\n", errno, strerror(errno));
return -2;
}

if (err)
{
errno = err;
close(iSocket);

return -3;
}
}

return 0;
}

poll:

int CheckConnect(int iSocket) {
struct pollfd fd;
int ret = 0;
socklen_t len = 0;

fd.fd = iSocket;
fd.events = POLLOUT;

while ( poll (&fd, 1, -1) == -1 ) {
if( errno != EINTR ){
perror("poll");
return -1;
}
}

len = sizeof(ret);
if ( getsockopt (iSocket, SOL_SOCKET, SO_ERROR, &ret, &len) == -1 ) {
perror("getsockopt");
return -1;
}

if(ret != 0) {
fprintf (stderr, "socket %d connect failed: %s\n",
iSocket, strerror (ret));
return -1;
}

return 0;
}

❿ 对于使用select的操作有没有必要把IO设置为非阻塞

可以用WINDOWS完成端口(等同于Linux下的epoll模型)来实现你的需求,以下是简介: Win32重叠I/O(Overlapped I/O)机制允许发起一个操作,然后在操作完成之后接受到信息。对于那种需要很长时间才能完成的操作来说,重叠IO机制尤其有用

阅读全文

与linuxselect非阻塞相关的资料

热点内容
男主囚禁女主灭了她的国家 浏览:841
男人看的电影网站 浏览:390
车展推广app有哪些 浏览:787
云学app哪个好 浏览:498
因为什么对编程感兴趣 浏览:161
linux获取内核时间 浏览:926
iphonehome键变硬 浏览:32
所有文件onion 浏览:841
word写作格式 浏览:1
网页中文件及文件夹的命名规则 浏览:105
水蜜桃电子书txt全集下载 浏览:850
豫剧电影农村片 浏览:26
javaprivate类继承 浏览:487
电脑文件历史记录干什么用 浏览:136
如何去掉文件的只读属性 浏览:403
水沫缘浅的全部作品集下载 浏览:575
免费电影在线观看网站 浏览:697
涨奶挤出来的母乳电影 浏览:897
催眠控制类百合 浏览:13
编程属于哪个发票范围 浏览:207

友情链接