基于GmSSL实现server服务端和client客户端之间SSL通信代码(升级优化公开版)

2023-05-16

参考链接

工程搭建介绍

  • Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本_MY CUP OF TEA的博客-CSDN博客
  • CLion运行程序时添加命令行参数 即设置argv输入参数_MY CUP OF TEA的博客-CSDN博客
  • 基于SM2证书实现SSL通信_MY CUP OF TEA的博客-CSDN博客
  • 基于Gmssl库静态编译,实现服务端和客户端之间的SSL通信_MY CUP OF TEA的博客-CSDN博客
  • 基于openssl和国密算法生成CA、服务器和客户端证书_MY CUP OF TEA的博客-CSDN博客
  • openssl实现双向认证教程(服务端代码+客户端代码+证书生成)_MY CUP OF TEA的博客-CSDN博客
  • mac系统使用 clion远程调试redis4源码_迹忆客  target_link_libraries

相关函数介绍

  • dtls到srtp的整个流程_小狮子slioner的博客-CSDN博客
  • dtls_srtp学习笔记_weixin_30779691的博客-程序员宅基地 - 程序员宅基地   SSL_export_keying_material
  • C语言inet_aton()函数:将网络地址转成网络二进制的数字_C语言中文网  
  • /docs/man1.0.2/man3/SSL_CTX_set_mode.html
  • /docs/man1.0.2/man3/SSLeay_add_ssl_algorithms.html

Server

层次结构

  • lib存放静态编译gmssl代码生成的静态库,即libssl.a和libcrypto.a
  • pem存放证书文件,因为SSL双向验证,服务端会验证客户端的证书,因此服务端存放客户端的证书和私钥,以及生成客户端证书时用于签名的ca证书

Code

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAXBUF 1500

void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    // SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
    // 如果验证不通过,那么程序抛出异常中止连接
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        printf("证书验证通过\n");
    }
    if (cert != nullptr) {
        printf("数字证书信息:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
        printf("证书: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
        printf("颁发者: %s\n", line);
        free(line);
        X509_free(cert);
    } else
        printf("无证书信息!\n");
}

int main(int argc, char **argv) {
    int listen_fd = -1; /* TCP监听套接字 */
    int accept_fd = -1; /* 已连接TCP套接字 */
    struct sockaddr_in server_addr, client_addr;
    bzero(&server_addr, sizeof(server_addr));

    SSL_CTX *ctx = nullptr; /* SSL会话环境 */
    SSL *ssl = nullptr; /* SSL安全套接字 */
    socklen_t len;
    char buf[MAXBUF]={0};  /* 服务器接收数据buffer */


    if( 3!=argc )
    {
        printf("argcment wrong:ip port\n");
    }

    SSL_library_init(); /* SSL 库初始化 */
    SSLeay_add_ssl_algorithms();
    OpenSSL_add_all_algorithms();  /* 载入所有 SSL 算法 */
    SSL_load_error_strings(); /* 载入所有 SSL 错误消息 */
//    ERR_load_BIO_strings();


    //TCP服务器:创建、绑定、监听
    if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket create wrong\n");
        exit(1);
    } else
        printf("socket created\n");

    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);;

    if (bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr))
        == -1) {
        perror("bind wrong\n");
        exit(1);
    } else
        printf("binded success\n");
    int lisnum = 2;

    do{
        //使用SSL_CTX_new()创建会话环境,建立连接时要使用协议由TLS_server_method()来定。如果这一步出错,需要查看错误栈来查看原因
        if(nullptr == (ctx = SSL_CTX_new( TLSv1_2_method())))		//using sm3, TLSv1_2_method
        {
            ERR_print_errors_fp(stdout);
            break;
        }

        // 双向验证
        // SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
        // SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);

        // 设置信任根证书
        if(SSL_CTX_load_verify_locations(ctx, "/home/chy-cpabe/CLionProjects/learn_GmSSL_server/pem/CaCert.pem", nullptr) != 1)
        {
            printf("SSL_CTX_load_verify_locations error\n");
            ERR_print_errors_fp(stdout);
            break;
        }
        /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
        if( 0>=SSL_CTX_use_certificate_file(ctx, "/home/chy-cpabe/CLionProjects/learn_GmSSL_server/pem/HuiguanCert.pem", SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户证书 */
        {
            ERR_print_errors_fp(stdout);
            break;
        }
        /* 载入用户私钥 */
        if( 0>=SSL_CTX_use_PrivateKey_file(ctx, "/home/chy-cpabe/CLionProjects/learn_GmSSL_server/pem/HuiguanKey.pem", SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户私钥 */
        {
            ERR_print_errors_fp(stdout);
            break;
        }
        /* 检查用户私钥是否正确 */
        if(!SSL_CTX_check_private_key(ctx))                                 										 /* 验证私钥和证书是否相符 */
        {
            ERR_print_errors_fp(stdout);
            break;
        }

        if (listen(listen_fd, lisnum) == -1) {
            perror("listen wrong\n");
            exit(1);
        } else
            printf("begin listen\n");

        len = sizeof(struct sockaddr);
        /* 等待客户端连上来 */
        if ((accept_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &len))
            == -1) {
            perror("accept wrong\n");
            exit(errno);
        } else{
            printf("server: got connection from %s, port %d, socket %d\n",
                   inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port),
                   accept_fd);
        }

        ssl = SSL_new(ctx); /* 基于 ctx 产生一个新的 SSL */
        SSL_set_fd(ssl, accept_fd); /* 将连接用户的 socket 加入到 SSL */
        /* 建立 SSL 连接 */
        if (SSL_accept(ssl) == -1) {
            perror("accept wrong\n");
            SSL_shutdown(ssl);
            SSL_free(ssl);
            ssl= nullptr;
            close(accept_fd);
            accept_fd=-1;
            break;
        }
        ShowCerts(ssl);

        /* 开始处理每个新连接上的数据收发 */
        bzero(buf, MAXBUF + 1);
        strcpy(buf, "server->client");
        /* 发消息给客户端 */
        len = SSL_write(ssl, buf, strlen(buf));

        if (len <= 0) {
            printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno,
                   strerror(errno));
            goto finish;
        } else
            printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len);

        bzero(buf, MAXBUF + 1);
        /* 接收客户端的消息 */
        len = SSL_read(ssl, buf, MAXBUF);
        if (len > 0)
            printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
        else
            printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",
                   errno, strerror(errno));
        /* 处理每个新连接上的数据收发结束 */
        finish:
        /* 关闭 SSL 连接 */
        SSL_shutdown(ssl);
        /* 释放 SSL */
        SSL_free(ssl);
        ssl = nullptr;
        /* 关闭 socket */
        close(accept_fd);
        accept_fd = -1;
    }while(1);

    /* 关闭监听的 socket */
    close(listen_fd);
    listen_fd = -1;
    /* 释放 CTX */
    SSL_CTX_free(ctx);
    ctx = nullptr;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.22)

project(ssl_server)
set(CMAKE_CXX_STANDARD 11)

# 忽略警告
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations ")

# 指定lib目录
 link_directories(${PROJECT_SOURCE_DIR}/lib)

# 指定头文件搜索策略
include_directories(/usr/local/gmssl/include)

# 使用指定的源文件来生成目标可执行文件
add_executable(${PROJECT_NAME} ssl_server.cpp)

# 将库链接到项目中
target_link_libraries(${PROJECT_NAME} libssl.a libcrypto.a pthread dl)



配置执行输入参数

  • CLion运行程序时添加命令行参数 即设置argv输入参数_MY CUP OF TEA的博客-CSDN博客
  • 127.0.0.1
    7838

执行结果

Client

层次结构

  • lib存放静态编译gmssl代码生成的静态库,即libssl.a和libcrypto.a
  • pem存放证书文件,因为SSL双向验证,客户端同样会验证客户端的证书,因此客户端存放服务端的证书和私钥,以及生成服务端证书时用于签名的ca证书

Code

#include <cstdio>
#include <cstring>
#include <cerrno>
#include <sys/socket.h>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAXBUF 1024

void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    // SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
    // 如果验证不通过,那么程序抛出异常中止连接
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        printf("证书验证通过\n");
    }
    if (cert != nullptr) {
        printf("数字证书信息:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
        printf("证书: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
        printf("颁发者: %s\n", line);
        free(line);
        X509_free(cert);
    } else
        printf("无证书信息!\n");
}

static void PrintData(char *p, char *buf,int len,char *filename)
{
    char *name=p;
    printf("%s[%d]:\n",p,len);
    for (p=buf; p && p++-buf<len;)
        printf("%02x%c",(unsigned char)p[-1],(!((p-buf)%16) || p-buf==len)?'\n':' ');
//	if (filename) FileWrite(name,buf,len,filename);
}

int main(int argc, char **argv)
{
    int sock_fd = -1;            /* TCP套接字    */
    int len = 0;                 /* SSL会话环境 */
    SSL *ssl = nullptr;          /* SSL安全套接字 */
    struct sockaddr_in ser_addr; /* 服务器地址 */
    bzero(&ser_addr, sizeof(ser_addr));
    SSL_CTX *ctx = nullptr;
    char buffer[MAXBUF + 1];

    if( argc != 3 )
    {
        printf("argcment wrong:ip port content\n");
        exit(0);
    }

    /* SSL 库初始化,参看 ssl-server.c 代码 */
    SSL_library_init();
    SSLeay_add_ssl_algorithms();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
//    ERR_load_BIO_strings();

    do{
        /* 申请SSL会话环境 */
        if( nullptr==(ctx=SSL_CTX_new(TLSv1_2_method())) )    //使用SSL_CTX_new()创建会话环境,建立连接时要使用协议由TLS_client_method()来定,服务器由对应的TLS_server_method()来定。如果这一步出错,需要查看错误栈来查看原因
        {
            ERR_print_errors_fp(stdout);
            break;
        }
        // 双向验证
        // SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
        // SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
        // 设置信任根证书
        if (SSL_CTX_load_verify_locations(ctx, "/home/chy-cpabe/CLionProjects/learn_GmSSL_server/pem/CaCert.pem",nullptr)<=0){
            ERR_print_errors_fp(stdout);
            exit(1);
        }

        /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
        if (SSL_CTX_use_certificate_file(ctx, "/home/chy-cpabe/CLionProjects/ssl_client/src/pem/TerminalCert.pem", SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 载入用户私钥 */
        if (SSL_CTX_use_PrivateKey_file(ctx, "/home/chy-cpabe/CLionProjects/ssl_client/src/pem/TerminalKey.pem", SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 检查用户私钥是否正确 */
        if (!SSL_CTX_check_private_key(ctx)) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        //https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_mode.html
        SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
        /* 创建一个 socket 用于 tcp 通信 */
        if(-1==(sock_fd=socket(AF_INET, SOCK_STREAM, 0)) )
        {
            printf("creat socket wrong\n");
            break;
        }
        printf("socket created\n");
        /* 初始化服务器端(对方)的地址和端口信息 */
        ser_addr.sin_family = AF_INET;
        ser_addr.sin_port = htons(atoi(argv[2]));
        ser_addr.sin_addr.s_addr = inet_addr(argv[1]);
        //将网络地址转成网络二进制的数字
        //http://c.biancheng.net/cpp/html/362.html
        //另外一种写法
/*		if (inet_aton(argv[1], (struct in_addr *) &ser_addr.sin_addr.s_addr) == 0) {
			perror(argv[1]);
			exit(errno);
		}
*/
        printf("address created\n");
        //建立连接
        if( -1==(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr))) )
        {
            printf("connect wrong\n");
            break;
        }
        printf("server connected\n");

        /* 基于 ctx 产生一个新的 SSL */
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sock_fd);
        /* 建立 SSL 连接 */
        if (SSL_connect(ssl) == -1)
            ERR_print_errors_fp(stderr);
        else {
            printf("The relevant information is as follows:\n");
            printf("-->ssl version %s\n",SSL_get_version(ssl));
            printf("-->ssleay version %s\n",SSLeay_version(0));
            printf("-->Connected with %s encryption\n", SSL_get_cipher(ssl));
            ShowCerts(ssl);
        }

        //导出key和salt
        unsigned char buf[16];
        int err = -1;
        err = SSL_export_keying_material(ssl, buf, 16, nullptr,0, nullptr, 0, 1);
        if(err != 1){
            printf("err=%d\n",err);
        }else{
            PrintData("SSL_export_keying_material", (char*)buf, 16, nullptr);
        }


        /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
        bzero(buffer, MAXBUF + 1);
        /* 接收服务器来的消息 */
        len = SSL_read(ssl, buffer, MAXBUF);
        if (len > 0)
            printf("接收消息成功:'%s',共%d个字节的数据\n",
                   buffer, len);
        else {
            printf
                    ("消息接收失败!错误代码是%d,错误信息是'%s'\n",
                     errno, strerror(errno));
            goto finish;
        }
        bzero(buffer, MAXBUF + 1);
        strcpy(buffer, "from client->server");
        /* 发消息给服务器 */
        len = SSL_write(ssl, buffer, strlen(buffer));
        if (len < 0)
            printf
                    ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
                     buffer, errno, strerror(errno));
        else
            printf("消息'%s'发送成功,共发送了%d个字节!\n",
                   buffer, len);

        /* 处理每个新连接上的数据收发结束 */
        finish:
        /* 关闭 SSL 连接 */
        SSL_shutdown(ssl);
        /* 释放 SSL */
        SSL_free(ssl);
        ssl = nullptr;
    }while(0);

    /* 关闭socket */
    close(sock_fd);
    sock_fd = -1;
    /* 释放 CTX */
    SSL_CTX_free(ctx);
    ctx = nullptr;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.22)
project(ssl_client)

set(CMAKE_CXX_STANDARD 11)

# 忽略警告
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations ")

# 指定lib目录
link_directories(${PROJECT_SOURCE_DIR}/lib)

# 指定头文件搜索策略
include_directories(/usr/local/gmssl/include)

link_libraries(ssl crypto)

# 使用指定的源文件来生成目标可执行文件
add_executable(${PROJECT_NAME} ssl_client.cpp)

# 将库链接到项目中
target_link_libraries(${PROJECT_NAME} libssl.a libcrypto.a pthread dl)

配置执行输入参数

  • 127.0.0.1
    7838

执行结果

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于GmSSL实现server服务端和client客户端之间SSL通信代码(升级优化公开版) 的相关文章

  • idea本地调试web报“There is no configured/running web-servers found! Please, run any web-config”...

    为什么80 的码农都做不了架构师 xff1f gt gt gt 本文永久更新地址 xff1a https my oschina net bysu blog 3051091 1 按照网上的各种配置 如下图 还是不行 2 网上还说要先run才行
  • Visual Studio Code语言设置为中文

    1 Visual Studio Code下载安装 https code visualstudio com 2 语言设置 2 1 快捷键 Windows Linux 快捷键是 xff1a ctrl 43 shift 43 p macOS 快捷
  • 查看zookeeper注册中心是否有注册服务

    为什么80 的码农都做不了架构师 xff1f gt gt gt 查看zookeeper注册中心是否有注册服务可以在服务器上看 xff0c 也可以在dubboadmin看哦 1 在服务器上看 xff1a 1 xff09 查找zookeeper
  • matplotlib 设置图形大小时 figsize 与 dpi 的关系

    matplotlib 中设置图形大小的语句如下 xff1a fig 61 plt figure figsize 61 a b dpi 61 dpi 其中 xff1a figsize 设置图形的大小 xff0c a 为图形的宽 xff0c b
  • iOS- SQLite3的基本使用

    iOS 简单说说iOS移动客户端SQLite3的基本使用 1 为什么要使用SQLite3 xff1f 大量数据需要存储 管理数据 xff0c 存储数据 SQLite是一种关系型数据库 xff08 也是目前移动客户端的主流数据库 xff09
  • Daily Scrum: 2012/12/8

    成员角色今天工作明天计划王安然PM Dev已请假 xff0c 开会 继续开会 黄杨PM Dev已收拾skynet的小问题并且通过测试 xff08 312 xff09 xff0c 编写武器项cracker xff08 313 xff09 完成
  • 【Python】控制鼠标点击

    from pymouse import PyMouse m 61 PyMouse a 61 m position 获取当前坐标的位置 print a m move 50 500 鼠标移动到 x y 位置 a 61 m position pr
  • C++ 标准程序库std::string 详解

    现在一般不再使用传统的char 而选用C 43 43 标准程序库中的string类 xff0c 是因为string标准程序和char 比较起来 xff0c 不必担心内存是否足够 字符串长度 等等 xff0c 而且作为一个类出现 xff0c
  • Lighttpd 搭建 Web 服务器

    背景 xff1a 公司项目用到了lighttpd xff0c 由于自己没有接触过 xff0c 所以做下记录 简介 xff1a Lighttpd 是一个德国人领导的开源Web服务器软件 xff0c 其根本的目的是提供一个专门针对高性能网站 x
  • lua中.和:的区别

    2019独角兽企业重金招聘Python工程师标准 gt gt gt lua中 和 都可以用于方法的声明和调用 和table配合使用 和 最大的不同点 xff0c 就是 xff1a 会把调用者自身 xff0c 传入到函数中 如下代码 xff1
  • 一个很有意思的玩意:FlightGear,开源飞机模拟器

    你一定很想知道开F22战机是什么感觉 xff0c 甚至梦想有一天自己也能驾驭着飞机在空中飞翔 现实生活中 xff0c 做飞行员可不是一件简单的事 xff0c 既然如此 xff0c 我们就别想那么多 xff0c 但有了FlightGear这个
  • 第二学期无人机操作师结业复习测试

    无人机操作师结业复习测试 姓名 xff1a 学号 xff1a 得分 xff1a xff08 本套试卷考试时间为90分钟 xff0c 共分选择题 判断题 填空题 问答题四大部分 xff0c 总分100分 xff09 一 选择题 xff08 共
  • 误删linux文件恢复

    Linux下文件误删除 xff0c 使用extundelete恢复测试过程 extundelete下载官网地址 xff1a https pkgs org download extundelete 给虚拟主机添加一块磁盘 xff0c 磁盘为
  • POJ训练计划1459_Power Network(网络流最大流/Dinic)

    解题报告 这题建模实在是好建 xff0c xff0c 好贱 xff0c 给前向星给跪了 xff0c 纯dinic的前向星居然TLE xff0c sad xff0c xff0c 回头看看优化 xff0c 矩阵跑过了 2A xff0c sad
  • WIN10下微信崩溃(已经是最新版)的解决方法

    问题症状 xff1a WIN10下运行最新版微信 xff08 CrashVersion 61 1644560715 xff09 微信运行错误 你的微信崩溃次数较多 xff0c 建议使用最新版本 xff0c 点击 34 确定 34 到官网 h
  • golang ----map按key排序

    实现map遍历有序 1 key有序 思路 xff1a 对key排序 xff0c 再遍历key输出value 代码如下 xff1a 既可以从小到大排序 xff0c 也可以从大到小排序 package main import 34 fmt 34
  • egg(102)--egg之用户登录 以及登录时候涉及的一些安全问题

    router router get 39 login 39 initMiddleware controller default pass login router post 39 pass doLogin 39 initMiddleware
  • 火狐浏览器添加MetaMask钱包和本地开启私有链开发

    火狐浏览器添加MetaMask钱包 因为对其配置了代理工具 xff0c 所以直接使用谷歌引擎搜索MetaMask钱包即可 第一次使用 xff0c 立即开始设置 点击我同意 xff0c 进行密码的创建 牢记助记词 xff0c 助记词及其关键
  • Cordova 打包签名 Android release app 过程详解及cordova创建app

    很久之前就想写这篇博客 xff0c 但是一直没有时间 xff0c 今天抽空来整理一下 xff0c 总结一下cordova的创建 打包 签名apk 对于cordova所需的打包环境 xff0c 如node cordova的安装 xff0c 这
  • MySQL【Update误操作】回滚

    1 2 3 4 5 6 7 8 9 10 11 12

随机推荐

  • dart常用正则表达式

    电话号码 xff1a 1开头 xff0c 后面10位数字 static bool isPhone String input RegExp mobile 61 new RegExp r span class hljs string 34 1
  • Less编写函数(mixin/@functions)的小技巧分享

    技术背景 开发移动端Web项目的时候 xff0c 有一种弹性布局的方案是基于rem开发项目 简单来说 xff0c 应用淘宝 lib flexible xff08 虽说有新方案vw xff0c 暂时先不讨论 xff09 后 xff0c 会根据
  • 中科院总共有多少计算机研究所?

    我说的都是招计算机的所哈 北京的 xff1a 中科院计算所 中科院软件所 中科院网络中心 中科院信息工程学院 xff08 其实就是中科院研究生本部 xff09 中科院计算与通信工程学院 中科院自动化所 中科院高能所 还有光电 生物的两个所招
  • iOS objc_setAssociatedObject 关联对象的学习

    今天看了FDTemplateLayoutCell的源码 xff0c 类别里面相当频繁使用了关联对象 xff0c 做笔记 xff01 xff01 xff01 学套路 主要函数 xff1a void objc setAssociatedObje
  • 迭代器、生成器

    迭代器 通过迭代器取值优缺点 xff1a 优点 xff1a 不依赖索引 xff0c 完成取值 缺点 xff1a 不能计算长度 xff0c 不能指定位取值 只能从前往后逐一取值 可迭代对象 可迭代对象 有 iter 方法的对象 xff0c 调
  • 使用androidstudio 分析内存泄漏

    分析内存泄漏 http www jianshu com p c49f778e7acf 转载于 https www cnblogs com sunfb p 5086317 html
  • 详解BASIC认证

    Basic 认证是HTTP 中非常简单的认证方式 xff0c 因为简单 xff0c 所以不是很安全 xff0c 不过仍然非常常用 本文详细讲解BASIC认证的过程及原理 BASIC认证流程 xff1a 在HTTP协议进行通信的过程中 xff
  • 孙子兵法全文及翻译

    第1章 始计 兵者 xff0c 国之大事 xff0c 死生之地 xff0c 存亡之道 xff0c 不可不察也 故经之以五事 xff0c 校之以计 xff0c 而索其情 xff1a 一曰道 xff0c 二曰天 xff0c 三曰地 xff0c
  • Ubuntu安装Google浏览器

    下载谷歌浏览器 直接使用Ubuntu自带的火狐浏览器进行下载 默认下载到 tmp临时文件夹里面 xff0c 考虑到权限问题 xff0c 需要将其移动到 Downloads文件夹下面使用命令 sudo mv goo xff08 Tab xff
  • ArcGIS中的多个栅格波段合成一幅影像

    此处用到了ArcGIS栅格处理中的Composite Bands工具 xff08 Data Management Tools gt Raster gt Raster Processing xff09 具体操作如下图所示
  • Sourcetree 更新git账号密码

    删除Sourcetree 缓存文件 只需要删密码文件 xff0c 文件位置 xff1a Mac xff1a Library Application Support SourceTree Windows xff1a C Users USERN
  • Vue.js仿一个购买火车票的app

    项目地址 预览的时候如果是用电脑预览的话请切换手机端预览地址源码地址 xff08 欢迎点赞 lt xffe3 xffe3 gt xff09 项目描述 主要技术 使用vue js实现单页应用使用vue Router处理路由使用vuex实现数据
  • k8s ingress获取真实IP地址配置

    背景 业务架构 xff1a Client gt WAF gt LB gt ECS gt 容器 问题 xff1a 在容器中获取不到真实的客户端公网IP 抓包分析 1 在ECS上的抓包分析 xff0c 看到WAF已经将 真实客户端地址放到了 x
  • 华为视频终端默认的Web页面用户名和密码是多少

    在将华为视频会议系统安装好之后我们需要进终端web管理页面设置 xff0c 但是很多朋友并不知道默认的用户名和密码是多少 xff0c 今天我们就来说说华为视频会议终端默认的web页面默认的用户名密码是多少吧 华为视频会议终端9030 800
  • 缺省vlan的简单介绍

    什么是缺省vlan xff1f 首先要理解什么是vlan xff1f 简单点说vlan就是可以把一个LAN划分成多个逻辑的LAN VLAN xff0c 每个VLAN是一个广播域VLAN内的主机间通信就和在一个LAN内一样 xff0c 而VL
  • 解决:The declared package does not match the expected package

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 这个问题让人挺头疼 xff0c 看网上答案很多 xff0c 但是这个比较靠谱 xff0c 原理也说清楚了 xff0c 并且已经解决了我的问题 xff1a Maven 61
  • IOS破解软件,比较全的网站。

    转载于 https blog 51cto com 14259888 2369621
  • 共享组件(有码):将文件中数据导入到DataTable

    08 11 29日更新 xff0c 增加了Xls和Xlsx文件导入支持 1 功能 xff1a 1 1 自由配置文件格式 xff1a 生成的DataTable的主键 文件内容中是否有表头 列分隔符 列是否可空 列中数据类型 String型可加
  • Sql Server 2008修改Sa密码

    1 用Windows验证模式进入数据库管理器 右键根目录 属性 左边的安全性 选择sql server 和windows 验证 xff08 SQL Server and Windows Authentication Mode xff09 2
  • 基于GmSSL实现server服务端和client客户端之间SSL通信代码(升级优化公开版)

    参考链接 工程搭建介绍 Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本 MY CUP OF TEA的博客 CSDN博客CLion运行程序时添加命令行参数 即设置argv输入参数 MY CUP OF TEA的博客 C