An open API service indexing awesome lists of open source software.

https://github.com/yauntyour/appweb

appweb 开源执行端框架 具备集成的功能 性能极佳
https://github.com/yauntyour/appweb

c socket webapp

Last synced: about 2 months ago
JSON representation

appweb 开源执行端框架 具备集成的功能 性能极佳

Awesome Lists containing this project

README

          

# appweb (v3.0)
## !⚠️新版的架构已经发布为servic.cpp和router.cpp
具备简单的集成性基础功能。

模块架构:

- acc(接受请求)
- rsc(响应+调度器实现)
- RESRC(资源池)
- com(中心封装和集成)

全部二次封装&集成&C++ class封装于`appweb.h`。

## 详细内容

### example.cpp dome

```c
#include
#include
#include
#include "appweb.h"

static RESRC res;

FUNC_CB_C(api)
{
printf("%s\r\n", req->data.data);
return "{'test':'Hello,World'}";
};

FUNC_CB_C(POST_TEST)
{
#ifdef _WIN32
RESRC_FILE *p = RESRC_select_path(&res, "D:\\Dev\\appweb\\out\\post_test.html");
#else
RESRC_FILE *p = RESRC_select_path(&res, "/workspaces/appweb/out/post_test.html");
#endif
return p->data.data;
};

FUNC_CB_C(test)
{
return "

Hello,World

";
};

FUNC_CB_C(img)
{
// 在func内部使用send()需要使用func_CB_OUT,因为需要一个“\r\n”字符来终止标头
#ifdef _WIN32
RESRC_FILE *p = RESRC_select_path(&res, "D:\\Dev\\appweb\\out\\image.jpg");
#else
RESRC_FILE *p = RESRC_select_path(&res, "/workspaces/appweb/out/image.jpg");
#endif
FUNC_CB_OUT(req->addr.socket, p->data.data, p->data.length, 0);
// 返回包含“\0”是第一个字符的结果的字符串
return "";
}
void *func(void *arg)
{
#ifdef _WIN32
system("dir");
#else
system("ls -a");
#endif
return NULL;
}

#ifdef _WIN32
static FILE_PATH file_list[] = {
{"D:\\Dev\\appweb\\out\\post_test.html", "rb"},
{"D:\\Dev\\appweb\\out\\image.jpg", "rb"},
{NULL, NULL}};
#else
static FILE_PATH file_list[] = {
{"/workspaces/appweb/out/post_test.html", "rb"},
{"/workspaces/appweb/out/image.jpg", "rb"},
{NULL, NULL}};
#endif //_WIN32

int main(int argc, char const *argv[])
{
LOG_LIGHT_NF("%s\n", "Build application by Yauntyour (https://github.com/yauntyour) with C++");
RESRC_load_filelist(&res, file_list, 2);
#ifdef _WIN32
WS_Init();
#endif
appweb app(8, 10000, 3);
app.set_root_dict_func(test, Type_ALL, "text/html");
Varde home_list[] = {
Varde_def(POST_TEST, Type_GET, "postTest", COMPATH_True, "text/html"),
Varde_def(api, Type_POST, "api", COMPATH_True, "application/json"),
Varde_def(img, Type_GET, "img", COMPATH_True, "image/png"),
};
Varde home_dict[] = {
{test, Type_GET, "home", home_list, 3, 3, COMPATH_True, "text/html"},
{test, Type_GET, "index", home_list, 3, 3, COMPATH_True, "text/html"}};
app.root_dict_p->list_append(home_dict, sizeof(home_dict) / sizeof(Varde));
app.root_dict_p->ZIP();

app.add_event(func, NULL);
app.start(flag_wait);
#ifdef _WIN32
WS_clean();
#endif
for (size_t i = 0; file_list[i].path == NULL; i++)
{
RESRC_free(&(res.filelist[i]));
RESRC_FILE_CLOSE(&(res.filelist[i]));
}
return 0;
}
```

### example.c dome

```c
#include
#include
#include "appweb.h"

static RESRC res;

FUNC_CB_C(api)
{
printf("%s\r\n", req->data.data);
return "{'test':'Hello,World'}";
};
FUNC_CB_C(POST_TEST)
{
#ifdef _WIN32
RESRC_FILE *p = RESRC_select_path(&res, "D:\\Dev\\appweb\\out\\post_test.html");
#else
RESRC_FILE *p = RESRC_select_path(&res, "/workspaces/appweb/out/post_test.html");
#endif
return p->data.data;
};
FUNC_CB_C(test)
{
return "

Hello,World

";
};
FUNC_CB_C(img)
{
// 在func内部使用send()需要使用func_CB_OUT,因为需要一个“\r\n”字符来终止标头
#ifdef _WIN32
RESRC_FILE *p = RESRC_select_path(&res, "D:\\Dev\\appweb\\out\\image.jpg");
#else
RESRC_FILE *p = RESRC_select_path(&res, "/workspaces/appweb/out/image.jpg");
#endif
FUNC_CB_OUT(req->addr.socket, p->data.data, p->data.length, 0);
// 返回包含“\0”是第一个字符的结果的字符串
return "";
}

void *func(void *arg)
{
#ifdef _WIN32
system("dir");
#else
system("ls -a");
#endif
return NULL;
}

#ifdef _WIN32
static FILE_PATH file_list[] = {
{"D:\\Dev\\appweb\\out\\post_test.html", "rb"},
{"D:\\Dev\\appweb\\out\\image.jpg", "rb"},
{NULL, NULL}};
#else
static FILE_PATH file_list[] = {
{"/workspaces/appweb/out/post_test.html", "rb"},
{"/workspaces/appweb/out/image.jpg", "rb"},
{NULL, NULL}};
#endif //_WIN32

int main(int argc, char const *argv[])
{
LOG_LIGHT_NF("%s\n", "Build application by Yauntyour (https://github.com/yauntyour) with C");
RESRC_load_filelist(&res, file_list, 2);
#ifdef _WIN32
WS_Init();
#endif
appev_t ev;
ev.port = 10000;
ev.UTCoffset = 8;
// UDP_CONNECT or TCP_CONNECT
ev.connect_type = TCP_CONNECT; // Use TCP connection
// ev.connect_type = UDP_CONNECT;

app_event_init(&ev, 128);

// root event
set_root_dict_func(&ev, test, Type_ALL, "text/html");
// root list
ev.root_dict.list_length = 0;
ev.root_dict.list_size = 0;
ev.root_dict.list = NULL;

Varde home_list[] = {
Varde_def(POST_TEST, Type_GET, "postTest", COMPATH_True, "text/html"),
Varde_def(api, Type_POST, "api", COMPATH_True, "application/json"),
Varde_def(img, Type_GET, "img", COMPATH_True, "image/png"),
};
Varde home_dict[] = {
{test, Type_GET, "home", home_list, 3, 3, COMPATH_True, "text/html"},
{test, Type_GET, "index", home_list, 3, 3, COMPATH_True, "text/html"}};

Varde_list_append(&(ev.root_dict), home_dict, sizeof(home_dict) / sizeof(Varde));
Varde_ZIP(&(ev.root_dict));

// set a event func out of server
ev.event_func = func;

pthread_t acc_th;
app_acc(&acc_th, &ev);
pthread_join(acc_th, NULL);
#ifdef _WIN32
WS_clean();
#endif
for (size_t i = 0; file_list[i].path == NULL; i++)
{
RESRC_free(&(res.filelist[i]));
RESRC_FILE_CLOSE(&(res.filelist[i]));
}
return 0;
}
```

### 基本使用

Varde 的基本原理和结构————树级目录
[![](tree.png)](Tree)

1. 注册一个Varde,其结构为

```C
/*
necessary arg:
char* Name :node's Name;
func_cb func :A deal by function;
int req_Type :request model;
struct varde *list :A node list this node;
size_t list_length, list_size :The list's length & size;
int ComPath :Common path resolution:true or false;
if req_model == -1,it will disable this Varde;
*/
typedef struct varde
{
func_cb func;
int req_Type;
char *Name; // The Name of varde
struct varde *list;
size_t list_length;
size_t list_size;
int ComPath; // Common path resolution:true or false
char *resp_mime_type;
#ifdef __cplusplus
int append(struct varde *Var);
int ZIP();
int list_append(struct varde *dict, size_t len);
#endif //__cplusplus
} Varde;

//函数类型为:
typedef char *(*func_cb)(req_t *, bytes *);
//利用该宏可以快速定义一个标准函数(参见example dome)
#define FUNC_CB_C(__name__) char *__name__(req_t *req, bytes *header)
//显然我们可以通过bytes组件库提供的操作函数为header添加内容。
//但是要注意,header尚未调用bytes_create。
//理论上根据规范,您只需要返回页面的内容,调度器会自动写入响应流的末尾。

//如果你要在定义的FUNC_CB里使用内容输出:请使用这个宏
#define FUNC_CB_OUT(__arg__...) send(req->addr.socket, "\r\n",2, 0);send(__arg__)
//就像这样:
FUNC_CB_C(img)
{
// 在func内部使用send()需要使用func_CB_OUT,因为需要一个“\r\n”字符来终止标头
RESRC_FILE *p = RESRC_select_path(&res, "K:\\CCXXProgram\\appweb\\out\\bg.jpg");
FUNC_CB_OUT(req->addr.socket, p->data.data, p->data.length, 0);
// 返回包含“\0”是第一个字符的结果的字符串
return "";
}
```

我们提供一个快捷注册的宏

```c++
#define Varde_def(func, req_Type, Name, ComPath) \
{ \
func, req_Type, Name, NULL, 0, 0, ComPath \
}
//eg: Varde var = Varde_def(test,req_ALL,"test",COMPATH_True);
```

同时可以使用`append(struct varde *Var)`与`list_append(struct varde *dict, size_t len)`函数便捷地添加Varde节点或是直接追加Varde列表。

```c++
app.set_root_dict_func(test, Type_ALL, "text/html");
Varde home_list[] = {
Varde_def(POST_TEST, Type_GET, "postTest", COMPATH_True, "text/html"),
Varde_def(api, Type_POST, "api", COMPATH_True, "application/json"),
Varde_def(img, Type_GET, "img", COMPATH_True, "image/png"),
};
Varde home_dict[] = {
{test, Type_GET, "home", home_list, 3, 3, COMPATH_True, "text/html"},
{test, Type_GET, "index", home_list, 3, 3, COMPATH_True, "text/html"}};
app.root_dict_p->list_append(home_dict, sizeof(home_dict) / sizeof(Varde));//追加列
app.root_dict_p->ZIP();//删除冗余内存
```

2. 使用`app.start(flag_wait);`执行服务。执行端会监听您提供的port。flag设置为0表示默认阻塞运行。

3. 使用`app.add_event(func, NULL);`为程序添加额外的事件服务函数。

```c++
void *func(void *arg)
{
#ifdef _WIN32
system("dir");
#else
system("ls -a");
#endif
return NULL;
}
app.add_event(func, NULL);//添加事件函数,会在acc线程执行后执行此线程
```

可以在开启服务器的同时,额外注册一个线程执行自定义的内容,例如启动SQL服务、Python脚本等等。

### 相关基础信息

```c++
typedef struct appev
{
IPv4_addr_t tcpip, udpip;
unsigned int port;
Varde root_dict;
size_t MAXCONNECT;
int UTCoffset;
int connect_type; // 0:TCP, 1:UDP, 2:ALL
void *(*event_func)(void *arg);//事件注册函数
void *arg;//参数指针
pthread_t event_th;
} appev_t;
```

### SDK&Debug&Python实现的调试工具

1. nc.py

```python
#参数
if sys.argv[1] == '-nc':
netcat()
elif sys.argv[1] == '-cli':
UDPclientSend()
elif sys.argv[1] == '-server':
Server()
else:
print("no this mode")
print("argv format: -mode host port recvbufflen/data (Server socketTypes:STREAM/DGRAM)")
##argv format: -mode host port recvbufflen/data (Server socketTypes:STREAM/DGRAM)
#eg :python nc.py -cli 127.0.0.1 10000 1280 STREAM
```

2. netools.py

```python
#可以自行修改msg的内容
msg = "GET /home HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2\r\n\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8\r\nAccept-Language: zh-cn,zh;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nReferer: http://localhost/\r\nContent-Length: 25\r\nContent-Type: application/x-www-form-urlencoded\r\nusername=aa&password=1234"

if sys.argv[1] == '-nc':
netcat()
else:
print("argv format: -mode host port recvbufflen")
#argv format: -mode host port recvbufflen
```

# 关键的依赖库

## Windows下使用appweb库看起来这样(Windows下socket 需要 wsock32.lib)

```
g++ -g XXXX.cpp -o XXXX -fexec-charset=UTF-8 -lwsock32 -lpthread
```

## Linux下使用appweb库看起来是这样的

```
g++ -g XXXX.cpp -o XXXX -fexec-charset=UTF-8 -lpthread
```

## 只需包含根目录下的appweb.h(C/C++完全封装)即可调用此库

### **Made by yauntyour Copyright reserved**

### e-mail:yauntyour@outlook.com

### Copyright see the file LICENSE