文件服务器架构
职责定义
主线程
- 命令行输入,管理员可控制服务端工作状态
监听线程
- 服务端启动后对客户端连接进行监听的工作环境
通讯线程
- 客户端连接成功后与服务端的数据交互环境
主线程
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 512
typedef 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.Software
D.T.Software @ Input >>> start
Server is OK!
D.T.Software @ Input >>> DoResp - Request : GET / HTTP/1.1
Host: 192.168.112.165:9000
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-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.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
DoResp - Req String: /1/2/3 // 提取到的文件路径 !!
Process_Thread - Thread Exit : 0x7f77ac000c90
DoResp - Request : GET /favicon.ico HTTP/1.1
Host: 192.168.112.165:9000
Connection: keep-alive
User-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.50
Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://192.168.112.165:9000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
DoResp - Req String: /favicon.ico
Process_Thread - Thread Exit : 0x7f77ac000b20
浏览器请求
思考
favivon.ico 是什么?如何处理?
如何创建浏览器中的文件展示页面?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。