Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets OpenSSL阻塞套接字SSL_读取块_Sockets_Ssl_Openssl_Blocking - Fatal编程技术网

Sockets OpenSSL阻塞套接字SSL_读取块

Sockets OpenSSL阻塞套接字SSL_读取块,sockets,ssl,openssl,blocking,Sockets,Ssl,Openssl,Blocking,我在OpenSSL连接中使用阻塞套接字。SSL_读取块有时会持续几秒钟。在服务器中,BIO_写入用于发送可变缓冲区大小的数据。在客户端中,第一次SSL_读取以获取缓冲区大小成功,但在SSL_读取后几秒钟内获取缓冲区数据块(此问题在2到3分钟后模拟),即使数据发送成功。我等待poll()调用客户端读取函数。如何纠正阻塞套接字中的这些问题 服务器代码 void process_and_send() { // sending variable size buffer each time

我在OpenSSL连接中使用阻塞套接字。SSL_读取块有时会持续几秒钟。在服务器中,BIO_写入用于发送可变缓冲区大小的数据。在客户端中,第一次SSL_读取以获取缓冲区大小成功,但在SSL_读取后几秒钟内获取缓冲区数据块(此问题在2到3分钟后模拟),即使数据发送成功。我等待poll()调用客户端读取函数。如何纠正阻塞套接字中的这些问题

服务器代码

void process_and_send() {
     // sending variable size buffer each time
     // sbuf - first 4 bytes contains sbuf size information
     send_data(sbuf, sbufSize);
}


void send_data(void *sbuf, int pending_len) {
        while(pending_len > 0) {
                result = BIO_write(bio, sbuf, pending_len);
                if(result == 0) {
                        attempts = 0;
                        LOG_D("%s", log_str(SSL_CONN_CLOSE));
                        SSL_FN_TRACE("connection closed\n");
                        break;
                }
                else if(result < 0) {
                        LOG_I("%s", log_str(SSL_WRITE_FAIL));
                        SSL_FN_TRACE("BIO_write fail\n");
                        if(errno == EINTR) {
                                continue;
                        }
                        if(errno == EAGAIN) {
                                attempts++;
                                continue;
                        }
                        if(errno == EWOULDBLOCK) {
                                attempts++;
                                continue;
                        }
                        break;
                }
                else {
                        BIO_flush(bio);
                        pending_len -= result;
                        sbuf += result;
                }
        }  
 }
void进程和发送(){
//每次发送可变大小的缓冲区
//sbuf-前4个字节包含sbuf大小信息
发送_数据(sbuf、sbufSize);
}
void发送数据(void*sbuf,int待定){
同时(挂起时间>0){
结果=BIO_写入(BIO、sbuf、待处理_len);
如果(结果==0){
尝试次数=0;
LOG_D(“%s”,LOG_str(SSL_CONN_CLOSE));
SSL_FN_跟踪(“连接已关闭”);
打破
}
否则如果(结果<0){
日志I(“%s”,日志str(SSL写入失败));
SSL_FN_跟踪(“BIO_写入失败\n”);
如果(errno==EINTR){
继续;
}
if(errno==EAGAIN){
尝试++;
继续;
}
if(errno==ewoldblock){
尝试++;
继续;
}
打破
}
否则{
生物冲洗(BIO);
待定项-=结果;
sbuf+=结果;
}
}  
}
客户端代码

// wait on poll() and call receive_and_process
void receive_and_process() {
     int rbufSize = 0;
     // get the size of data to read
     receive_data((void *)&rbufSize, sizeof(Int));
     // this call blocks for few seconds
     receive_data(rbuf, rbufSize);
}

void receive_data(void *rbuf, int pending_len) {
    while(pending_len > 0) {
                    result = SSL_read(ssl, rbuf, pending_len);
            if(result == 0) {
                    LOG_D("%s", log_str(SSL_CONN_CLOSE));
                    SSL_FN_TRACE("connection closed\n");
                    return NULL;
            }
            else if(result < 0) {
                    if(errno == ETIMEDOUT) {
                            SSL_FN_ERROR("SSL read timeout:  \n");
                            continue;
                    }
                    if(errno == EINTR) {
                            continue;
                    }
                    if(errno == EAGAIN) {
                            continue;
                    }
                    if(errno == EWOULDBLOCK) {
                            continue;
                    }

                    SSL_FN_ERROR("SSL read fail error no:  %s\n",
                                    ERR_reason_error_string(ERR_get_error()));
                    LOG_I("%s", log_str(SSL_READ_FAIL));
                    return NULL;
            }
            pending_len -= result;
            rbuf += result;
            FN_ERROR("after read full data pending len %d\n", pending_len);
    }
}
//等待poll()并调用receive\u和\u进程
无效接收_和_过程(){
int rbufSize=0;
//获取要读取的数据的大小
接收_数据((void*)&rbufSize,sizeof(Int));
//此呼叫中断几秒钟
接收_数据(rbuf、rbufSize);
}
无效接收数据(无效*rbuf,整数待定){
同时(挂起时间>0){
结果=SSL读取(SSL、rbuf、待定项);
如果(结果==0){
LOG_D(“%s”,LOG_str(SSL_CONN_CLOSE));
SSL_FN_跟踪(“连接已关闭”);
返回NULL;
}
否则如果(结果<0){
if(errno==ETIMEDOUT){
SSL_FN_错误(“SSL读取超时:\n”);
继续;
}
如果(errno==EINTR){
继续;
}
if(errno==EAGAIN){
继续;
}
if(errno==ewoldblock){
继续;
}
SSL\u FN\u错误(“SSL读取失败错误号:%s\n”,
ERR_reason_error_string(ERR_get_error());
日志I(“%s”,日志str(SSL读取失败));
返回NULL;
}
待定项-=结果;
rbuf+=结果;
FN\u错误(“读取完整数据后,挂起长度%d\n”,挂起长度);
}
}

首先,您的客户机代码无法按照所示进行编译,因为
receive_data()
具有
void
返回类型,因此
return NULL
是编译器错误。此外,不能在
void*
指针上使用
+=
运算符,这也是一个编译器错误

除此之外,如果
SSL\u read()
返回<0,则需要使用
SSL\u get\u error()
而不是
errno
来找出失败的原因。不要使用
errno
,除非
SSL\u get\u error()
返回
SSL\u error\u SYSCALL
。如果
SSL\u get\u error()
返回
SSL\u error\u SSL
,请改用
ERR\u get\u error()
和相关函数。另外,请确保您正在处理
SSL\u错误\u希望\u读取
SSL\u错误\u希望\u写入
错误

此外,在发送多字节整数时,如果要跨机器边界发送,则必须处理endian问题。最好使用诸如
htonl()
ntohl()
之类的函数通过网络字节顺序发送整数

尝试类似以下内容:

服务器:

void process_and_send() {
     // sending variable size buffer each time
     // sbuf - DO NOT store the size information in the first 4 bytes!
     //        handle the size separately...
     int32_t size = htonl(sbufSize);
     if (send_data(&size, sizeof(size)))
         send_data(sbuf, sbufSize);
}

bool send_data(void *sbuf, int pending_len) {
    unsigned char *pbuf = (unsigned char *) sbuf;
    while (pending_len > 0) {
        result = BIO_write(bio, pbuf, pending_len);
        if (result > 0) {
            BIO_flush(bio);
            pbuf += result;
            pending_len -= result;
        }
        else if (result == 0) {
            attempts = 0;
            LOG_D("%s", log_str(SSL_CONN_CLOSE));
            SSL_FN_TRACE("connection closed\n");
            return false;
        }
        else if (!BIO_should_retry(bio)) {
            LOG_I("%s", log_str(SSL_WRITE_FAIL));
            SSL_FN_TRACE("BIO_write fail\n");
            return false;
        }
        else {
            ++attempts;
        }
    }  
    return true;
}
客户:

// wait on poll() and call receive_and_process
void receive_and_process() {
     int32_t rbufSize = 0;
     // get the size of data to read
     if (receive_data(&rbufSize, sizeof(rbufSize))) {
         rbufSize = ntohl(rbufSize);
         // TODO: make sure rbuf is at least rbufSize in size...
         receive_data(rbuf, rbufSize);
     }
}

bool receive_data(void *rbuf, int pending_len) {
    unsigned char *pbuf = (unsigned char *) rbuf;
    while (pending_len > 0) {
        result = SSL_read(ssl, pbuf, pending_len);
        if (result > 0) {
            pbuf += result;
            pending_len -= result;
            FN_ERROR("after read full data pending len %d\n", pending_len);
        }
        else {
            result = SSL_get_error();
            if (result == SSL_ERROR_ZERO_RETURN) {
                LOG_D("%s", log_str(SSL_CONN_CLOSE));
                SSL_FN_TRACE("connection closed\n");
            }
            else {
                if (result == SSL_ERROR_WANT_READ) {
                    // TODO: use select() to wait for the socket to be readable before trying again...
                    continue;
                }
                else if (result == SSL_ERROR_WANT_WRITE) {
                    // TODO: use select() to wait for the socket to be writable before trying again...
                    continue;
                }
                else if (result == SSL_ERROR_SYSCALL) {
                    if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                        continue;
                    }

                    if (errno == ETIMEDOUT) {
                        SSL_FN_ERROR("SSL read timeout:  \n");
                        continue;
                    }

                    SSL_FN_ERROR("SSL read fail error no:  %d\n", errno);
                }
                else if (result == SSL_ERROR_SSL) {
                    SSL_FN_ERROR("SSL read fail error no:  %s\n",
                        ERR_reason_error_string(ERR_get_error()));
                }
                else {
                    SSL_FN_ERROR("SSL read fail error no:  %d\n", result);
                }
                LOG_I("%s", log_str(SSL_READ_FAIL));
            }
            return false;
        }
    }
    return true;
}

我同意。通过阻塞插座块进行I/O。你的问题?为什么它会阻塞?即使数据发送成功。谢谢雷米。正如你提到的,我对代码做了更改。但SSL_读取块有时会超过2000毫秒,即使数据发送成功。@ArunrajShanmugam那么您可能没有以正确的格式读取数据。如果请求的字节数超过实际发送的字节数,例如如果误读数据大小,则阻塞读取将被阻塞。仔细检查您的读取逻辑OK I will debug,当服务器从多个客户端接收数据时,经常会模拟此问题。它看起来像读取调用,以获取数据的大小
receive_data(&rbufSize,sizeof(rbufSize)))
本身会阻塞几秒钟。