用C语言搓一个小型的服务器,拥有路由解析器(支持MVC架构)
架构讲解
最近做学校专周,用C语言和RIO搓一个Tiny服务器,本身没啥难度,但是是让你返回一个页面。
对于特别习惯前后端分离开发的我来说,头疼,还是给json吧,前端html自己接收。
要求我们实现登录和注册,然后大概的方式是前端对tiny进行请求,tiny进行路由解析后,通过fork创建新的进程,再通过execve(filename, argv, envp)进行一个cgi执行,使用setenv来进行程序上下文的传递
void serve_dynamic(int fd, const char *filename, const char *cgiargs)
{
char buf[MAXLINE], *emptylist[] = {NULL};
/* Return first part of HTTP response */
sprintf(buf, "HTTP/1.0 200 OK\r\n");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Server: Tiny Web Server\r\n");
Rio_writen(fd, buf, strlen(buf));
if (Fork() == 0)
{ /* Child */ // line:netp:servedynamic:fork
/* Real server would set all CGI vars here */
setenv("QUERY_STRING", cgiargs, 1); // line:netp:servedynamic:setenv
Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ // line:netp:servedynamic:dup2
Execve(filename, emptylist, environ); /* Run CGI program */ // line:netp:servedynamic:execve
}
Wait(NULL); /* Parent waits for and reaps child */ // line:netp:servedynamic:wait
}
添加描述
但是,按照原来的思路,我要写很多个业务处理程序,很麻烦,有没有简单一点的?
有!那不就是Spring Boot和Spring MVC吗?
添加描述
但是不能用框架,vocal,那怎么办?
没有环境,咱们就创建环境,没有条件,咱们就创建条件!
来说说思路,我们现在在tiny层重写一个路由解析,相当于把tiny服务器当作一个网关,把请求的内容按照我们的约定来重新封装,再通过setenv进行路由信息传递,原来是传参数,那么我们就要改,改为“METHOD URL/?PARAM”的形式
上代码
void serve_dynamic(int fd, const char *filename, const char *cgiargs, char uri[8192])
{
char buf[MAXLINE], *emptylist[] = {NULL};
char *url=strdup(uri);
if(strlen(cgiargs)){
strcat(url,"?");
strcat(url,cgiargs);
}
printf("【serve_dynamic-Fork】uri写入环境变量:%s\n",url);
/* Return first part of HTTP response */
sprintf(buf, "HTTP/1.0 200 OK\r\n");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Server: Tiny Web Server\r\n");
Rio_writen(fd, buf, strlen(buf));
//#if usingFork == 1
printf("【serve_dynamic】尝试打开进程:%s 传入子进程信息如下:%s\r\n",filename,uri);
if (Fork() == 0)
{ /* Child */ // line:netp:servedynamic:fork
/* Real server would set all CGI vars here */
setenv("QUERY_STRING", url, 1); // line:netp:servedynamic:setenv
char *buff=getenv("QUERY_STRING");
/* Extract the two arguments */
printf("【serve_dynamic-Fork】进程%s打开成功!\t环境变量取出尝试:%s\r\n\r\n",filename,buff);
Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ // line:netp:servedynamic:dup2
Execve(filename, emptylist, environ); /* Run CGI program */ // line:netp:servedynamic:execve
// free(url);
}
Wait(NULL); /* Parent waits for and reaps child */ // line:netp:servedynamic:wait
// free(url);
}
url我们在之前拼接,给你们看看doit-请求处理的代码
void doit(int fd)
{
int is_static; // 判断访问的资源是否为静态资源
struct stat sbuf; // todo:
char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
char filename[MAXLINE], cgiargs[MAXLINE];
rio_t rio;
/* Read request line and headers */
Rio_readinitb(&rio, fd);
if (!Rio_readlineb(&rio, buf, MAXLINE)) // line:netp:doit:readrequest
return;
printf("%s", buf);
sscanf(buf, "%s %s %s", method, uri, version); // line:netp:doit:parserequest
// 如果不是get请求,就拒绝,客户端报异常
printf("ParseURI:%s\n", uri);
if (strcasecmp(method, "GET")&&strcasecmp(method, "POST"))
{ // line:netp:doit:beginrequesterr
clienterror(fd, method, "501", "Not Implemented",
"Tiny does not implement this method");
return;
} // line:netp:doit:endrequesterr`
read_requesthdrs(&rio); // line:netp:doit:readrequesthdrs
/* Parse URI from GET request */
is_static = parse_uri(uri, filename, cgiargs); // line:netp:doit:staticcheck
// 如果文件读取失败,客户端报错
if (stat(filename, &sbuf) < 0 && is_static)
{ // line:netp:doit:beginnotfound
printf("文件名:%s\n",filename);
clienterror(fd, filename, "404", "Not found",
"Tiny couldn't find this file");
return;
} // line:netp:doit:endnotfound
if (is_static)
{ /* Serve static content */
if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))
{ // line:netp:doit:readable
clienterror(fd, filename, "403", "Forbidden",
"Tiny couldn't read the file");
return;
}
printf("访问静态文件:%s",filename);
// 如果访问的是静态文件,那么对静态文件进行响应的处理
serve_static(fd, filename, sbuf.st_size); // line:netp:doit:servestatic
}
else
{ /* Serve dynamic content */
strcpy(filename,"./api/cgin.cgi");
if(stat(filename, &sbuf) < 0){
clienterror(fd, filename, "403", "Forbidden",
"CGIN框架加载失败");
return;
}
if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode))
{ // line:netp:doit:executable
clienterror(fd, filename, "403", "Forbidden",
"Tiny couldn't run the CGI program");
return;
}
char urlmsg[8910]="";
strcat(urlmsg,method);
strcat(urlmsg," ");
strcat(urlmsg,uri);
// 对交互操作进行响应
serve_dynamic(fd, filename, cgiargs, urlmsg); // line:netp:doit:servedynamic
}
}
那么业务层我们怎么做?
我们可以用哈希来进行映射,C语言哈希怎么办?手搓!一个路由对应一个函数
哈希实现
//
// Created by 30398 on 2023/12/30.
//
#ifndef C_HASH_TABLE_H
#define C_HASH_TABLE_H
//使用C语言编写个哈希表
#include <stdio.h>
#include "RequestContext.h"
#include "Response.h"
#define DEFAULT_RouterTable_SIZE 1<<5
int NotFound(RequestContext* requestContext){
return 404;
}
typedef struct {
char* key;
ResponseData* (*run)(RequestContext* requestContext);
struct Entry* nextEntry;
} Entry;
const Entry NOTFOUND_ENTRY={
"404",
NotFound,
NULL
};
typedef struct {
Entry** slots;
int size; //
int count;
}RouterTable;
int isNULLEntry(Entry* entry){
if(entry==NULL) return 1;
if(entry->key==NULL) return 1;
return 0;
}
RouterTable* createRouterTable(int size){
#ifdef DEBUG
printf("[MAIN-Hash]哈希表创建中\n");
#endif
RouterTable* RouterTable=malloc(sizeof(RouterTable));
RouterTable->count=0;
RouterTable->size=size;
#ifdef DEBUG
printf("[MAIN-Hash]slots创建中\n");
#endif
RouterTable->slots= malloc(sizeof(Entry*)*size);
#ifdef DEBUG
printf("[MAIN-Hash]正在对每一个slot进行初始化\n");
#endif
for (int i = 0; i < size; ++i) {
RouterTable->slots[i]= malloc(sizeof (Entry));
RouterTable->slots[i]->key=NULL;
RouterTable->slots[i]->nextEntry=NULL;
RouterTable->slots[i]->run=NULL;
}
#ifdef DEBUG
printf("[MAIN]哈希对象创建成功!\n");
#endif
return RouterTable;
}
void freeRouterTable(RouterTable* RouterTable){
#ifdef DEBUG
printf("[freeRouterTable]RouterTable.slots Begin to %d\r\n", RouterTable->size);
#endif
for (int i = 0; i < RouterTable->size; ++i) {
#ifdef DEBUG
printf("[freeRouterTable]RouterTable.slots[%d]\r\n",i);
#endif
Entry* entry=RouterTable->slots[i];
while (entry!=NULL){
Entry* nextEntry=entry->nextEntry;
entry->key=NULL;
entry->run=NULL;
free(entry);
entry=nextEntry;
}
}
free(RouterTable->slots);
free(RouterTable);
}
RouterTable* createDefaultRouterTable(){
#ifdef DEBUG
puts("创建默认哈希对象中...\n");
#endif
return createRouterTable(DEFAULT_RouterTable_SIZE);
}
// 计算在哈希表中的slot位置
long getHashSlotByKEY(RouterTable *RouterTable,char* key){
long long h=0;
for(char *s=key;*s!='\0';s++){
// printf("h=5*%d+%d\n",h,(int)*s);
h=5*h+(*s);
}
long long slot=(long long)h&((RouterTable->size)-1);
// printf("h:%d size:%d slot: %d\n",h,RouterTable->size,slot);
return slot;
}
long getHashSlot(RouterTable *RouterTable,Entry* entry){
char* key = entry->key;
return getHashSlotByKEY(RouterTable,key);
}
void entryCpy(Entry* old , Entry* current){
current->key=old->key;
current->run=old->run;
current->nextEntry=old->nextEntry;
}
void rehash(RouterTable* RouterTable){
if(RouterTable->count*4<RouterTable->size*3) return;
Entry** oldSlots=RouterTable->slots;
int oldSize=RouterTable->count;
RouterTable->size=oldSize<<1;
RouterTable->count=0;
Entry** newSlots = RouterTable->slots=malloc(RouterTable->size*sizeof(Entry*));
for(int i=0;i<oldSize;i++){
Entry* entry=oldSlots[i];
while(!isNULLEntry(entry)){
long hashcode= getHashSlot(RouterTable,entry);
Entry* slot=newSlots[hashcode];
while(!isNULLEntry(slot->nextEntry)){
slot=slot->nextEntry;
}
Entry * nxt = slot->nextEntry= malloc(sizeof(Entry*));
entryCpy(entry,nxt);
nxt->nextEntry=NULL;
entry=entry->nextEntry;
}
}
free(oldSlots);
}
void putEntry(RouterTable* RouterTable,Entry* entry){
rehash(RouterTable);
RouterTable->count++;
entry->nextEntry=NULL;
long slotCode=getHashSlot(RouterTable,entry);
Entry ** slots =RouterTable->slots;
Entry* slot=slots[slotCode];
if(isNULLEntry(slot)){
slots[slotCode]=slot=malloc(sizeof(Entry*));
entryCpy(entry,slot);
entryCpy(slot,slots[slotCode]);
return;
}
while(!isNULLEntry(slot->nextEntry)){
slot=slot->nextEntry;
}
slot->nextEntry=malloc(sizeof(Entry*));
entryCpy(entry,slot->nextEntry);
}
void addRoute(RouterTable* RouterTable,char* key,int(*run)(RequestContext* requestContext)){
Entry* entry=malloc(sizeof(Entry));
entry->key = key;
entry->run=run;
entry->nextEntry=NULL;
putEntry(RouterTable,entry);
}
Entry runRoute(RouterTable* RouterTable,char* key){
#ifdef DEBUG
printf("[runRoute]路由%s进入哈希表查找",key);
#endif
long slotCode = getHashSlotByKEY(RouterTable,key);
Entry* slot = RouterTable->slots[slotCode];
if(!isNULLEntry(slot)&&!strcmp(slot->key,key)){
#ifdef DEBUG
printf("[runRoute]路由%s在slot",key);
#endif
return *slot;
}
while(!isNULLEntry(slot->nextEntry)){
slot=slot->nextEntry;
if(!strcmp(slot->key,key)){
#ifdef DEBUG
printf("[runRoute]路由%s存在",key);
#endif
return *slot;
}
}
#ifdef DEBUG
printf("[runRoute]路由%s不存在",key);
#endif
return NOTFOUND_ENTRY;
}
#endif
由于是新的进程,所以我直接用哈希,如果是直接面向业务层来进行的请求的话,那么我建议这里可以做个渐进式哈希,便于后面实现通过UI来新增路由
请求上下文封装
RequestContext是啥?我们肯定还要对上下文进行封装,看看实现吧
//
// Created by 30398 on 2024/1/2.
//
#ifndef _REQUEST_CONTEXT_H
#define _REQUEST_CONTEXT_H
#include <stdlib.h>
#include <string.h>
#include "RouterAnalysis.h"
typedef struct {
char* uri;
char* routePath;
char** argName;
char** argValue;
char* routeParrtern;
char* method;
int argNums;
} RequestContext;
char* strdup(const char* str) {
// 获取字符串长度
size_t len = strlen(str);
// 分配足够的内存(包括字符串结尾的 '\0')
char* new_str = (char*)malloc(len + 1);
// 如果内存分配成功,则字符串并返回指针
if (new_str != NULL) {
strcpy(new_str, str);
}
return new_str;
}
RequestContext* initializeRequestContext(char* uri) {
// 分配内存给 RequestContext 结构体指针
RequestContext* context = (RequestContext*)malloc(sizeof(RequestContext));
#ifdef DEBUG
printf("[RequestContextInit] 正在给 %s 生成上下文,context对象生成中\n",uri);
#endif
// 检查内存分配是否成功
if (context == NULL) {
// 处理内存分配失败的情况
return NULL;
}
// "POST /api/login"
int pos=0;
context->uri = strdup(uri); // 假设有一个 strdup 函数用于字符串
char** argName= malloc(sizeof(char*)*50);
char** argValue=malloc(sizeof(char*)*50);
#ifdef DEBUG
printf("[RequestContextInit] URL参数分析中...\n");
#endif
int numArgs = UriParamAnlysis(uri, &argName, &argValue);
context->argNums=numArgs;
// 分配内存来存储 argName 和 argValue 数组的指针
context->routePath=strdup(UriRouteAnalysis(uri));
context->argName = (char**)malloc(numArgs * sizeof(char*));
context->argValue = (char**)malloc(numArgs * sizeof(char*));
context->method=malloc(sizeof(char)*10);
context->routeParrtern=malloc(sizeof(char)*256);
sscanf(uri,"%s %s",context->method,context->routeParrtern);
free(context->routeParrtern);
context->routeParrtern=malloc(sizeof(char)*512);
strcat(context->routeParrtern,context->method);
strcat(context->routeParrtern," ");
strcat(context->routeParrtern,context->routePath);
#ifdef DEBUG
printf("%s\n",context->method);
printf("%s\n",context->routeParrtern);
#endif
// 检查内存分配是否成功
if (context->argName == NULL || context->argValue == NULL) {
// 处理内存分配失败的情况
free(context->uri);
free(context->argName);
free(context->argValue);
free(context);
return NULL;
}
// 将解析后的参数拷贝到 context->argName 和 context->argValue 数组中
for (int i = 0; i < numArgs; ++i) {
context->argName[i] = strdup(argName[i]);
context->argValue[i] = strdup(argValue[i]);
}
// 释放 UriParamAnlysis 分配的内存
for (int i = 0; i < numArgs; ++i) {
free(argName[i]);
free(argValue[i]);
}
free(argName);
free(argValue);
#ifdef DEBUG
printf("[RequestContextInit] %s 上下文生成完毕,参数:",uri);
for (int i = 0; i < numArgs; ++i) {
printf("%s ",context->argName[i]);
}
printf("值:");
for (int i = 0; i < numArgs; ++i) {
printf("%s ",context->argValue[i]);
}
printf("\n");
#endif
return context;
}
// 函数用于释放 RequestContext 结构体占用的内存
void freeRequestContext(RequestContext* context) {
free(context->uri);
// 释放 argName 和 argValue 数组的指针所指向的字符串内存
for (int i = 0; context->argName[i]!=NULL; ++i) {
free(context->argName[i]);
free(context->argValue[i]);
}
// 释放 argName 和 argValue 数组的指针数组
free(context->argName);
free(context->argValue);
}
char** getParam(RequestContext* requestContext,char* argName){
#ifdef DEBUG
printf("正在查找参数%s",argName);
#endif
for (int i = 0; requestContext->argNums; ++i) {
if (strcmp(requestContext->argName[i], argName) == 0) {
return requestContext->argValue[i];
}
}
return NULL;
}
#endif
路由分析工具
还有一个路由分析工具
//
// Created by 30398 on 2023/12/30.
//
#ifndef _ROUERANALYSIS_H_
#define _ROUERANALYSIS_H_
#include <string.h>
char* UriRouteAnalysis(char *uri){
// 获取出连接的路由,去除hostname和参数 uri的格式为:METHOD URL(URI/?argkey=argvalue)
char *start = strdup(strchr(uri,' '));
start++;
char *end = strchr(start, '?');
if (end != NULL) {
*end = '\0';
}
#ifdef DEBUG
printf("uri【%s】解析成功:%s\n",uri,start);
#endif
char *result = start;
return result;
}
int UriParamAnlysis(const char* uri, char*** argName, char*** argValue) {
if(argName==NULL || argValue==NULL){
return 0;
}
char* pvstrs = strchr(uri, '?');
if (pvstrs == NULL) {
// 没有参数部分,直接返回
return 0;
}
// 创建字符串的副本进行解析
char* pvstrsCopy = strdup(pvstrs + 1);
if (pvstrsCopy == NULL) {
// 内存分配失败
return -1;
}
// 通过等号来分析,将每个参数 参数名放入params, value放在values
char* iter = strtok(pvstrsCopy, "&");
int numParams = 0;
// printf("%s\n",iter);
while (iter != NULL) {
char* eq = strchr(iter, '=');
if (eq != NULL) {
*eq = '\0';
char* key = iter;
char* value = eq + 1;
// 分配内存来存储参数名和参数值
(*argName)[numParams] = strdup(key);
(*argValue)[numParams] = strdup(value);
// printf("%s %s\n",(*argName)[numParams],(*argValue)[numParams]);
numParams++;
}
iter = strtok(NULL, "&");
}
// 释放副本的内存
free(pvstrsCopy);
return numParams;
}
#endif
JSON封装工具
响应是使用JSON,我这里用的很少,就不用CJson了,直接自己封装一个
//
// Created by 30398 on 2024/1/2.
//
#ifndef TINY_RESPONSE_H
#define TINY_RESPONSE_H
#include <stdio.h>
typedef struct {
int code;
char* data;
char* message;
}ResponseData;
char* toJSON(ResponseData* res){
int code=res->code;
char* data=res->data;
char* message=res->message;
char* resf= malloc(sizeof(char)*10240);
sprintf(resf,"{\n"
" \"code\": %d,\n"
" \"data\": \"%s\",\n"
" \"message\": \"%s\"\n"
"}\n",code,data,message);
return resf;
}
ResponseData* RES_SUCESS_DATA(char* data){
ResponseData* res = malloc(sizeof (ResponseData));
res->code=0;
res->data= strdup(data);
res->message="success";
return res;
}
ResponseData* RES_SUCESS(){
ResponseData* res = malloc(sizeof (ResponseData));
res->code=0;
res->data="";
res->message="success";
return res;
}
ResponseData* RES_FAIL(){
ResponseData* res = malloc(sizeof (ResponseData));
res->code=10001;
res->data="";
res->message="fail";
return res;
}
ResponseData* RES_FAIL_MESSAGE(char* message){
ResponseData* res = malloc(sizeof (ResponseData));
res->code=10001;
res->data="";
res->message= strdup(message);
return res;
}
ResponseData* RES_FAIL_CODE_MESSAGE(int code,char* message){
ResponseData* res = malloc(sizeof (ResponseData));
res->code=code;
res->data="";
res->message = strdup(message);
return res;
}
#endif //TINY_RESPONSE_H
主函数编写
好了,下面是主函数的编写
// 使用Demo
int main() {
// 这两句话放在主函数中
RouterTable *RouteHash = createDefaultRouterTable();
RouterInit(RouteHash);
redisInit();
char *buf=NULL;
char content[1024];
memset(content,0,sizeof content);
// /* Extract the two arguments */
// strdup(strcat(strdup(POST_ROUTE_LOGIN),"?username=admin&password=12345"))
if ((buf = getenv("QUERY_STRING")) != NULL) {
RequestContext *requestContext = initializeRequestContext(buf);
// 对于所有类型的请求拦截使用routePath
// 对于指令method使用 Parrtern,并且添加路由的时候命名规则为: “METHOD routerName”
#ifdef DEBUG
printf("[MAIN]进行路由处理 {Router: %s}\n",buf);
#endif
char* res=toJSON(runRoute(RouteHash, requestContext->routeParrtern).run(requestContext));
sprintf(content,"%s\r\n",res);
printf("Connection: close\r\n");
printf("Content-length: %d\r\n", (int)strlen(content));
printf("Content-type: text/json;charset=UTF-8\r\n\r\n");
printf("%s\r\n", content);
#ifdef DEBUG
printf("[MAIN]释放返回体content: %s\n",content);
#endif
fflush(stdout);
#ifdef DEBUG
printf("[MAIN]释放请求上下文requestContext\n");
#endif
freeRequestContext(requestContext);
}
else {
buf= strdup("NULL");
printf("Connection: close\r\n");
printf("Content-length: %d\r\n", 17);
printf("Content-type: text/html;charset=UTF-8\r\n\r\n");
printf("404 - NOT FIND of %s\r\n",buf);
fflush(stdout);
}
#ifdef DEBUG
printf("[MAIN]释放路由表\n");
#endif
freeRouterTable(RouteHash);
exit_status(0);
}
控制层调用
其中,这段代码是拿来进行Controller层执行的
char* res=toJSON(runRoute(RouteHash, requestContext->routeParrtern).run(requestContext));
咱们来看看Controller层的代码
Controller层
是不是有Java那味儿了?
//
// Created by 30398 on 2023/12/31.
//
#ifndef TINY_USER_CONTROLLER_H
#define TINY_USER_CONTROLLER_H
#include <string.h>
#include "../RequestAndResponse/RouterHash.h"
#include "./service/userdao.h"
// 使用define定义路由
const char* POST_ROUTE_LOGIN = "POST /api/login";
ResponseData* login(RequestContext* requestContext){
// 解析参数
char* username=getParam(requestContext,"username");
char* password=getParam(requestContext,"password");
if(loginOPER(username,password)){
return RES_SUCESS("登录成功");
}
return RES_FAIL_MESSAGE("密码错误或检查数据库连接");
}
const char* POST_ROUTE_REG = "POST /api/reg";
ResponseData* reg(RequestContext* requestContext){
// 解析参数
char* username=getParam(requestContext,"username");
char* password=getParam(requestContext,"password");
if(regOPER(username,password)){
return RES_SUCESS("注册成功");
}
return RES_FAIL_MESSAGE("注册失败,请检查数据库连接");
}
#endif //TINY_USER_CONTROLLER_H
Service层
看看Service层吧
//
// Created by 30398 on 2024/1/3.
//
#ifndef TINY_USERDAO_H
#define TINY_USERDAO_H
#include "daoconfig.h"
int loginOPER(char* username, char* password){
return !strcmp(getHashMapping("user",username),password);
}
int regOPER(char* username, char* password){
putHashMapping("user",username,password);
return 1;
}
#endif //TINY_USERDAO_H
Dao层
这里,我用的hiredis,课程设计原本使用sqlite3
//
// Created by 30398 on 2024/1/3.
//
#ifndef TINY_DAOCONFIG_H
#define TINY_DAOCONFIG_H
//#include <sqlite3.h>
//#define connectDB(db) sqlite3_open("/home/tiny/student_test.db", &db);
//#define closeDB(db) sqlite3_close(&db);
//#define store() connectDB(db);rc=sqlite3_exec(db, sql,NULL,NULL,NULL);closeDB(db);
//sqlite3 *db;
//int rc;
#include <hiredis/hiredis.h>
// 包含hiredis的所有包
#define __REDIS__IP "服务器账号"
#define __REDIS__PORT 服务器端口
#define __REDIS__PASSWORD "服务器密码"
redisContext* RedisContext;
void redisInit(){
// char *sql = "CREATE TABLE IF NOT EXISTS user (id integer constraint user_pk primary key,"
// "username text, "
// "password text);";
// store();
#ifdef DEBUG
printf("[MAIN]Redis连接中");
#endif
RedisContext = redisConnect(__REDIS__IP,__REDIS__PORT);
#ifdef DEBUG
printf("[MAIN]Redis正在鉴权");
#endif
redisCommand(RedisContext,"AUTH %s", __REDIS__PASSWORD);
#ifdef DEBUG
printf("[MAIN]Redis连接成功");
#endif
}
char* readValue(char* key){
redisReply *reply;
reply = redisCommand(RedisContext,"GET %s", key);
return reply->str;
}
void setValue(char* key, char* value){
redisCommand(RedisContext,"SET %s %s", key, value);
return;
}
char* deleteValue(char* key){
redisReply *reply;
reply = redisCommand(RedisContext,"DEL %s", key);
return reply->str;
}
int putHashMapping(char* key, char* field, char* value){
redisReply *reply;
reply=redisCommand(RedisContext,"HSET %s %s %s", key, field, value);
return reply->integer;
}
char* getHashMapping(char* key, char* field){
redisReply *reply;
reply = redisCommand(RedisContext,"HGET %s %s", key, field);
return reply->str;
}
void exit_status(int stat){
// closeDB(db);
#ifdef DEBUG
printf("[MAIN]释放Redis上下文\n");
#endif
redisFree(RedisContext);
exit(stat);
}
#endif //TINY_DAOCONFIG_H
路由添加
这个地方就有点像Golang了,哈哈,杂交语言组合完毕
//
// Created by 30398 on 2024/1/4.
//
#ifndef TINY_ROUTE_H
#define TINY_ROUTE_H
#include "RequestAndResponse/RequestContext.h"
#include "RequestAndResponse/Response.h"
#include "RequestAndResponse/RouterHash.h"
#include "controller/UserController.h"
#include "controller/service/daoconfig.h"
#include "../csapp.h"
// 路由方法初始化
void RouterInit(RouterTable* RouteHash){
#ifdef DEBUG
printf("[MAIN]路由表初始化中\n");
#endif
addRoute(RouteHash,POST_ROUTE_LOGIN,login);
addRoute(RouteHash,POST_ROUTE_REG,reg);
#ifdef DEBUG
printf("[MAIN]路由表初始化结束\n");
#endif
}
#endif //TINY_ROUTE_H