文章目录

  • 前言
  • 一、什么是并发服务器
  • 二、服务器的实现
  • 三、客户端的实现
  • 四、代码测试结果
  • 五、代码测试注意
  • 总结

前言

本文是我在IO进线程、网络编程学习阶段的练习项目。项目基于linux平台,利用多进程实现并发服务器;利用sqlite3数据库、TCP传输控制协议实现了多个客户端同时访问服务器、页面菜单、用户注册、用户登录、单词词义查询等功能。


  • 一、什么是并发服务器

为了提高服务器的并发处理能力,在这里又引入了并发服务器的模型。并发服务器解决了循环服务器的缺陷,即可以在同一时刻响应多个客户端的请求。其基本设计思想是在服务器端采用多任务机制(即多进程或多线程),分别为每一个客户端创建一个任务处理。此项目就是利用多进程机制实现的并发服务器。

  • 二、服务器的实现

server_tcp.c

/*===============================================*   文件名称:server_tcp.c*   创 建 者:hclhy9191    *   创建日期:2022年08月03日*   描    述:================================================*/
#include "server_tcp.h"
#include "sqlite3_server.h"#define PORT_NUMBER        6666
#define IP_NUMBER         "0.0.0.0"int server_init(void)
{int sockfd = socket(AF_INET , SOCK_STREAM, 0);if(sockfd < 0){perror("socket");return -1;}//设置端口、IP可以重复使用int opt = 1;if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0){perror("setsockopt");return -1;}struct sockaddr_in addr;addr.sin_family         =    AF_INET;addr.sin_port           =    htons(PORT_NUMBER); addr.sin_addr.s_addr    =    inet_addr(IP_NUMBER); if(0 > bind(sockfd, (struct sockaddr *)&addr, sizeof(addr))){perror("bind");return -1;}if(0 > listen(sockfd, 5)){perror("listen");return -1;}printf("server init success!\n");return sockfd;
}int wait_client(int sockfd)
{struct sockaddr_in caddr;socklen_t len = sizeof(caddr);int connfd = accept(sockfd, (struct sockaddr *)&caddr, &len);if(connfd < 0){perror("accept");return -1;}printf("server accept success!\n");return connfd;
}int data_communicate(int connfd, char *name)
{char word[128] = {0};int ret = read(connfd, word, sizeof(word));if(ret < 0){perror("read1");return -1;}else if(ret == 0){printf("clinet leaved!\n");close(connfd);exit(0);}printf("word_com:%s \n", word);char translation[512] = {0};if(0 > sqlite3_select(word, translation)){printf("select failure\n");char err[32] = "没有为您找到相关单词\n";write(connfd, err, strlen(err));return -1;}else{write(connfd, translation, strlen(translation));}return 0;
}int send_sigal_success(int connfd)
{char buf[32] = "success";write(connfd, buf, sizeof(buf));return 0;
}
int send_sigal_err(int connfd)
{char buf[32] = "error";write(connfd, buf, sizeof(buf));return 0;
}

server_tcp.h

/*===============================================
*   文件名称:server_tcp.h
*   创 建 者:hclhy9191
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#ifndef SERVER_TCP_H_
#define SERVER_TCP_H_//tcp_server
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "sqlite3_server.h"//sqlite3int server_init(void);
int wait_client(int sockfd);
int data_communicate(int connfd,char *name);
int send_sigal_success(int connfd);
int send_sigal_err(int connfd);#endif

sqlite3_server.c

/*===============================================
*   文件名称:sqlite3_server.c
*   创 建 者:hclhy9191
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#include "sqlite3_server.h"int sqlite3_select(char *word, char *translation)
{sqlite3 *db;printf("word: %s\n",word);if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}char sql[128] = {0};sprintf(sql,"select translation from dict where word='%s';",word);int nRow, nCloumn;char **resultp;if( sqlite3_get_table(db, sql, &resultp, &nRow, &nCloumn, NULL) != SQLITE_OK){printf("select: %s\n", sqlite3_errmsg(db));return -1;}if(NULL == resultp[nCloumn]){return -1;}strcpy(translation, resultp[nCloumn]);return 0;
}int sqlite3_usr_create(int connfd)
{char name[32] = {0};char passwd[32] = {0};read(connfd, name, sizeof(name));if(0 > dup_name(name)){send_sigal_err(connfd);return -1;}else{send_sigal_success(connfd);}read(connfd, passwd, sizeof(passwd));printf("name: %s passwd: %s\n",name, passwd);sqlite3 *db;if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}//建立用户目录char sql[128] = {0};char **resultp;sprintf(sql, "create table if not exists usr(name text, passwd varchar(12) );");if( sqlite3_get_table(db, sql, &resultp, NULL, NULL, NULL) != SQLITE_OK){printf("create: %s\n", sqlite3_errmsg(db));return -1;}//插入新建用户名和密码sprintf(sql, "insert into usr values('%s', '%s');", name, passwd);if( sqlite3_get_table(db, sql, &resultp, NULL, NULL, NULL) != SQLITE_OK){printf("insert: %s\n", sqlite3_errmsg(db));return -1;}printf("注册成功\n");return 0;
}int dup_name(char *name)
{sqlite3 *db;char **resultp;if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}char sql[128] = {0};sprintf(sql, "select name from usr where name='%s';",name);int nRow, nCloumn;if( sqlite3_get_table(db, sql, &resultp, &nRow, &nCloumn, NULL) != SQLITE_OK){printf("select: %s\n", sqlite3_errmsg(db));return -1;}if(NULL == resultp[nCloumn]){return 0;}else{printf("%s\n",resultp[nCloumn]);printf("dup_name\n");return -1;}
}int sqlite3_usr_enter(int connfd, char *name)
{char passwd[32] = {0};read(connfd, name, sizeof(name));read(connfd, passwd, sizeof(passwd));printf("name: %s passwd: %s\n",name, passwd);sqlite3 *db;char **resultp;if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}char sql[128] = {0};sprintf(sql, "select passwd from usr where name='%s';",name);int nRow, nCloumn;if( sqlite3_get_table(db, sql, &resultp, &nRow, &nCloumn, NULL) != SQLITE_OK){printf("select: %s\n", sqlite3_errmsg(db));return -1;}printf("passwd: %s\n", resultp[nCloumn]);if(NULL == resultp[nCloumn]){printf("用户不存在\n");return -1;}if( 0 == strcmp(passwd, resultp[nCloumn])){printf("登陆成功\n");return 0;}else{printf("用户名或密码错误\n");return -1;}}char my_list_enter(int connfd)
{char list_enter;int ret = read(connfd, &list_enter, 1);if(ret < 0){perror("read");return -1;}else if(ret == 0){printf("client leaved!\n");exit(0);}printf("%c\n", list_enter);switch(list_enter){case REGISTER :return '1';break;case ENTER    :return '2';break;case QUIT     :return '3';break;default       :printf("选项错误!\n");return -1;}}char my_list_select(int connfd)
{char list_enter;int ret = read(connfd, &list_enter, 1);if(ret < 0){perror("read");return -1;}else if(ret == 0){printf("client leaved!\n");exit(0);}printf("%c\n", list_enter);switch(list_enter){case SELECT :return '1';break;case FUNQUIT     :return '2';break;case HISTORY     :return '3';break;default       :printf("选项错误!\n");return -1;}}

sqlite3_server.h

/*===============================================
*   文件名称:sqlite3_server.h
*   创 建 者:hclhy9191
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#ifndef SQLITE3_SERVER_H_
#define SQLITE3_SERVER_H_#include <sqlite3.h>
#include "server_tcp.h"#define REGISTER   '1'
#define SELECT     '1'
#define ENTER      '2'
#define FUNQUIT    '2'
#define QUIT       '3'
#define HISTORY    '3'int sqlite3_select(char *word, char *translation);
int sqlite3_usr_create(int connfd);
int sqlite3_usr_enter(int connfd, char *name);
char my_list_enter(int connfd);
char my_list_select(int connfd);
int sqlite3_history_in(char *name, char *word, char *translation);
int history(int connfd, char *name);
int dup_name(char *name);#endif

main.c

/*===============================================
*   文件名称:main.c
*   创 建 者:hclhy9191
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#include "server_tcp.h"
#include "sqlite3_server.h"int main(int argc, char *argv[])
{ int sockfd = server_init();while(1){   //主进程获取客户端连接套接字int connfd = wait_client(sockfd);//子进程与客户端交互if(0 == fork()){int key = 0;char name[32] = {0};while(1){                                                           memset(name, 0 , sizeof(name));char list_enter;while(1){                                                             //初始菜单list_enter = my_list_enter(connfd); if(list_enter < 0){send_sigal_err(connfd);continue;}else{send_sigal_success(connfd);}switch(list_enter){                                                         //注册case REGISTER :if(0 != sqlite3_usr_create(connfd)){send_sigal_err(connfd);}else{send_sigal_success(connfd);}break;//登陆case ENTER    :if ( 0 == sqlite3_usr_enter(connfd, name)){key = 1;send_sigal_success(connfd);}else{send_sigal_err(connfd);memset(name, 0, sizeof(name));}break;//退出case QUIT     :printf("client leaved!\n");exit(0);break;}if(key == 1){break;}}key = 0;char list_select;while(1){                                                    //功能菜单list_select = my_list_select(connfd);           switch(list_select){                                                //查询单词case SELECT:data_communicate(connfd, name);break;//退出登陆case FUNQUIT:key = 1;break;//查询历史记录case HISTORY:break;}if(key == 1){break;}}key = 0;}}//close(connfd);           //主进程关闭连接套接字 }close(sockfd);return 0;
}
  • 三、客户端的实现

client_tcp.c

/*===============================================
*   文件名称:clinet_tcp.c
*   创 建 者:hclhy9191
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#include "client_tcp.h"#define PORT_NUMBER        6666
#define IP_NUMBER         "192.168.12.149"int client_init(void)
{int sockfd = socket(AF_INET , SOCK_STREAM, 0);if(sockfd < 0){perror("socket");return -1;}printf("client init success!\n");return sockfd;
}int connect_server(int sockfd)
{struct sockaddr_in addr;addr.sin_family         =    AF_INET;addr.sin_port           =    htons(PORT_NUMBER); addr.sin_addr.s_addr    =    inet_addr(IP_NUMBER); if(0 > connect(sockfd, (struct sockaddr *)&addr, sizeof(addr))){perror("connect");return -1;}printf("client connect success!\n");return 0;
}int data_communicate(int sockfd, char *name)
{//发送查询的单词char buf[128] = {0};printf("\033[1;36;40minput select word> \033[0m");fflush(stdout);//fgets(buf, sizeof(buf), stdin);scanf("%s",buf);getchar();write(sockfd, buf, strlen(buf));//接收服务器返回数据char translation[512] = {0};int ret = read(sockfd, translation, sizeof(translation));if(ret < 0){perror("read");return -1;}if(0 != strcmp("没有为您找到相关单词\n",translation)){if(0 > sqlite3_history_in(name, buf, translation)){printf("history_in error!\n");return -1;}}printf("word:%s\t", buf);printf("translation:%s\n",translation);return 0;
}int recv_sigal(int sockfd)
{char buf[32] = {0};read(sockfd, buf, sizeof(buf));if (0 == strcmp("success",buf)){return 0;}else{return -1;}
}

printf_vdio.c

#include "printf_vdio.h"
void my_printf_vdio()
{printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t");sleep(1); int a,b;a=0;while(a<=70){system("clear");b=1;printf("\n\n\n\n\n\n\n\n\n\n\n\n\n");while(b<=a){  printf(" ");b++;}printf("┌════════┐...┌════════┐...┌.═════════┐   ╭═════╮ 欢迎使用\n");b=1;while(b<=a){   printf(" ");b++;}printf("║        ║ ═ ║        ║ ═ ║          ║═  ║    ║\n");b=1;while(b<=a){   printf(" ");b++;}printf("└⊙═⊙═⊙═⊙ ⊙═⊙═⊙═⊙  └⊙═⊙═⊙═⊙~~ ╰⊙═⊙╯\n");usleep(100000);a=a+1;}    system("clear");}

sqlite3_server.c

/*===============================================
*   文件名称:sqlite3_server.c
*   创 建 者:hclhy9191
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#include "sqlite3_server.h"char my_list_enter(int connfd)
{ printf("\033[1;34;40m*******************************************\n");printf("****1.注册********2.登陆*********3.退出****\n");printf("*******************************************\033[0m\n");printf("\033[1;36;40minput list> \033[0m");fflush(stdout);char key;scanf("%c",&key);getchar();printf("%c\n",key);write(connfd, &key, 1);system("clear");return key;
} char my_list_select(int connfd)
{ printf("\033[1;34;40m********************************************\n");printf("***1.查询********2.退出*******3.历史记录****\n");printf("********************************************\033[0m\n");printf("\033[1;36;40minput list> \033[0m");fflush(stdout);char key;scanf("%c",&key);getchar();printf("%c\n",key);write(connfd, &key, 1);system("clear");return key;
} int sqlite3_usr_create(int connfd)
{    printf("\033[1;34;40m*****************************************\n");printf("**************注*********册**************\n");printf("*****************************************\033[0m\n");printf("\033[1;36;40minput name> \033[0m");fflush(stdout);char name[32] = {0};scanf("%s",name);getchar();write(connfd, name, strlen(name));if(0 > recv_sigal(connfd)){return -1;}printf("\033[1;36;40minput passwd> \033[0m");fflush(stdout);char passwd[32] = {0};scanf("%s",passwd);getchar();write(connfd, passwd, strlen(passwd));system("clear");return 0;
}int sqlite3_usr_enter(int connfd, char *name)
{printf("\033[1;34;40m*****************************************\n");printf("**************登*********陆**************\n");printf("*****************************************\033[0m\n");printf("\033[1;36;40minput name> \033[0m");fflush(stdout);scanf("%s",name);getchar();write(connfd, name, strlen(name));printf("\033[1;36;40minput passwd> \033[0m");fflush(stdout);char passwd[32] = {0};scanf("%s",passwd);getchar();write(connfd, passwd, strlen(passwd));system("clear");return 0;
}int sqlite3_history_in(char *name, char *word, char *translation)
{sqlite3 *db;if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}//建立用户目录char sql[128] = {0};char **resultp;sprintf(sql, "create table if not exists history(name text, word text, translation text);");if( sqlite3_get_table(db, sql, &resultp, NULL, NULL, NULL) != SQLITE_OK){printf("create: %s\n", sqlite3_errmsg(db));return -1;}//插入新建用户名和密码sprintf(sql, "insert into history values('%s', '%s', '%s');", name, word, translation);if( sqlite3_get_table(db, sql, &resultp, NULL, NULL, NULL) != SQLITE_OK){printf("insert: %s\n", sqlite3_errmsg(db));return -1;}return 0;
}int history(int connfd, char *name)
{sqlite3 *db;char **resultp;if(SQLITE_OK != sqlite3_open("Dirctionary.db",&db)){printf("open: %s\n",sqlite3_errmsg(db));return -1;}char sql[128] = {0};sprintf(sql, "select word,translation from history where name='%s';",name);int nRow, nCloumn;if( sqlite3_get_table(db, sql, &resultp, &nRow, &nCloumn, NULL) != SQLITE_OK){printf("select: %s\n", sqlite3_errmsg(db));return -1;}printf("\033[5;33;40m********************************************\033[0m\n");int k = 1;for(int i = nCloumn; i < (nRow+1)*nCloumn; i++){printf("%s\t",resultp[i]);if(k % 2 == 0)printf("\n");k++;}printf("\033[5;33;40m********************************************\033[0m\n");return 0;
}

main.c

/*===============================================*   文件名称:main.c*   创 建 者:hclhy9191      *   创建日期:2022年08月03日*   描    述:================================================*/
#include "client_tcp.h"
#include "sqlite3_server.h"
#include "printf_vdio.h"
int main(int argc, char *argv[])
{ int sockfd = client_init();connect_server(sockfd);while(1){int count = 0;char name[32] = {0};my_printf_vdio();while(1){memset(name, 0, sizeof(name));char key ;                                             //初始菜单key = my_list_enter(sockfd);if(0 != recv_sigal(sockfd)){continue;}switch(key){                                                     //注册case REGISTER :if(0 > sqlite3_usr_create(sockfd)){printf("\033[4;31;40m-------------用户名已存在--------------\033[0m\n");}if(0 > recv_sigal(sockfd)){printf("\033[4;31;40m---------------注册失败----------------\033[0m\n");}else{printf("\033[4;31;40m---------------注册成功----------------\033[0m\n");}break;//登陆case ENTER    :sqlite3_usr_enter(sockfd, name);if(0 != recv_sigal(sockfd)){count = 2;printf("\033[4;31;40m-------------密码或账户错误-------------\033[0m\n");}else{printf("\033[4;31;40m---------------登陆成功----------------\033[0m\n");count = 1;}break;//退出case QUIT     :exit(0);}if(count == 1){break;}else if(count == 2){continue;}}count = 0;char list_select;while(1){                                                       //功能菜单list_select = my_list_select(sockfd);switch(list_select){                                                   //查询单词case SELECT:data_communicate(sockfd, name);break;//退出登陆case FUNQUIT:                                   count = 1;break;//查询历史记录case HISTORY:history(sockfd, name);break;}if(count == 1){break;}}}close(sockfd);return 0;
}

client_tcp.h

/*===============================================
*   文件名称:client_tcp.h
*   创 建 者:hclhy9191
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#ifndef CLIENT_TCP_H_
#define CLIENT_TCP_H_#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sqlite3.h>int client_init(void);
int connect_server(int sockfd);
int data_communicate(int sockfd, char *name);
int recv_sigal(int sockfd);
extern int sqlite3_history_in(char *name, char *word, char *translation);
#endif

printf_vdio.h

/*===============================================
*   文件名称:printf_vido.h
*   创 建 者:hclhy9191
*   创建日期:2022年08月17日
*   描    述:
================================================*/
#ifndef PRINTF_VDIO_H
#define PRINTF_VDIO_H#include<stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>void my_printf_vdio();
#endif

sqlite3_server.h

/*===============================================
*   文件名称:sqlite3_server.h
*   创 建 者:hclhy9191
*   创建日期:2022年08月04日
*   描    述:
================================================*/
#ifndef SQLITE3_SERVER_H_
#define SQLITE3_SERVER_H_#include <sqlite3.h>
#include "client_tcp.h"#define SELECT     '1'
#define REGISTER   '1'
#define ENTER      '2'
#define FUNQUIT    '2'
#define QUIT       '3'
#define HISTORY    '3'int sqlite3_usr_create(int connfd);
int sqlite3_usr_enter(int connfd, char *name);
char my_list_enter(int connfd);
char my_list_select(int connfd);
int sqlite3_history_in(char *name, char *word, char *translation);
int history(int connfd, char *name);#endif
  • 四、代码测试结果

  • 五、代码测试注意

1.保证客户端的ip为自己当前虚拟机的IP    ---ifconfig 查询

客户端ip设置在client_tcp.h中

参考下图

2.确保服务器先运行,否则客户端连接失败

3.运行需要一个单词库和一个历史记录库(点赞私聊作者免费获取)

  • 总结

运用TCP传输协议和多进程实现并发服务器,对我来说是个长足的进步。让我对网络传输、并发服务模型有了更加深入理解。同时查询单词的功能使用到了sqlite3数据库,也对数据库的有了一定的了解,更是一种知识的扩展。

推荐大家做为练习小项目!!!!

由于是自己初学写的练习小项目,其中细节还有些处理不当的地方。

例如大量客户端连接服务器,由于是多进程对cpu资源消耗很大,会导致客户端崩掉!!!想到也是很难受。通过查阅资料发现可以利用进程池技术和心跳包技术可以很好的解决这个问题!!

还有什么粘包问题!!!!

后续我会继续更新,感激浏览到这里读者们!!!祝大家技术快速飞跃!!!!

基于Linux平台的TCP通信并发服务器---在线英语词典项目相关推荐

  1. 构建基于Linux平台的开源×××服务器

    实验名称:构建基于Linux平台的开源×××服务器 实验目标:一.基于Linux配置poptop ×××与管理 二.基于Linux配置Openswan ×××与管理 ×××的功能:加密数据 信息认证和 ...

  2. 基于原子探索者stm32f407开发板的ucos-iii+lwip1.4.1的tcp server并发服务器完美解决例程(转)...

    源:基于原子探索者stm32f407开发板的ucos-iii+lwip1.4.1的tcp server并发服务器完美解决例程 转载于:https://www.cnblogs.com/LittleTig ...

  3. linux环境下企业基于域名访问的web于电子邮件服务器 论文,基于Linux平台的企业邮件服务器搭建...

    我失骄杨君失柳,杨柳轻飏直上重霄九.得道多助,失道寡助.身后有余忘缩手,眼前无路想回头.鸟宿池边树,僧敲月下门.想当年,金戈铁马,气吞万里如虎. 本文由418133804贡献 pdf文档可能在WAP端 ...

  4. linux局域网语音通讯软件下载,基于Linux平台的局域网可语音的IM软件的设计与实现.doc...

    基于Linux平台的局域网可语音的IM软件的设计与实 作者: 专业:软件工程 指导老师: 摘要 随着计算机网络的日益普及人们通过网络进行交流显得越来越重要.于是出现了一系列的通信软件. 自1990s ...

  5. 计算机网络套接字编程实验-TCP多进程并发服务器程序与单进程客户端程序(简单回声)

    1.实验系列 ·Linux NAP-Linux网络应用编程系列 2.实验目的 ·理解多进程(Multiprocess)相关基本概念,理解父子进程之间的关系与差异,熟练掌握基于fork()的多进程编程模 ...

  6. linux升级ipv6协议栈,IPv6技术及基于Linux平台IPv6协议栈的实现

    IPv6技术及基于Linux平台IPv6协议栈的实现 简单介绍了 IPv6的基本原理和特征 ,重点探讨了 IPv6技术在 L inux环境中的应用 :对支持 IPv6协 (本文共5页) 阅读全文> ...

  7. linux集群管理平台,基于Linux平台的高可用集群管理系统的研究与实现

    摘要: 集群管理系统的高可用性是指其能够连续地对外提供服务,本文针对集群系统的高可用性,以开源的集群搭建和管理软件KUSU为基础,以集群管理节点的双机热备份技术理论为支撑,以实现集群系统的帮障检测与业 ...

  8. linux 车载视频监控,基于Linux平台车载视频监控系统研发-计算机科学与技术专业论文.docx...

    基于Linux平台车载视频监控系统研发-计算机科学与技术专业论文 目录 HYPERLINK \l "_bookmark0" 第一章 绪论1 HYPERLINK \l "_ ...

  9. linux网卡握手速率模式,一种基于Linux平台下的网卡速率和双工模式测试的方法与流程...

    本发明涉及计算机技术领域,更具体的说是涉及一种基于Linux平台下的网卡速率和双工模式测试的方法. 背景技术: 随着社会经济的发展和互联网技术的进步,如今把计算机网络使得我们的生活变得更加方便,快捷. ...

最新文章

  1. WinDBG加载符号表的一点心得体会
  2. re_path 的 ?P
  3. IEEE802.11协议栈
  4. [工具]微软的学习平台Microsoft Learn很好用,推荐一下
  5. java python 运行 内存_Python C Java中字符串在内存中的存储
  6. vue3,vite2,json数据通过拼接显示链接src
  7. linux文件监控和同步,(转)Linux下经过rsync与inotify(异步文件系统事件监控机制)实现文件实时同步...
  8. 【剑指offer】八皇后问题
  9. 微信小程序列表切换样式简单案例
  10. python爬取酷狗音乐源码_python爬虫教程:爬取酷狗音乐
  11. YGG 与 StemsDAO 达成合作,为全球音乐创作者提供支持
  12. 企业级地理数据库(2)创建并加载企业级地理数据库
  13. matlab析取范式求主析取范式用电脑,(p∧q)∨r 求其主析取范式 再用主析取范式求主合取范式...
  14. STRATEGY模式(冒泡算法为例)
  15. 笔记本喇叭无声音解决方案
  16. js对日期加减指定天、时、分、秒
  17. 数据到底如何搞定电影票房预测?
  18. 进制转换计算机文档,计算机进制转换.pdf
  19. 如何打开一个已经保存的微信小程序
  20. 软件设计师-多媒体专题

热门文章

  1. python案例:股民福利,采集股票数据~
  2. 二分查找板子(check()函数)
  3. 【第25题】一球从 100 米高度自由落下,每次落地后反跳回原高度的一半
  4. Google Play Store 应用无法安装解决方案
  5. macOS 上如何禁用 Adob​​e 后台进程,但保存 CPU、内存和网络活动呢
  6. python学习——tsv文件批量转为csv文件、csv文件列合并
  7. tp6实现商城后台登录功能
  8. 学 Rust 要几天?「GitHub 热点速览 v.22.51」
  9. 计算机二级考试office操作题11,【第十一套】计算机二级MS Office操作题
  10. java统计excel数据_数据分析实战——EXCEL实现复购率计算