导航:首页 > 操作系统 > linuxsocket设置非阻塞

linuxsocket设置非阻塞

发布时间:2025-02-20 20:30:06

linux网络编程中阻塞和非阻塞socket的区别

阻塞socket和非阻塞socket的区别:
1、读操作
对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的字节数,返回实际读取的长度。
对于非阻塞socket而言,socket的接收缓冲区中有没有数据,read调用都会立刻返回。接收缓冲区中有数据时,与阻塞socket有数据的情况是一样的,如果接收缓冲区中没有数据,则返回错误号为EWOULDBLOCK,表示该操作本来应该阻塞的,但是由于本socket为非阻塞的socket,因此立刻返回,遇到这样的情况,可以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。
因此,非阻塞的rea调用一般这样写:
if ((nread = read(sock_fd, buffer, len)) < 0)
{
if (errno == EWOULDBLOCK)
{
return 0; //表示没有读到数据
}else return -1; //表示读取失败
}else return nread;读到数据长度
2、写操作
对于写操作write,原理是类似的,非阻塞socket在发送缓冲区没有空间时会直接返回错误号EWOULDBLOCK,表示没有空间可写数据,如果错误号是别的值,则表明发送失败。如果发送缓冲区中有足够空间或者是不足以拷贝所有待发送数据的空间的话,则拷贝前面N个能够容纳的数据,返回实际拷贝的字节数。
而对于阻塞Socket而言,如果发送缓冲区没有空间或者空间不足的话,write操作会直接阻塞住,如果有足够空间,则拷贝所有数据到发送缓冲区,然后返回.
非阻塞的write操作一般写法是:
int write_pos = 0;
int nLeft = nLen;
while (nLeft > 0)
{
int nWrite = 0;
if ((nWrite = write(sock_fd, data + write_pos, nLeft)) <= 0)
{
if (errno == EWOULDBLOCK)
{
nWrite = 0;
}else return -1; //表示写失败
}
nLeft -= nWrite;
write_pos += nWrite;
}
return nLen;
3、建立连接
阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的确认时,则connect返回.否则的话一直阻塞.
非阻塞方式,connect将启用TCP协议的三次握手,但是connect函数并不等待连接建立好才返回,而是立即返回。返回的错误码为EINPROGRESS,表示正在进行某种过程.
4、接收连接
对于阻塞方式的倾听socket,accept在连接队列中没有建立好的连接时将阻塞,直到有可用的连接,才返回。
非阻塞倾听socket,在有没有连接时都立即返回,没有连接时,返回的错误码为EWOULDBLOCK,表示本来应该阻塞。
无阻塞的设置方法
方法一:fcntl
int flag;
if (flag = fcntl(fd, F_GETFL, 0) <0) perror("get flag");
flag |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flag) < 0)
perror("set flag");
方法二:ioctl
int b_on = 1;
ioctl (fd, FIONBIO, &b_on);

Ⅱ recv是阻塞还是非阻塞的

网络编程函数如recv是阻塞(同步)还是非阻塞(异步)取决于在调用recv函数前创建的套接字socket是阻塞还是非阻塞。socket默认创建时设定为阻塞模式;若要将socket设定为非阻塞模式,可以在socket创建时设定为非阻塞模式,那么函数recv就是非阻塞的。
可以通过一下几种方法设定socket为非阻塞:
1.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);
2.windows和linux平台accept()函数返回的socekt也是阻塞的,linux另外提供了一个accept4()函数,可以直接将socket设置为非阻塞模式:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
只要将accept4()最后一个参数flags设置成SOCK_NONBLOCK即可。

3.除了在创建socket时,将socket设置为非阻塞模式,还可以通过以下函数来设置:

linux平台可以调用fcntl()或ioctl()函数,例如:
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
ioctl(sockfd, FIONBIO, 1); //1:非阻塞 0:阻塞
windows平台可调用ioctlsocket函数:

int ioctlsocket(
_In_ SOCKET s,
_In_ long cmd,
_Inout_ u_long *argp
);
将cmd参数设置为FIONBIO,*argp=0即设置成阻塞模式,而*argp非0即可设置成非阻塞模式。但windows平台一个地方需要注意,如果对一个socket调用了WSAAsyncSelect()或WSAEventSelect()函数后,你再调用ioctlsocket()函数将该socket设置为阻塞模式,则会失败,必须先调用WSAAsyncSelect()设置lEvent参数为0或调用WSAEventSelect()设置lNetworkEvents参数为0来分别禁用WSAAsyncSelect()或WSAEventSelect(),再次调用ioctlsocket()将该socket设置成阻塞模式才会成功。因为调用WSAAsyncSelect()或WSAEventSelect()函数会自动将socket设置成非阻塞模式。

Ⅲ 服务器编程心得(四)—— 如何将socket设置为非阻塞模式

在服务器编程中,设置socket为非阻塞模式是提高性能的关键技术之一。不同操作系统上实现这一功能的方法有所差异。在Windows平台上,无论是使用socket()函数还是WSASocket()函数创建的socket都是默认为阻塞模式的。

相比之下,Linux平台上在使用socket()函数创建socket时,可以通过在type参数中设置SOCK_NONBLOCK标志来创建一个非阻塞模式的socket。例如:

在Linux上,通过将SOCK_NONBLOCK标志设置为SOCK_NONBLOCK,即可创建一个非阻塞模式的socket。

在Windows和Linux平台上的accept()函数返回的socket同样是阻塞模式的,不过Linux额外提供了一个accept4()函数,该函数可以直接将返回的socket设置为非阻塞模式。实现方法只需将accept4()函数的最后一个参数flags设置为SOCK_NONBLOCK即可。

除了在创建socket时设置非阻塞模式外,还可以通过调用特定的API函数来实现。在Linux平台上,可以使用fcntl()或者ioctl()函数来修改socket的阻塞属性。例如:

通过调用fcntl()函数或者ioctl()函数,即可将Linux平台上的socket设置为非阻塞模式。在设置非阻塞模式时,需要确保在接收和发送数据时使用了MSG_DONTWAIT标志,即在recv、recvfrom和send、sendto函数调用时,将flag参数设置为MSG_DONTWAIT。然而,根据Linux手册的说明,设置recv()函数的flags标识位为MSG_DONTWAIT或者通过fcntl()函数设置O_NONBLOCK标识,已经足够实现非阻塞操作,无需同时设定两种方式。

在Windows平台上,可以通过调用ioctlsocket函数来改变socket的阻塞模式。将cmd参数设置为FIONBIO,同时将*argp参数设置为0或非0,即可分别设置socket为阻塞模式或非阻塞模式。需要注意的是,如果对socket调用了WSAAsyncSelect()或WSAEventSelect()函数后,再尝试使用ioctlsocket()将socket设置为非阻塞模式,将会失败。解决此问题,需要先通过设置lEvent参数为0或设置lNetworkEvents参数为0来禁用WSAAsyncSelect()或WSAEventSelect(),然后再调用ioctlsocket()设置socket为阻塞模式。

在实际项目中,有的前辈可能会在一个循环里调用fcntl()或者ioctlsocket()函数来改变socket的阻塞模式。然而,这是否必要,仍有待验证。建议读者根据实际需求和项目要求选择合适的方法。

如果想系统地学习上述知识,推荐阅读尹圣雨的《TCP/IP 网络编程》这本书,它兼顾了Windows和Linux两个平台,使用C语言和操作系统的Socket API,能够帮助读者理解网络编程的基本概念和实现方法。对于更深入的高性能网络框架和设计,可以参考游双老师的《Linux 高性能服务器编程》一书。

此外,作者也出版了一本书《C++服务器开发精髓》,涵盖了从客户端到服务器、从Windows到Linux的经验总结,包括C++开发编译调试技术、多线程编程、网络故障排查、通信协议设计、高性能网络框架设计、服务框架设计、服务组件开发等知识。获取更多书籍信息,请参考相关链接。

阅读全文

与linuxsocket设置非阻塞相关的资料

热点内容
三菱plc编程软件gxdevelop 浏览:400
php从入门到精通光盘下载 浏览:922
不能表示算法的是什么 浏览:131
读卡器在文件夹怎么查看照片 浏览:802
程序员是属于哪个部门管理 浏览:615
交换机命令be 浏览:330
存储压缩加密技术情况 浏览:504
知名的可编程步进电机驱动器工厂 浏览:184
银行卡信息加密想取消 浏览:219
程序员唱可爱 浏览:824
除了移动花卡怎么更改定向app 浏览:326
python多线程java 浏览:255
2021程序员笔记本r5 浏览:662
算法监管的要点在于 浏览:895
长安s460压缩机 浏览:246
php访问符 浏览:142
搜索字体在哪个文件夹 浏览:31
查python答案用什么 浏览:317
nm卡数据加密么 浏览:571
ipad如何给软件加密 浏览:682