文件服务器架构
职责定义
主线程
- 命令行输出,管理员可管制服务端工作状态
监听线程
- 服务端启动后对客户端连贯进行监听的工作环境
通信线程
- 客户端连贯胜利后与服务端的数据交互环境
主线程
int main(int argc, char *argv){ if (argc >=2) { DIR *dir = opendir(argv[1]); if (dir != NULL) { close(dir); Run(argv[1]); } } printf("Can not launch File Server, need a valid director as root.\n"); return 0;}
if (*line) { char *cmd = FormatByChar(line, ' '); // 此处的作用次要为去除前后空格 int done = 0; for (i=0; i<DIM(g_handler); ++i) { if (strcmp(g_handler[i].cmd, cmd) == 0) { g_handler[i].handler(cmd); done = 1; break; } } if (!done) { printf("\'%s\' can NOT be parser!\n", cmd); } free(cmd);}
交互流程一
交互流程二
监护线程
static void *Server_Thread(void *arg){ while (TcpServer_IsValid(arg)) { TcpClient *client = TcpServer_Accept(arg); if (client &&(g_status != PAUSE)) { pthread_t tid = 0; pthread_create(&tid, NULL, Process_Thread, client); } else { TcpClient_Del(client); } } printf("%s - Thread Exit : %p\n", __FCUNTION__, arg); g_status = STOP;}
申请响应流程
通信流程
static void DoResp(TcpClient *client){ int len = TcpClient_Available(client); if (len > 0) { char *buf = malloc(len + 1); TcpClient_RecvRaw(client, buf, len); buf[len] = 0; char resp[255] = {0}; // do process to create response TcpClient_SendRaw(client, resp, strlen(resp)); TcpClient_Del(client); free(buff); }}
编程试验:实现申请响应
main.c
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include <sys/types.h>#include <dirent.h>#include <sys/stat.h>#include <time.h>#include <fcntl.h>#include <string.h>#include "tcp_server.h"#include "tcp_client.h" #include "utility.h"#define BUF_SIZE 512typedef struct { const char *cmd; void (*handler)(const char *);}Handler;enum {STOP, RUN, PAUSE};static const volatile char *g_root = NULL;static volatile int g_status = STOP;static void DoResp(TcpClient *client){ int len = TcpClient_Available(client); if (len > 0) { char *buf = malloc(len + 1); len = TcpClient_RecvRaw(client, buf, len); if (len > 0) { buf[len] = 0; printf("%s - Request : %s\n", __FUNCTION__, buf); char resp[255] = {0}; sscanf(buf, "GET %s HTTP\n", resp); // 提取文件门路 !! printf("%s - Req String: %s\n", __FUNCTION__, resp); char* format = "HTTP/1.1 200 OK\r\n" "Server:D.T. Http Server\r\n" "Content-Length:%d\r\n" "Content-Type:text/html\r\n" "Connection:close\r\n" "\r\n" "%s"; sprintf(resp, format, strlen((const char*)g_root), g_root); TcpClient_SendRaw(client, resp, strlen(resp)); TcpClient_Del(client); } free(buf); }}static void *Process_Thread(void *arg){ while (TcpClient_IsValid(arg)) { DoResp(arg); } printf("%s - Thread Exit : %p\n", __FUNCTION__, arg); return arg;}static void *Server_Thread(void *arg){ while (TcpServer_IsValid(arg)) { TcpClient *client = TcpServer_Accept(arg); if (client && (g_status != PAUSE)) { pthread_t tid = 0; pthread_create(&tid, NULL, Process_Thread, client); } else { TcpClient_Del(client); } } g_status = STOP; return arg;}static void Start_Handler(const char *arg){ int err = 0; if (g_status == STOP) { TcpServer *server = TcpServer_New(); TcpServer_Start(server, 9000, 100); if (TcpServer_IsValid(server)) { pthread_t tid = 0; err = pthread_create(&tid, NULL, Server_Thread, server); } else { err = 1; } } if (!err) { g_status = RUN; printf("Server is OK!\n"); } else { g_status = STOP; printf("Server is failed!\n"); }}static void Pause_Handler(const char *arg){ if (g_status == RUN) { g_status = PAUSE; printf("Server is paused!\n"); } else { printf("Server is NOT started!\n"); }}static void Exit_Handler(const char *arg){ exit(0);}static Handler g_handler[] = { {"start", Start_Handler}, {"pause", Pause_Handler}, {"exit", Exit_Handler}};static void Run(const char *root){ printf("File Server Demo @ D.T.Software\n"); g_root = root; while (1) { char line[BUF_SIZE] = {0}; int i = 0; printf("D.T.Software @ Input >>> "); fgets(line, sizeof(line) - 1, stdin); line[strlen(line) - 1] = 0; if (*line) { char *cmd = FormatByChar(line, ' '); int done = 0; for (i-0; i<DIM(g_handler); ++i) { if (strcmp (g_handler[i].cmd, cmd) == 0) { g_handler[i].handler(cmd); done = 1; break; } } if (!done) { printf("'\%s\' can NOT be parsed!\n", cmd); } free(cmd); } }}int main(int argc, char *argv[]){ if (argc >= 2) { DIR *dir = opendir(argv[1]); if (dir != NULL) { closedir(dir); Run(argv[1]); } } printf("Can not launch File Server, need a valid directory as roots.\n"); return 0;}
输入:
tiansong@tiansong:~/Desktop/network/web$ ./a.out ./File Server Demo @ D.T.SoftwareD.T.Software @ Input >>> startServer is OK!D.T.Software @ Input >>> DoResp - Request : GET / HTTP/1.1Host: 192.168.112.165:9000Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.50Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6DoResp - Req String: /1/2/3 // 提取到的文件门路 !!Process_Thread - Thread Exit : 0x7f77ac000c90DoResp - Request : GET /favicon.ico HTTP/1.1Host: 192.168.112.165:9000Connection: keep-aliveUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.50Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8Referer: http://192.168.112.165:9000/Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6DoResp - Req String: /favicon.icoProcess_Thread - Thread Exit : 0x7f77ac000b20
浏览器申请
思考
favivon.ico 是什么?如何解决?
如何创立浏览器中的文件展现页面?