OpenSSL简介

对于OpenSSL而言,所有的XX_method都是通过类似这样的接口来完成对象的实例化、抽象回调函数的初始化等一些列的操作。如下为源码分析:

IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,DTLS_server_method,dtls1_accept,ssl_undefined_function,dtls1_get_server_method, DTLSv1_2_enc_data)如上宏完成DTLS_server_method函数对应的对象实例化,并将一系列的回调函数以函数指针的方式注册到该对象中。# define IMPLEMENT_dtls1_meth_func(version, func_name, s_accept, s_connect, \s_get_meth, enc_data) \
const SSL_METHOD *func_name(void)  \{ \static const SSL_METHOD func_name##_data= { \version, \dtls1_new, \dtls1_clear, \dtls1_free, \s_accept, \ //该回调完成握手操作s_connect, \ //该回调发起主动握手操作(ClientHello请求)ssl3_read, \ssl3_peek, \ssl3_write, \dtls1_shutdown, \ssl3_renegotiate, \ssl3_renegotiate_check, \dtls1_get_message, \dtls1_read_bytes, \dtls1_write_app_data_bytes, \dtls1_dispatch_alert, \dtls1_ctrl, \ssl3_ctx_ctrl, \ssl3_get_cipher_by_char, \ssl3_put_cipher_by_char, \ssl3_pending, \ssl3_num_ciphers, \dtls1_get_cipher, \s_get_meth, \dtls1_default_timeout, \&enc_data, \ssl_undefined_void_function, \ssl3_callback_ctrl, \ssl3_ctx_callback_ctrl, \}; \ssl_log(SSL_LOG_VEB, "%s enter ...\n", __FUNCTION__); \return &func_name##_data; \}

OpenSSL初始化

#include <openssl.h>static void openssl_log_format(int level, const char *file, int line, const char *msg)
{int openssl_level = 0;switch (level) {case SSL_LOG_ERR:openssl_level = OPENSSL_LOG_ERR;break;case SSL_LOG_WAR:openssl_level = OPENSSL_LOG_WAR;break;case SSL_LOG_NOT:openssl_level = OPENSSL_LOG_NOT;break;case SSL_LOG_DEB:openssl_level = OPENSSL_LOG_DEB;break;case SSL_LOG_VEB:openssl_level = OPENSSL_LOG_VEB;break;default:openssl_level = OPENSSL_LOG_DEB;break;}openssl_log(openssl_level, "[%s:%04d] %s", file, line, msg);
}void openssl_log_init(void)
{ssl_set_logger_cb(openssl_log_format);
}void openssl_log_vsprintf(int level, const char *file, int line, const char *format, ...)
{char *log_buffer = NULL;char *file_name = NULL;char *level_str = NULL;struct timeval tv_now;time_t tt;struct tm *t = NULL;va_list ap;va_start(ap, format);int ret = vasprintf(&log_buffer, format, ap);va_end(ap);if (file) {file_name = strrchr(file, '/');}switch (level) {case OPENSSL_LOG_ERR:level_str = "\033[31;1m  ERROR\33[0m";break;case OPENSSL_LOG_WAR:level_str = "\033[32;31;1mWARRING\33[0m";break;case OPENSSL_LOG_NOT:level_str = "\033[33;1m NOTICE\33[0m";break;case OPENSSL_LOG_DEB:level_str = "\033[32;1m  DEBUG\33[0m";break;case OPENSSL_LOG_VEB:level_str = "\033[32mVERBOSE\33[0m";break;default:level_str = "\033[32;1m  DEBUG\33[0m";break;}tt = time(NULL);t = localtime(&tt);gettimeofday(&tv_now, NULL);fprintf(stderr, "[%4d-%02d-%02d %02d:%02d:%02d:%03ld] %s [%05ld] -- %s:%d %s\n",t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv_now.tv_usec,level_str, syscall(SYS_gettid), file_name ? ++file_name : file, line, log_buffer);if (log_buffer) {free(log_buffer);}
}static void openssl_msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
{const char *str_write_p, *str_version, *str_content_type ="", *str_details1 = "", *str_details2 = "";char msg_buffer[65535] = {0};int msg_len = 0;str_write_p = write_p ? ">>>" : "<<<";switch (version) {case SSL2_VERSION:str_version = "SSL 2.0";break;case SSL3_VERSION:str_version = "SSL 3.0 ";break;case TLS1_VERSION:str_version = "TLS 1.0 ";break;case TLS1_1_VERSION:str_version = "TLS 1.1 ";break;case TLS1_2_VERSION:str_version = "TLS 1.2 ";break;case DTLS1_VERSION:str_version = "DTLS 1.0 ";break;case DTLS1_BAD_VER:str_version = "DTLS 1.0 (bad) ";break;default:str_version = "???";}if (version == SSL2_VERSION) {str_details1 = "???";if (len > 0) {switch (((const unsigned char *)buf)[0]) {case 0:str_details1 = ", ERROR:";str_details2 = " ???";if (len >= 3) {unsigned err =(((const unsigned char *)buf)[1] << 8) +((const unsigned char *)buf)[2];switch (err) {case 0x0001:str_details2 = " NO-CIPHER-ERROR";break;case 0x0002:str_details2 = " NO-CERTIFICATE-ERROR";break;case 0x0004:str_details2 = " BAD-CERTIFICATE-ERROR";break;case 0x0006:str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR";break;}}break;case 1:str_details1 = ", CLIENT-HELLO";break;case 2:str_details1 = ", CLIENT-MASTER-KEY";break;case 3:str_details1 = ", CLIENT-FINISHED";break;case 4:str_details1 = ", SERVER-HELLO";break;case 5:str_details1 = ", SERVER-VERIFY";break;case 6:str_details1 = ", SERVER-FINISHED";break;case 7:str_details1 = ", REQUEST-CERTIFICATE";break;case 8:str_details1 = ", CLIENT-CERTIFICATE";break;}}}if (version == SSL3_VERSION ||version == TLS1_VERSION ||version == TLS1_1_VERSION ||version == TLS1_2_VERSION ||version == DTLS1_VERSION ||version == DTLS1_2_VERSION ||version == DTLS1_BAD_VER) {switch (content_type) {case 20:str_content_type = "ChangeCipherSpec";break;case 21:str_content_type = "Alert";break;case 22:str_content_type = "Handshake";break;}if (content_type == 21) { /* Alert */str_details1 = ", ???";if (len == 2) {switch (((const unsigned char *)buf)[0]) {case 1:str_details1 = ", warning";break;case 2:str_details1 = ", fatal";break;}str_details2 = " ???";switch (((const unsigned char *)buf)[1]) {case 0:str_details2 = " close_notify";break;case 10:str_details2 = " unexpected_message";break;case 20:str_details2 = " bad_record_mac";break;case 21:str_details2 = " decryption_failed";break;case 22:str_details2 = " record_overflow";break;case 30:str_details2 = " decompression_failure";break;case 40:str_details2 = " handshake_failure";break;case 42:str_details2 = " bad_certificate";break;case 43:str_details2 = " unsupported_certificate";break;case 44:str_details2 = " certificate_revoked";break;case 45:str_details2 = " certificate_expired";break;case 46:str_details2 = " certificate_unknown";break;case 47:str_details2 = " illegal_parameter";break;case 48:str_details2 = " unknown_ca";break;case 49:str_details2 = " access_denied";break;case 50:str_details2 = " decode_error";break;case 51:str_details2 = " decrypt_error";break;case 60:str_details2 = " export_restriction";break;case 70:str_details2 = " protocol_version";break;case 71:str_details2 = " insufficient_security";break;case 80:str_details2 = " internal_error";break;case 90:str_details2 = " user_canceled";break;case 100:str_details2 = " no_renegotiation";break;case 110:str_details2 = " unsupported_extension";break;case 111:str_details2 = " certificate_unobtainable";break;case 112:str_details2 = " unrecognized_name";break;case 113:str_details2 = " bad_certificate_status_response";break;case 114:str_details2 = " bad_certificate_hash_value";break;case 115:str_details2 = " unknown_psk_identity";break;}}}if (content_type == 22) { /* Handshake */str_details1 = "???";if (len > 0) {switch (((const unsigned char *)buf)[0]) {case 0:str_details1 = ", HelloRequest";break;case 1:str_details1 = ", ClientHello";break;case 2:str_details1 = ", ServerHello";break;case 3:str_details1 = ", HelloVerifyRequest";break;case 11:str_details1 = ", Certificate";break;case 12:str_details1 = ", ServerKeyExchange";break;case 13:str_details1 = ", CertificateRequest";break;case 14:str_details1 = ", ServerHelloDone";break;case 15:str_details1 = ", CertificateVerify";break;case 16:str_details1 = ", ClientKeyExchange";break;case 20:str_details1 = ", Finished";break;}}}#ifndef OPENSSL_NO_HEARTBEATSif (content_type == 24) { /* Heartbeat */str_details1 = ", Heartbeat";if (len > 0) {switch (((const unsigned char *)buf)[0]) {case 1:str_details1 = ", HeartbeatRequest";break;case 2:str_details1 = ", HeartbeatResponse";break;}}}
#endif}msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1,"%s %s%s [length %04lx]%s%s\n", str_write_p, str_version,str_content_type, (unsigned long)len, str_details1, str_details2);if (len > 0) {size_t num, i;msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "   ");num = len;for (i = 0; i < num; i++) {if (i % 32 == 0 && i > 0) {msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "\n   ");}msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, " %02x", ((const unsigned char *)buf)[i]);}if (i < len) {msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", " ...");}msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "\n");}openssl_log(OPENSSL_LOG_DEB, "\n%s", msg_buffer);
}int openssl_init(void)
{SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();
}#define SERVER_CA   "ServerCAcert.pem"
#define SERVER_KEY  "ServerPrivkey.pem"#define CLIENT_CA   "ClientCAcert.pem"
#define CLIENT_KEY  "ClientPrivkey.pem"int openssl_load_cert_file(SSL_CTX *ctx, int csopt)
{if (csopt) {if (SSL_CTX_use_certificate_file(ctx, OPENSSL_SERVER_CA_PATH "/" SERVER_CA, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stdout);return -1;}if (SSL_CTX_use_PrivateKey_file(ctx, OPENSSL_SERVER_CA_PATH "/" SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stdout);return -1;}} else {if (SSL_CTX_use_certificate_file(ctx, OPENSSL_CLIENT_CA_PATH "/" CLIENT_CA, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stdout);return -1;}if (SSL_CTX_use_PrivateKey_file(ctx, OPENSSL_CLIENT_CA_PATH "/" CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stdout);return -1;}}if (!SSL_CTX_check_private_key(ctx)) {ERR_print_errors_fp(stdout);return -1;}return 0;
}static void openssl_info_callback(const SSL *s, int where, int ret)
{const char *str;int w;w = where & ~SSL_ST_MASK;if (w & SSL_ST_CONNECT) {str = "SSL_connect";} else if (w & SSL_ST_ACCEPT) {str = "SSL_accept";} else {str = "undefined";}if (where & SSL_CB_LOOP) {openssl_log(SSL_LOG_DEB, "%s: %s\n", str, SSL_state_string_long(s));} else if (where & SSL_CB_ALERT) {str = (where & SSL_CB_READ) ? "read" : "write";openssl_log(SSL_LOG_DEB, "SSL3 alert %s:%s:%s\n", str,SSL_alert_type_string_long(ret),SSL_alert_desc_string_long(ret));} else if (where & SSL_CB_EXIT) {if (ret == 0) {openssl_log(SSL_LOG_ERR, "%s:failed in %s\n", str, SSL_state_string_long(s));} else if (ret < 0) {openssl_log(SSL_LOG_ERR, "%s:error in %s\n", str, SSL_state_string_long(s));}}
}SSL_CTX *openssl_ctx_new(const SSL_METHOD *method)
{SSL_CTX *ctx = NULL;ctx = SSL_CTX_new(method);if (NULL == ctx) {ERR_print_errors_fp(stdout);return NULL;}SSL_CTX_set_info_callback(ctx, openssl_info_callback);return ctx;
}SSL *openssl_ssl_new(SSL_CTX *ctx)
{SSL *ssl = NULL;ssl = SSL_new(ctx);if (NULL == ssl) {return NULL;}SSL_set_msg_callback(ssl, openssl_msg_cb);SSL_set_msg_callback_arg(ssl, NULL);return ssl;
}int openssl_set_fd(SSL *ssl, int sockfd)
{return SSL_set_fd(ssl, sockfd);
}int openssl_accept(SSL *ssl)
{return SSL_accept(ssl);
}

Socket初始化

#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>#include <inet_sock.h>
#include <openssl.h>int init_nonblock(int fd)
{int flags = -1;if(flags = fcntl(fd, F_GETFL, 0) < 0) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}flags |= O_NONBLOCK;if(fcntl(fd, F_SETFL, flags) < 0) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}return 0;
}int init_sock(inet_sock_t sock, int type)
{return socket(sock, type, 0);
}int init_sockaddr(struct sockaddr *sockaddr, inet_sock_t sock, int sockfd, int utopt, int csopt)
{struct sockaddr_in addr;int on = 1;memset(&addr, 0, sizeof(addr));addr.sin_family = sock;if (csopt) {addr.sin_port = htons(7838);addr.sin_addr.s_addr = INADDR_ANY;} else {addr.sin_port = htons(7838);if (!inet_aton("127.0.0.1", (struct in_addr *)&addr.sin_addr.s_addr)) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}}if (sockaddr) {memcpy(sockaddr, &addr, sizeof(addr));}if (csopt) {if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr))) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}openssl_log(OPENSSL_LOG_NOT, "Bind sockaddr: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));}if (utopt) {if (listen(sockfd, 100)) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}} else {if (!csopt) {if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr))) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}openssl_log(OPENSSL_LOG_NOT, "Connect sockaddr: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));}}return 0;
}int init_udp_sockaddr(struct sockaddr *sockaddr, inet_sock_t sock, int sockfd, int csopt)
{struct sockaddr_in addr;int on = 1;memset(&addr, 0, sizeof(addr));addr.sin_family = sock;if (csopt) {addr.sin_port = htons(7838);addr.sin_addr.s_addr = INADDR_ANY;} else {addr.sin_port = htons(7838);if (!inet_aton("127.0.0.1", (struct in_addr *)&addr.sin_addr.s_addr)) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}}if (sockaddr) {memcpy(sockaddr, &addr, sizeof(addr));}if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}if (csopt) {if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr))) {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));return -1;}openssl_log(OPENSSL_LOG_NOT, "Bind sockaddr: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));}return 0;
}int init_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{return accept(sockfd, addr, addrlen);
}-

OpenSSL DTLS Client端

#include <openssl.h>
#include <inet_sock.h>int main(int argc, char **argv)
{SSL_CTX * ctx = NULL;int sockfd = -1;socklen_t socklen = 0;struct sockaddr_in their_addr;struct sockaddr peer;SSL *ssl = NULL;int retval = -1;char readbuf[65535] = {0};BIO *sbio = NULL;int try = 0;openssl_log_init();openssl_init();ctx = openssl_ctx_new(DTLS_method());if (NULL == ctx) {goto error;}if (openssl_load_cert_file(ctx, 0)) {goto error;}sockfd = init_sock(SOCK_AF_INET, SOCK_DGRAM);if (sockfd < 0) {goto error;}if (init_sockaddr((struct sockaddr *)&their_addr, SOCK_AF_INET, sockfd, 0, 0)) {goto error;}ssl = openssl_ssl_new(ctx);if (NULL == ssl) {goto error;}sbio = BIO_new_dgram(sockfd, BIO_NOCLOSE);if (NULL == sbio) {goto error;}BIO_ctrl_set_connected(sbio, 1, &peer);SSL_set_bio(ssl, sbio, sbio);SSL_set_connect_state(ssl);while (try++ < 10) {snprintf(readbuf, sizeof(readbuf) - 1, "%s", "This is a DTLS client!\n");retval = SSL_write(ssl, readbuf, strlen(readbuf));if (retval > 0) {openssl_log(OPENSSL_LOG_DEB, "Write '%d' bytes to '%s:%d'\n", retval, inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port));sleep(1);} else {openssl_log(OPENSSL_LOG_ERR, "%s\n", strerror(errno));sleep(1);}}return 0;error:if (sockfd > 0) {close(sockfd);}if (ctx) {SSL_CTX_free(ctx);}
}

OpenSSL DTLS Server端

#include <poll.h>
#include <errno.h>
#include <string.h>#include <openssl.h>
#include <inet_sock.h>int main(int argc, char **argv)
{SSL_CTX * ctx = NULL;int sockfd = -1;socklen_t socklen = 0;struct sockaddr_in my_addr, their_addr;SSL *ssl = NULL;int retval = -1;char readbuf[65535] = {0};BIO * sbio = NULL;int read_from_sslcon = -1;struct pollfd fds = {0};struct timeval timeout;openssl_log_init();openssl_init();ctx = openssl_ctx_new(DTLS_server_method());if (NULL == ctx) {goto error;}if (openssl_load_cert_file(ctx, 1)) {goto error;}sockfd = init_sock(SOCK_AF_INET, SOCK_DGRAM);if (sockfd < 0) {goto error;}if (init_sockaddr((struct sockaddr *)&my_addr, SOCK_AF_INET, sockfd, 0, 1)) {goto error;}ssl = openssl_ssl_new(ctx);if (NULL == ssl) {goto error;}sbio = BIO_new_dgram(sockfd, BIO_NOCLOSE);if (NULL == sbio) {goto error;}timeout.tv_sec = 0;timeout.tv_usec = 250000;BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);timeout.tv_sec = 0;timeout.tv_usec = 250000;BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);SSL_set_bio(ssl, sbio, sbio);SSL_set_accept_state(ssl);while (1) {memset(&fds, 0, sizeof(fds));fds.fd = sockfd;fds.events = POLLIN;retval = poll(&fds, 1, 10000);if (retval && (fds.revents & POLLIN)) {read_from_sslcon = SSL_read(ssl, readbuf, sizeof(readbuf) - 1);if (read_from_sslcon > 0) {if (!SSL_is_init_finished(ssl)) {openssl_log(OPENSSL_LOG_WAR, "SSL init failure ...\n");continue;}BIO_dgram_get_peer(sbio, &my_addr);openssl_log(OPENSSL_LOG_DEB, "Read %d bytes from '%s:%d', %s\n", read_from_sslcon,inet_ntoa(my_addr.sin_addr), ntohs(my_addr.sin_port), readbuf);}}}return 0;error:if (sockfd > 0) {close(sockfd);}if (ctx) {SSL_CTX_free(ctx);}
}

OpenSSL DTLS通信(一)相关推荐

  1. openssl 的 tls 命令和相关使用心得

    声明:本文基于 openssl 1.1.1f 版本 服务端: Usage: s_server [options] Valid options are:-help Display this summar ...

  2. 网络安全技术与应用实验——SSL验证分析 基于DTLS的安全服务器设计

    1. SSL验证分析 实验目的:通过实验,掌握SSL的基本原理,掌握扫描器的基本原理和基本工具Wireshark的使用. 实验内容:使用Wireshark工具分析TCP连接中主机和服务器之间传输SSL ...

  3. 开源项目SMSS发开指南(四)——SSL/TLS加密通信详解

    本文将详细介绍如何在Java端.C++端和NodeJs端实现基于SSL/TLS的加密通信,重点分析Java端利用SocketChannel和SSLEngine从握手到数据发送/接收的完整过程.本文也涵 ...

  4. 网安技术与应用(2)——基于DTLS的安全服务器设计

    一 实验目的 通过实验,掌握DTLS的基本原理,掌握python3-dtls库的基本使用. 二 实验内容 利用 DTLS 库编写客户端和服务器程序,服务端开启监听,提供数据传输.文件传输功能: 客户端 ...

  5. Ubuntu下搭建Janus Server

    Ubuntu下搭建Janus Server 目录 Janus简介 下载和编译 Janus 配置和运行janus 视频通话联调测试 1. Janus简介 Janus 是一个开源的,通过 C 语言实现了对 ...

  6. raspberry ubuntu 修改源为清华_Ubuntu 下 Janus Server 搭建笔记

    1 Ubuntu 下 Janus Server 搭建笔记 QQ交流群 782508536 FFmpeg/WebRTC/RTMP音视频流媒体高级开发 https://ke.qq.com/course/4 ...

  7. 服务器系统及软件常见漏洞

    漏洞名称 允许Traceroute探测 远端WWW服务支持TRACE请求 远端WWW服务提供了对WebDAV的支持 远端WEB服务器上存在/robots.txt文件 远端VNC服务正在运行 远端HTT ...

  8. Ubuntu 下 Janus Server 搭建笔记

    1 简介 Janus 是一个开源的,通过 C 语言实现了对 WebRTC 支持的 Gateway:Janus 自身实现得很简单,提供插件机制来支持不同的业务逻辑,配合官方自带插件就可以用来实现高效的 ...

  9. webRTC服务器搭建(基于Janus)与Demo运行

    原文网址:https://blog.csdn.net/newchenxf/article/details/110451532 转载请注明出处^^ 前言 2020年,直播带货不要太火,直播的方案基于啥? ...

最新文章

  1. js日期的初始化的格式
  2. 映射技术之储存器映射
  3. MSCRM二次开发实现自动编号功能
  4. Redis 持久化——AOF
  5. git tag和分支的区别_GIT常用命令大全
  6. Lucene 和 Elastic
  7. iOS开发:AVPlayer实现流音频边播边存
  8. mariadb驱动下载教程_性能测试教程[3] nmon analyser
  9. linux 批量解压war,图文处理war包解压【搞定方式】
  10. 基因结构图的0_在线网站绘制基因结构图!
  11. 神器win7系统登录服务器失败原因,Win7系统提示加载dll失败“五种解决方法(图文)...
  12. 去中心化通信简易方案
  13. 在lomboz eclipse 3.3中配置tomcat7/8 server运行时环境遇到的问题
  14. VB.NET 文本框获得焦点
  15. 各类牛B电影,暑假慢慢看完
  16. anaconda 代码提示,Anaconda安装OpenCV没有自动代码补全
  17. C语言实现实数和复数矩阵及其各种运算(一)
  18. Linux 驱动开发研究
  19. CSS弹性布局网格布局
  20. 计算机网络常用术语WWW,计算机网络常用术语中英文对照表

热门文章

  1. 《概率论与数理统计》之事件的相互关系及运算
  2. IntentFilter简述
  3. 生成订单编号,编号格式(由编号类型编码+编号创建平台编码+6位日期+时间戳后4位+4位随机数组成),生成四位或者N位随机数字
  4. Html和Css的理解
  5. zero:seo技术领域的搜索引擎优化指南
  6. C# FileSystemWatcher使用说明
  7. linux国产操作系统下载网站,三分钟快速安装国产操作系统Ylmf OS
  8. HCL模拟器中Server设备启动失败的解决办法
  9. 9-斐波拉契数列解法归纳
  10. android5.1 MT6735 编译过程