openssl处理非阻塞socket
来源:互联网 发布:catia软件旋转快捷键 编辑:程序博客网 时间:2024/04/28 12:24
openssl处理非阻塞socket
上篇博文是使用libevent加入ssl功能:
http://blog.csdn.net/fly2010love/article/details/46459485
文中说道,在处理非阻塞socket时需要注意的地方SSL_accept SSL_read SSL_wirte,本篇博文专门介绍如何处理socket在非阻塞下openssl如何处理
有网络程序开发经验的人都知道一个很头疼的问题,那就是在非阻塞的socket下
如果使用事件驱动epoll的ET模式下,在读数据时,若一次没有全部读取,
下次事件将要等到客户端再次发送数据时才会触发,那么这就存在一个问题,
如果客户端不在发送数据了,那么这个链接就废了,本来内核缓冲区还有数据,
并且加上之前读到的数据刚好是一个完整的请求,由于在事件触发时没有一次性
读取完,所以导致了业务处理上检查包的时认为包接收不完整,所以在等待下次
数据接收回调,SSL在非阻塞时同样存在这个问题,并且在accept时也会存在同样的
问题,下面就此问题来进行解决,可能存在一些处理不够完善,欢迎大家吐槽指正
非阻塞socket下SSL_accept处理:
这是上篇博文一样的将socket附加到SSL上的函数,请注意SSL_accept的处理
SSL* CEventBaseMgr::CreateSSL(evutil_socket_t& fd){ if (!CConfiger::GetInstance()->GetEnableSSL()) { return NULL; } SSL_CTX* ctx = NULL; SSL* ssl = NULL; ctx = SSL_CTX_new (SSLv23_method()); if( ctx == NULL) { printf("SSL_CTX_new error!\n"); return NULL; } // 要求校验对方证书 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); // 加载CA的证书 if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) { SSL_CTX_free(ctx); printf("SSL_CTX_load_verify_locations error!\n"); return NULL; } // 加载自己的证书 if(SSL_CTX_use_certificate_file(ctx, SERVER_CERT_FILE, SSL_FILETYPE_PEM) <= 0) { SSL_CTX_free(ctx); printf("SSL_CTX_use_certificate_file error!\n"); return NULL; } // 加载自己的私钥 if(SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_FILE, SSL_FILETYPE_PEM) <= 0) { SSL_CTX_free(ctx); printf("SSL_CTX_use_PrivateKey_file error!\n"); return NULL; } // 判定私钥是否正确 if(!SSL_CTX_check_private_key(ctx)) { SSL_CTX_free(ctx); printf("SSL_CTX_check_private_key error!\n"); return NULL; } // 将连接付给SSL ssl = SSL_new (ctx); if(!ssl) { SSL_CTX_free(ctx); printf("SSL_new error!\n"); return NULL; } SSL_set_fd(ssl, fd); bool isContinue = true; while(isContinue) { isContinue = false; if(SSL_accept(ssl) != 1) { int icode = -1; int iret = SSL_get_error(ssl, icode); if (iret == SSL_ERROR_WANT_READ) { isContinue = true; } else { SSL_CTX_free(ctx); SSL_free(ssl); ctx = NULL; ssl = NULL; break; } } else break; } return ssl;}
这一段处理中
bool isContinue = true; while(isContinue) { isContinue = false; if(SSL_accept(ssl) != 1) { int icode = -1; int iret = SSL_get_error(ssl, icode); if (iret == SSL_ERROR_WANT_READ) { isContinue = true; } else { SSL_CTX_free(ctx); SSL_free(ssl); ctx = NULL; ssl = NULL; break; } } else break; }
我们使用一个循环来进行处理,因为非阻塞时,socket的SSL底层进行身份和密钥证书协商是socket同样是阻塞的,故通过判断SSL_accept的返回值和SSL_get_error(ssl, icode);的返回值来确定是真的
出现错误,还是没用完成accept等验证操作,accept也是一个socket可读事件
所以判断事件的类型是:SSL_ERROR_WANT_READ,具体可查看SSL_accept的帮助文档
非阻塞socket下SSL_read处理:
int SslRecv(SSL* ssl, char* buffer, int ilen){ int ires = 0, count = 0;; bool isCoutinue = true; while (isCoutinue) { ires = SSL_read(ssl, buffer + count, ilen - count); int nRes = SSL_get_error(ssl, ires); if(nRes == SSL_ERROR_NONE) { if(ires > 0) { count += ires; if (count >= ilen) { break; } continue; } } else { break; } } return count;}
理论同上,通过判断SSL_get_error 的返回值来判断读是否出错,并且判断缓冲区
的大小,若缓冲区足够大,且读回来的数据大于0,表示可能还有数据未读取完成
需要偏移缓冲区,继续读取。
非阻塞socket下SSL_write处理:
int SslSend(SSL* ssl, const char* buffer, int ilen){ int ires = 0, count = 0;; bool isCoutinue = true; while (isCoutinue) { ires = SSL_write(ssl, buffer + count, ilen - count); int nRes = SSL_get_error(ssl, ires); if(nRes == SSL_ERROR_NONE) { if(ires > 0) { if (count >= ilen) { break; } count += ires; continue; } } else if (nRes == SSL_ERROR_WANT_READ) { continue; } else { break; } } return count;}
在发送过程中处理也是类似,通过判断相应的返回值和错误码来判断发送
是否失败,在这里有个疑惑:
else if (nRes == SSL_ERROR_WANT_READ) { continue; }
这一段代码中,加入了一个判断SSL_ERROR_WANT_READ事件类型,有些想不通的
是,按理说应该是这个事件:SSL_ERROR_WANT_WRITE,但在调试过程中发现
返回确实SSL_ERROR_WANT_READ,本人暂时的理解是:socekt链接成功
以后应该是SSL_get_error在socket正常连接过程中都是SSL_ERROR_WANT_READ
状态,忘有高手来解答疑惑,或者后面有时间自己在深入了解和调试试试
结束语:
关于openssl的相关编程就告一段路了,后续有时间将继续更新关于libevent
使用的技巧和相关需要注意的地方,相关文章只供参考,有相关处理不当的地方
请读者自行优化处理。
- openssl处理非阻塞socket
- openssl处理非阻塞socket
- 非阻塞Socket连接处理
- 阻塞非阻塞socket
- socket阻塞,非阻塞
- 非阻塞/异步(epoll) openssl
- 非阻塞/异步(epoll) openssl
- openssl 使用非阻塞 bio
- 非阻塞/异步(epoll) openssl
- Socket的阻塞/非阻塞
- Socket的阻塞/非阻塞
- Socket的阻塞/非阻塞
- Socket的阻塞/非阻塞
- socket阻塞非阻塞区别
- Socket的阻塞/非阻塞
- Socket的阻塞/非阻塞
- socket 阻塞和非阻塞
- 阻塞非阻塞socket设置
- Iptables模块recent应用
- jquery开发之代码风格
- 利用推特工具进行分词
- 安卓中的Model-View-Presenter模式介绍
- 删除数据库中重复记录的SQL语句
- openssl处理非阻塞socket
- Java项目如何记录日志
- 认识自己——人活着要做的第一件事
- JavaScript学习总结-技巧、实用函数、简洁方法、编程细节
- Android开发getCacheDir和getFilesDir区别
- java实现任意进制的互相转换
- JavaScript面向对象编程——构造函数继承
- 就地交换两个数的值
- 苹果在中国面临的挑战:让用户为下载付费