Android VpnService.Builder setBlocking方法实际作用技术咨询
Android VpnService.Builder.setBlocking() 实际作用详解
让我来帮你把这个方法的作用拆解清楚,顺便验证你观察到的结论到底对不对~
首先,这个方法本质是控制TUN设备的I/O阻塞模式——Android的VpnService底层依赖Linux系统的TUN虚拟网络设备,setBlocking()就是给这个设备设置阻塞/非阻塞属性,你看到的Builder里只是把参数存在mConfig.blocking里,真正生效是在框架层创建TUN设备的时候,把这个参数传递给底层系统调用。
当设为true(阻塞模式)时的影响
你观察到的“不会丢弃要写入TUN的数据包”完全正确,它的核心行为是:
- 读取操作:调用
read()从TUN设备拿数据时,如果当前没有待处理的数据包,执行read()的线程会挂起等待,直到有新的数据包进入设备才会返回结果; - 写入操作:调用
write()向TUN设备写数据时,如果设备的输出缓冲区已经满了,线程同样会挂起等待,直到缓冲区腾出足够空间,再完成整个写入操作。
简单说就是:阻塞模式下,I/O操作必须“完成任务”才会返回,不会丢包,只是会让线程暂时停住。
当设为false(非阻塞模式)时的区别
和阻塞模式完全相反:
- 读取操作:如果TUN设备里没有数据,
read()会立刻返回-1,同时系统错误码会被设为EAGAIN或EWOULDBLOCK,告诉你“现在没数据,稍后再试”; - 写入操作:如果缓冲区满了,
write()不会等待,而是立刻返回已经成功写入的字节数(可能比你要写的长度短),或者直接返回-1并抛出对应错误。这时候如果你的代码不处理重试逻辑,没写入的那部分数据就相当于丢失了。
补充个开发场景小提示
- 用阻塞模式的话,一定要单独开后台线程处理TUN的读写,不然会阻塞主线程导致ANR;
- 非阻塞模式适合配合多路复用机制(比如
select()、epoll)使用,能同时处理多个I/O任务,避免线程挂起,但需要你自己处理重试和错误逻辑。
内容的提问来源于stack exchange,提问作者itarill
相关产品推荐
相关产品推荐

