Ruby环境下如何获取SSLSocket中剩余待读取的字节数
适用于Ruby SSLSocket的待读数据检测实现
OpenSSL::SSL::SSLSocket未内置普通TCPSocket的ready?方法,可通过以下两种方案实现待读取数据的检测与统计:
方案1:IO.select 无阻塞检测(全平台兼容,推荐)
IO.select是Ruby IO层提供的通用监听能力,可在不阻塞线程的前提下检测socket是否存在可读取数据,适配所有Ruby支持的平台:
# 入参为待检测的SSLSocket实例,timeout设为0表示立即返回不阻塞 def ssl_has_readable_data?(ssl_sock, timeout = 0) IO.select([ssl_sock], nil, nil, timeout) ? true : false end # 业务逻辑示例 if ssl_has_readable_data?(your_ssl_socket) # 存在待读数据,执行读取逻辑 received = your_ssl_socket.read_nonblock(4096) else # 无待读数据,主动发送消息 your_ssl_socket.write("peer active message") end
该方案仅检测是否存在可读数据,如需获取精确的待读字节数,使用方案2。
方案2:精确统计待读字节数(兼容Unix/Linux/macOS,可适配Windows)
结合SSL层内置缓冲区查询与底层TCP socket的ioctl系统调用,可得到完整的待读数据字节数:
require 'fcntl' require 'openssl' def get_ssl_pending_bytes(ssl_sock) # 优先返回SSL层已解密的待读字节数 pending = ssl_sock.pending return pending if pending > 0 # 查询底层TCP套接字未解密的待读字节数 buf = [0].pack('I') ssl_sock.ioctl(Fcntl::FIONREAD, buf) buf.unpack1('I') end # 业务逻辑示例 pending_bytes = get_ssl_pending_bytes(your_ssl_socket) if pending_bytes > 0 received = your_ssl_socket.read(pending_bytes) else # 主动发送逻辑 end
跨平台适配说明
Windows环境下将Fcntl::FIONREAD替换为常量值0x4004667f即可正常使用。
边缘情况处理
非阻塞读取场景下,建议捕获IO::WaitReadable、OpenSSL::SSL::SSLErrorWaitReadable异常,避免偶发的缓冲区未就绪报错。
内容的提问来源于stack exchange,提问作者Marek Küthe
相关产品推荐
相关产品推荐

