linux socket非阻塞 docker设置代理

各位老铁们,大家好,今天由我来为大家分享linux socket非阻塞,以及docker设置代理的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

C++ socket非阻塞模式

一、前言

初期学习socket的时候,为了方便理解,使用默认的阻塞模式比较多。而实际做项目时,我们必须考虑程序的并发性,非阻塞模式在其中担任着很重要的角色,是必会的点之一。本文不对阻塞IO和非阻塞IO的概念做说明,不了解的请自行了解。下文代码以linux平台为例。

二、设置非阻塞模式

设置非阻塞模式,通过fcntl方法设置,为了保存socket其他设置,一般选择先获取 status flags,并在其基础上设置O_NONBLOCK属性,代码如下:

fcntl失败返回值为-1,同时errno会被设置成对应的错误码。(errno在此不做说明,不了解的自行了解。)考虑失败的情况,个人注意到网上有些例子(包括ss-libev项目)在 F_GETFL失败后,给了flags默认值,代码如下:

经过测试,默认情况下,flags得到的值为2,也就是O_RDWR读写,而 0对应的相关宏为O_RDONLY只读,明显不合理。个人感觉,对于一个正常的socket来说,F_GETFL出错的机会不大吧,至少我是没遇到过。如果实在出错了,还是建议走错误流程而不是给个默认值。

三、非阻塞server

server端通常在accept后,我们为客户端连接的fd设置为非阻塞。设置O_NONBLOCK后,recv和send发生了变化。默认阻塞模式下,recv在没有数据可以接收(对方未发数据,或者缓冲区的数据已读完对方没有继续发)情况下,recv会阻塞等待,直到下次有数据发送过来。而非阻塞模式下,recv在没有数据可以接收的时候, recv会直接返回-1,同时errno会被设置为EAGAIN/EWOULDBLOCK。同理,非阻塞send也会在对方缓冲区满的情况下直接返回-1并设置errno,而不是阻塞等待。非阻塞模式下server代码大致如下:

四、非阻塞client

client除了在send/recv,还可以在connect前设置非阻塞模式,这样在connect时候可以直接返回。

client非阻塞connect的时候,如果返回0表示连接成功,如果返回-1,则需要判断errno是否为EINPROGRESS,EINPROGRESS表示非阻塞连接不能立刻获取connect结果,后面可使用select/poll/epoll等对socket可写性进行判断,如果socket已可写,使用 getsockopt(iSocket, SOL_SOCKET, SO_ERROR,&err,&len)进行判断。。。好像挺麻烦是不是,但是我还是建议在大部分项目中connect前设置非阻塞(小工具之类的就无所谓了,项目中一定要保证效率)。如果使用阻塞模式,有可能的问题:

下面是个非阻塞connect的部分代码,使用select,至于poll/epoll请自行搜索代码,跟非阻塞逻辑无关:

socket的阻塞模式和非阻塞模式

Socket技术在计算机网络编程中扮演着关键角色,它主要分为阻塞模式和非阻塞模式两种。

在Linux环境中,通常创建的Socket默认为阻塞模式。若需将其设置为非阻塞模式,可以使用特定选项。

在创建Socket时,通过将__type增加SOCK_NOBLOCK,即可实现非阻塞模式的设置。此外,使用Linux的accept4函数,可直接将返回的Socket设置为非阻塞。

Send和recv函数在不同的模式下执行特定操作。它们并不直接与网络交互,而是将数据从应用层缓冲区复制到内核缓冲区,或者从内核缓冲区复制到应用缓冲区。

通过流程图,可以直观了解数据传输过程。应用程序间的通信中,发送端将内核缓冲区的数据通过网络传输给接收端的内核缓冲区。若一端持续发送数据,而另一端未接收,内核缓冲区(即TCP窗口)将迅速满载,导致阻塞。

以《C++服务器开发精髓》中的例子说明,当服务端不断调用send函数,将数据填充到内核缓冲区后,若客户端未调用recv函数进行数据接收,服务端缓冲区将被填满。此时若继续调用send函数,将引起阻塞现象。

使用tcpdump工具可以观察到TCP窗口大小的动态变化,当窗口逐渐减小直至变为零时,即表示网络传输阻塞。

在非阻塞模式下,Send和Recv函数返回值具有特殊含义:返回值大于0表示成功发送或接收指定数量的字节;返回值等于零表示对端关闭连接;小于零表示出现错误,可能因信号中断、TCP窗口过小导致数据发送受阻或当前网络缓冲区无数据可接收。

需要特别注意的是,在非阻塞模式下,判断send返回值是否等于要发送的字节数,而非简单判断返回值是否大于零。这有助于避免误解发送情况,确保代码逻辑的准确性和高效性。

以上总结了Socket的阻塞和非阻塞模式,以及Send和Recv函数在不同模式下的行为和返回值意义,为开发者提供了清晰的指导和实践依据。

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);

阅读剩余
THE END