读写出错控制
—根据openssldoc/crypto/bio/bio_should_retry.pod翻译和自己的理解写成
(作者:DragonKingMail:wzhah@263.net发布于:之open
ssl专业论坛)
当BIO_read或BIO_write函数调用出错的时候,,BIO本身提供了一组出错原因的诊断
函数,他们定义如下(openssl/bio.h):
#defineBIO_should_read(a)((a)->flags&BIO_FLAGS_READ)
#defineBIO_should_write(a)((a)->flags&BIO_FLAGS_WRITE)
#defineBIO_should_io_special(a)((a)->flags&BIO_FLAGS_IO_SPECIAL)
#defineBIO_retry_type(a)((a)->flags&BIO_FLAGS_RWS)
#defineBIO_should_retry(a)((a)->flags&BIO_FLAGS_SHOULD_RETRY)
#defineBIO_FLAGS_READ0x01
#defineBIO_FLAGS_WRITE0x02
#defineBIO_FLAGS_IO_SPECIAL0x04
#defineBIO_FLAGS_RWS(BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPEC
IAL)
#defineBIO_FLAGS_SHOULD_RETRY0x08
BIO*BIO_get_retry_BIO(BIO*bio,int*reason);
intBIO_get_retry_reason(BIO*bio);
因为这些函数是用于决定为什么BIO在读写数据的时候不能读出或写入数据,所以他
们一般也是在执行BIO_read或BIO_write操作之后被调用的。
【BIO_should_retry】
如果读写出错的情况是要求程序稍后重试,那么该函数返回true.如果该函数返回f
alse,这时候判定错误情况就要根据BIO的类型和BIO操作的返回值来确定了。比如,如
果对socket类型的BIO调用BIO_read操作并且返回值为0,此时BIO_should_retry返回fa
lse就说明socket连接已经关闭了。而如果是file类型的BIO出现这样的情况,那说明就
是读到文件eof了。有些类型BIO还会提供更多的出错信息,具体情况参见各自的说明。
如果BIO下层I/O结构是阻塞模式的,那么几乎所有(SSL类型BIO例外)BIO类型都不
会返回重试的情况(就是说调用BIO_should_retry不会返回true),因为这时候对下层
I/O的调用根本不会进行。所以建议如果你的应用程序能够判定该类型BIO在执行IO操作
后不会出现重试的情况时,就不要调用BIO_should_retry函数。file类型BIO就是这样的
一个典型例子。
SSL类型的BIO是上述规则的唯一例外,也就是说,既便在阻塞型的I/O结构中,如果
在调用BIO_read的时候发生了握手的过程,它也能会返回重试要求(调用BIO_should_r
etry返回true)。在这种情况下,应用程序可以立刻重新执行失败的I/O操作,或者在底
层的I/O结构中设置为SSL_MODE_AUTO_RETRY,那么就可以避免出现这种失败的情况。
如果应用程序在非阻塞型BIO中调用IO操作失败后立刻重试,那么可能导致效率很低
,因为在数据允许读取或有效之前,调用会重复返回失败结果。所以,正常的应用应该
是等到需要的条件满足之后,程序才执行相关的调用,至于具体怎么做,就跟底层的IO
结构有关了。例如,如果一个底层IO是一个soket,并且BIO_should_retry返回true,那
么可以调用select()来等待数据有效之后再重试IO操作。在一个线程中,可以使用一个
select()来处理多个非阻塞型的BIO,不过,这时候执行效率可能出现非常低的情况,比
如如果其中一个延时很长的SSL类型BIO在握手的时候就会导致这种情况。
在阻塞型的IO结构中,对数据的读取操作可能会导致无限期的阻塞,其情况跟系统
的IO结构函数有关。我们当然不期望出现这种情况,解决的办法之一是尽量使用非阻塞
型的IO结构和使用select函数(或equivalent)来设置等待时间。
【BIO_should_read】
该函数返回true如果导致IO操作失败的原因是BIO此时要读数据。
【BIO_should_write】
该函数返回true如果导致IO操作失败的原因是BIO此时要写数据。
【BIO_should_io_special】
该函数返回true如果导致IO操作失败的原因是特殊的(也就是读写之外的原因)
【BIO_get_retry_reason】
返回失败的原因,其代码包括BIO_FLAGS_READ,BIO_FLAGS_WRITE和BIO_FLAGS_IO_
SPECIAL。目前的BIO类型只返回其中之一。如果输入的BIO是产生特殊出错情况的BIO,
那么该函数返回错误的原因代码,就跟BIO_get_retry_BIO()返回的reason一样。
【BIO_get_retry_BIO】
该函数给出特殊情况错误的简短原因,它返回出错的BIO,如果reason不是设置为N
ULL,它会包含错误代码,错误码的含义以及下一步应该采取的处理措施应该根据发生这
种情况下各种BIO的类型而定。
充满了恐惧的声音,一种不确定的归宿的流动。