模块 OpenSSL::Buffering
此模块允许 OpenSSL::SSL::SSLSocket
的行为类似于 IO
。
通常您不会直接使用此模块,您可以在 OpenSSL::SSL::SSLSocket
中看到它的实现。
常量
- BLOCK_SIZE
-
用于缓冲区操作的从 SSLSocket 读取或写入的默认大小。
属性
公共类方法
公共实例方法
来源
# File ext/openssl/lib/openssl/buffering.rb, line 434 def <<(s) do_write(s) self end
将 *s* 写入流。 *s* 将使用 .to_s
方法转换为 String
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 495 def close flush rescue nil sysclose end
关闭 SSLSocket 并刷新任何未写入的数据。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 266 def each(eol=$/) while line = self.gets(eol) yield line end end
为流中的每一行执行代码块,其中行由 *eol* 分隔。
另请参见 gets
来源
# File ext/openssl/lib/openssl/buffering.rb, line 307 def each_byte # :yields: byte while c = getc yield(c.ord) end end
为流中的每个字节调用一次给定的代码块。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 338 def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end
如果流位于文件末尾,则返回 true,这意味着没有更多数据要读取。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 483 def flush osync = @sync @sync = true do_write "" return self ensure @sync = osync end
将缓冲数据刷新到 SSLSocket。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 106 def getbyte read(1)&.ord end
从 'ssl' 获取下一个 8 位字节。在 EOF 时返回 `nil`
来源
# File ext/openssl/lib/openssl/buffering.rb, line 300 def getc read(1) end
从流中读取一个字符。如果在文件末尾调用,则返回 nil。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 238 def gets(eol=$/, limit=nil, chomp: false) idx = @rbuffer.index(eol) until @eof break if idx fill_rbuff idx = @rbuffer.index(eol) end if eol.is_a?(Regexp) size = idx ? idx+$&.size : nil else size = idx ? idx+eol.size : nil end if size && limit && limit >= 0 size = [size, limit].min end line = consume_rbuff(size) if chomp && line line.chomp!(eol) end line end
从流中读取下一“行”。行由 *eol* 分隔。如果提供了 *limit*,则结果将不会长于给定的字节数。
与 IO#gets
不同,读取的行不会被赋值给 +$_+。
与 IO#gets
不同,如果提供了限制,则必须提供分隔符。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 462 def print(*args) s = Buffer.new args.each{ |arg| s << arg.to_s } do_write(s) nil end
将 *args* 写入流。
有关完整详细信息,请参见 IO#print
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 475 def printf(s, *args) do_write(s % args) nil end
格式化并写入流,根据格式字符串控制转换参数。
有关格式字符串的详细信息,请参见 Kernel#sprintf
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 444 def puts(*args) s = Buffer.new if args.empty? s << "\n" end args.each{|arg| s << arg.to_s s.sub!(/(?<!\n)\z/, "\n") } do_write(s) nil end
将 *args* 以及记录分隔符写入流。
有关完整详细信息,请参见 IO#puts
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 122 def read(size=nil, buf=nil) if size == 0 if buf buf.clear return buf else return "" end end until @eof break if size && size <= @rbuffer.size fill_rbuff end ret = consume_rbuff(size) || "" if buf buf.replace(ret) ret = buf end (size && ret.empty?) ? nil : ret end
从流中读取 *size* 个字节。如果提供了 *buf*,它必须引用将接收数据的字符串。
有关完整详细信息,请参见 IO#read
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 207 def read_nonblock(maxlen, buf=nil, exception: true) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? return sysread_nonblock(maxlen, buf, exception: exception) end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end
以非阻塞方式最多读取 *maxlen* 个字节。
当无法在不阻塞的情况下读取数据时,它会引发由 IO::WaitReadable
或 IO::WaitWritable
扩展的 OpenSSL::SSL::SSLError
。
IO::WaitReadable
表示 SSL
需要在内部读取,因此当底层 IO
可读时,应再次调用 read_nonblock
。
IO::WaitWritable
表示 SSL
需要在内部写入,因此在底层 IO
可写后,应再次调用 read_nonblock
。
OpenSSL::Buffering#read_nonblock
需要两个 rescue 子句,如下所示
# emulates blocking read (readpartial). begin result = ssl.read_nonblock(maxlen) rescue IO::WaitReadable IO.select([io]) retry rescue IO::WaitWritable IO.select(nil, [io]) retry end
请注意,read_nonblock
写入底层 IO
的一个原因是当对等方请求新的 TLS/SSL 握手时。有关更多详细信息,请参见 openssl 的 FAQ。 www.openssl.org/support/faq.html
通过将关键字参数 *exception* 指定为 `false`,您可以指示 read_nonblock
不应引发 IO::Wait*able 异常,而是返回符号 `:wait_writable` 或 `:wait_readable`。在 EOF 时,它将返回 `nil` 而不是引发 EOFError
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 111 def readbyte raise EOFError if eof? getbyte end
获取下一个 8 位字节。在 EOF 时引发 EOFError
来源
# File ext/openssl/lib/openssl/buffering.rb, line 317 def readchar raise EOFError if eof? getc end
从流中读取一个单字符字符串。在文件末尾引发 EOFError
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 291 def readline(eol=$/) raise EOFError if eof? gets(eol) end
从流中读取由 *eol* 分隔的一行。
如果在文件末尾,则引发 EOFError
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 278 def readlines(eol=$/) ary = [] while line = self.gets(eol) ary << line end ary end
从流中读取由 *eol* 分隔的行。
另请参见 gets
来源
# File ext/openssl/lib/openssl/buffering.rb, line 149 def readpartial(maxlen, buf=nil) if maxlen == 0 if buf buf.clear return buf else return "" end end if @rbuffer.empty? begin return sysread(maxlen, buf) rescue Errno::EAGAIN retry end end ret = consume_rbuff(maxlen) if buf buf.replace(ret) ret = buf end ret end
从流中最多读取 *maxlen* 个字节。如果提供了 *buf*,它必须引用将接收数据的字符串。
有关完整详细信息,请参见 IO#readpartial
。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 330 def ungetc(c) @rbuffer[0,0] = c.chr end
将字符 *c* 推回流,以便后续的缓冲字符读取将返回它。
与 IO#getc
不同,可以将多个字节推回流。
对非缓冲读取(例如 sysread)无效。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 381 def write(*s) s.inject(0) do |written, str| do_write(str) written + str.bytesize end end
将 *s* 写入流。如果参数不是 String
,则会使用 .to_s
方法进行转换。返回写入的字节数。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 425 def write_nonblock(s, exception: true) flush syswrite_nonblock(s, exception: exception) end
以非阻塞方式写入 *s*。
如果存在缓冲数据,则首先刷新它。这可能会阻塞。
write_nonblock
返回写入 SSL
连接的字节数。
当无法在不阻塞的情况下写入数据时,它会引发由 IO::WaitReadable
或 IO::WaitWritable
扩展的 OpenSSL::SSL::SSLError
。
IO::WaitReadable
表示 SSL
需要在内部读取,因此在底层 IO
可读后,应再次调用 write_nonblock
。
IO::WaitWritable
表示 SSL
需要在内部写入,因此在底层 IO
可写后,应再次调用 write_nonblock
。
因此,OpenSSL::Buffering#write_nonblock
需要两个 rescue 子句,如下所示。
# emulates blocking write. begin result = ssl.write_nonblock(str) rescue IO::WaitReadable IO.select([io]) retry rescue IO::WaitWritable IO.select(nil, [io]) retry end
请注意,write_nonblock
从底层 IO
读取的一个原因是当对等方请求新的 TLS/SSL 握手时。有关更多详细信息,请参见 openssl FAQ。 www.openssl.org/support/faq.html
通过将关键字参数 *exception* 指定为 `false`,您可以指示 write_nonblock
不应引发 IO::Wait*able 异常,而是返回符号 `:wait_writable` 或 `:wait_readable`。
私有实例方法
来源
# File ext/openssl/lib/openssl/buffering.rb, line 91 def consume_rbuff(size=nil) if @rbuffer.empty? nil else size = @rbuffer.size unless size @rbuffer.slice!(0, size) end end
从缓冲区消耗 *size* 个字节
来源
# File ext/openssl/lib/openssl/buffering.rb, line 353 def do_write(s) @wbuffer = Buffer.new unless defined? @wbuffer @wbuffer << s @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false buffer_size = @wbuffer.size if @sync or buffer_size > BLOCK_SIZE nwrote = 0 begin while nwrote < buffer_size do begin nwrote += syswrite(@wbuffer[nwrote, buffer_size - nwrote]) rescue Errno::EAGAIN retry end end ensure @wbuffer[0, nwrote] = "" end end end
将 *s* 写入缓冲区。当缓冲区已满或 sync
为 true 时,缓冲区将刷新到底层套接字。
来源
# File ext/openssl/lib/openssl/buffering.rb, line 78 def fill_rbuff begin @rbuffer << self.sysread(BLOCK_SIZE) rescue Errno::EAGAIN retry rescue EOFError @eof = true end end
从底层 SSLSocket 填充缓冲区