共计 6232 个字符,预计需要花费 16 分钟才能阅读完成。
需要剖析
- 服务端启动时指定某本地文件夹作为网络共享文件夹
- 共享文件夹中的所有文件及子文件夹均可被客户端拜访
- 应用浏览器作为客户端,在浏览器中可“看到”所有共享文件
- 用户可在浏览器中将指标文件下载到本地
- 服务端可暂定服务,但不影响正在下载指标文件的客户端
技术可行性剖析
-
服务端网络通讯
- 基于 Http 协定与客户端浏览器通信
- 可应用 tcp socket 实现对 Http 协定的反对
-
服务端文件操作
- 获取文件夹中的所有文件及子文件夹
- 返回文件列表 或 返回文件内容
零碎概要设计
基础设施
- Socket – Http 协定以 TCP 协定为底座
- Thread – 同时对多个客户端服务(申请响应)
- File – 文件夹信息读取,文件属性读取,文件数据读取
基础设施一(Socket)
- 思考:是否应用课程中的网络通讯框架作为基础设施?
-
答:
临时不能
-
课程中通信框架的服务端基于 select 机制,即:
- 服务端工作时会导致程序阻塞(程序无奈持续向下执行)
- 每次只服务一个客户端(当服务工夫过长,会影响其它服务端通信)
-
文件服务器工作模型
网络通讯框架改良计划
-
新增服务端函数
-
TcpClient *TcpServer_Accept(TcpServer *server);
- 阻塞函数,调用后始终期待客户端连贯
- 返回与客户端通信的 TcpClient 构造体
- 返回的 TcpClient 构造体互相独立,并且独立于服务端
-
TcpClient *TcpServer_Accept(TcpServer *server) | |
{ | |
TcpClient *ret = NULL; | |
if (server) {Server *s = (Server*)server; | |
struct sockaddr_in caddr = {0}; | |
socklen_t asize =sizeof(caddr); | |
int fd = accept(s->fd, (struct sockaddr*)&caddr, &asize); | |
if (fd > -1) {ret = TcpClient_From(fd); | |
if (!ret) close(fd); | |
} | |
} | |
return ret; | |
} |
基础设施二(Thread)
- 过程:应用程序的一次加载执行(零碎进行资源分配的根本单位)
-
线程:过程中的程序执行流
- 一个过程中能够存在多个线程(至多存在一个线程)
- 每个线程执行不同的工作(多个线程可并行执行)
- 同一个过程中的多个线程共享过程的系统资源
## Linux 多线程 API
- 头文件:
#include <pthread.h>
- 线程创立函数:
int pthread_create(pthread_t *thread, | |
const pthread_attr_t *attr, | |
void *(start_routine)(void*), | |
void *arg); | |
thread: pthread_t 变量的地址,用于返回线程标识 | |
attr: 线程的属性,可设置为 NULL,即:应用默认属性 | |
start_routine: 线程入口函数 | |
arg: 线程入口函数参数 |
-
线程标识
- pthread_t pthread_self(void);
- 获取以后线程的 ID 标识
线程期待
int pthread_join(pthread_t thread, void **retval);
- 期待指标线程执行完结
多线程编程示例
void *thread_entry(void *arg) | |
{pthread_t id = pthread_self(); | |
int n = (long)(arg); | |
int i = 0; | |
for (i=0; i<n; ++i) {printf("tid = %ld, i = %d\n", id, i); | |
sleep(1); | |
} | |
return arg; | |
} | |
int main() | |
{ | |
pthread_t t1 = 0; | |
pthread_t t2 = 0; | |
int arg1 = 5; | |
int arg2 = 10; | |
printf("create thread...\n"); | |
pthread_create(&t1, NULL, thread_entry, (void*)arg1); | |
pthread_create(&t2, NULL, thread_entry, (void*)arg2); | |
printf("t1 = %ld\n", t1); | |
printf("t2 = %ld\n", t2); | |
pthread_join(t1, NULL); | |
pthread_join(t1, NULL); | |
printf("child thread is finished...\n"); | |
} |
基础设施三(Dir)
#include <sys/stat.h>
#include <dirent.h>
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
int stat(const char *file_name, struct stat *buf);
文件夹编程示例
DIR *dirp = opendir("."); | |
if (dirp != NULL) { | |
struct dirent *dp = NULL; | |
while ((dp = readdir(dirp)) != NULL) {struct stat sb = {0}; | |
if (stat(dp->d_name, &sb) != -1) { | |
printf("name: %s, type: %d, len: %ld, mtime: %s", | |
dp->d_name, dp->d_type, sb.st_size, ctime(&sb.st_mtime)); | |
} | |
} | |
} |
基础设施四(File)
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
sszie_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
文件编程示例
void file_copy(const char *dst, const char *src) | |
{int dfd = open(dst, O_WRONLY|O_CREAT, 0600); | |
int sfd = open(src, O_RDONLY); | |
if ((dfd != -1) && (sfd != -1)) {char buf[512] = {0}; | |
int len = 0; | |
while ((len = read(sfd, buf, sizeof(buf))) > 0) {write(dfd, buf, len); | |
} | |
} | |
close(dfd); | |
close(sfd); | |
} |
编程试验:后期技术筹备
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 "tcp_server.h" | |
#include "tcp_client.h" | |
void func1() | |
{TcpServer *s = TcpServer_New(); | |
TcpServer_Start(s, 9000, 100); | |
if (TcpServer_IsValid(s)) {char buf[64] = {0}; | |
int len = 0; | |
TcpClient *c = TcpServer_Accept(s); | |
if (c) {len = TcpClient_RecvRaw(c, buf, sizeof(buf) - 1); | |
buf[len] = 0; | |
printf("recv = %s\n", buf); | |
TcpClient_SendRaw(c, buf, len); | |
TcpClient_Del(c); | |
} | |
TcpServer_Del(s); | |
} | |
} | |
void *thread_entry(void *arg) | |
{pthread_t id = pthread_self(); | |
int n = (long)(arg); | |
int i = 0; | |
for (i=0; i<n; ++i) {printf("tid = %ld, i = %d\n", id, i); | |
sleep(1); | |
} | |
return arg; | |
} | |
void func2() | |
{ | |
pthread_t t1 = 0; | |
pthread_t t2 = 0; | |
int arg1 = 5; | |
int arg2 = 10; | |
printf("create thread...\n"); | |
pthread_create(&t1, NULL, thread_entry, (void*)arg1); | |
pthread_create(&t2, NULL, thread_entry, (void*)arg2); | |
printf("t1 = %ld\n", t1); | |
printf("t2 = %ld\n", t2); | |
pthread_join(t1, NULL); | |
pthread_join(t1, NULL); | |
printf("child thread is finished...\n"); | |
} | |
void func3() | |
{DIR *dirp = opendir("."); | |
if (dirp != NULL) { | |
struct dirent *dp = NULL; | |
while ((dp = readdir(dirp)) != NULL) {struct stat sb = {0}; | |
if (stat(dp->d_name, &sb) != -1) { | |
printf("name: %s, type: %d, len: %ld, mtime: %s", | |
dp->d_name, dp->d_type, sb.st_size, ctime(&sb.st_mtime)); | |
} | |
} | |
} | |
} | |
void file_copy(const char *dst, const char *src) | |
{int dfd = open(dst, O_WRONLY|O_CREAT, 0600); | |
int sfd = open(src, O_RDONLY); | |
if ((dfd != -1) && (sfd != -1)) {char buf[512] = {0}; | |
int len = 0; | |
while ((len = read(sfd, buf, sizeof(buf))) > 0) {write(dfd, buf, len); | |
} | |
} | |
close(dfd); | |
close(sfd); | |
} | |
int main(void) | |
{printf("=====================\n"); | |
func1(); | |
printf("=====================\n"); | |
func2(); | |
printf("=====================\n"); | |
func3(); | |
printf("=====================\n"); | |
file_copy("new.out", "a.out"); | |
return 0; | |
} |
输入
===================== | |
recv = http://www.cmsoft.cn | |
===================== | |
create thread... | |
t1 = 140155835639552 | |
t2 = 140155827246848 | |
tid = 140155835639552, i = 0 | |
tid = 140155827246848, i = 0 | |
tid = 140155835639552, i = 1 | |
tid = 140155827246848, i = 1 | |
tid = 140155835639552, i = 2 | |
tid = 140155827246848, i = 2 | |
tid = 140155835639552, i = 3 | |
tid = 140155827246848, i = 3 | |
tid = 140155835639552, i = 4 | |
tid = 140155827246848, i = 4 | |
tid = 140155827246848, i = 5 | |
child thread is finished... | |
===================== | |
name: utility.c, type: 8, len: 1875, mtime: Sun Jun 4 18:34:38 2023 | |
name: server_task.o, type: 8, len: 6872, mtime: Sun Jun 4 18:34:38 2023 | |
name: .., type: 4, len: 4096, mtime: Sun Jun 4 18:34:29 2023 | |
name: tcp_server.c, type: 8, len: 4978, mtime: Sun Jun 4 19:29:28 2023 | |
name: main.c, type: 8, len: 2353, mtime: Sun Jun 4 20:01:53 2023 | |
name: udp_point.h, type: 8, len: 860, mtime: Sun Jun 4 18:34:38 2023 | |
name: ., type: 4, len: 4096, mtime: Sun Jun 4 20:02:37 2023 | |
name: tcp_client.h, type: 8, len: 932, mtime: Sun Jun 4 18:34:38 2023 | |
name: new.out, type: 8, len: 29136, mtime: Sun Jun 4 20:02:18 2023 | |
name: message.h, type: 8, len: 482, mtime: Sun Jun 4 18:34:38 2023 | |
name: tcp_server.o, type: 8, len: 5864, mtime: Sun Jun 4 19:32:19 2023 | |
name: msg_parser.o, type: 8, len: 3960, mtime: Sun Jun 4 19:32:19 2023 | |
name: msg_parser.c, type: 8, len: 4218, mtime: Sun Jun 4 18:34:38 2023 | |
name: a.out, type: 8, len: 29136, mtime: Sun Jun 4 20:02:37 2023 | |
name: tcp_client.c, type: 8, len: 3825, mtime: Sun Jun 4 18:34:38 2023 | |
name: msg_parser.h, type: 8, len: 327, mtime: Sun Jun 4 18:34:38 2023 | |
name: utility.o, type: 8, len: 2752, mtime: Sun Jun 4 19:32:19 2023 | |
name: tcp_server.h, type: 8, len: 770, mtime: Sun Jun 4 19:29:33 2023 | |
name: message.o, type: 8, len: 2608, mtime: Sun Jun 4 19:32:19 2023 | |
name: msg_def.h, type: 8, len: 134, mtime: Sun Jun 4 18:34:38 2023 | |
name: tcp_client.o, type: 8, len: 5472, mtime: Sun Jun 4 19:32:19 2023 | |
name: message.c, type: 8, len: 1202, mtime: Sun Jun 4 18:34:38 2023 | |
name: utility.h, type: 8, len: 1539, mtime: Sun Jun 4 18:34:38 2023 | |
name: udp_point.c, type: 8, len: 4793, mtime: Sun Jun 4 18:34:38 2023 | |
name: Makefile, type: 8, len: 274, mtime: Sun Jun 4 18:34:38 2023 | |
name: udp_point.o, type: 8, len: 6232, mtime: Sun Jun 4 19:32:19 2023 | |
name: main.o, type: 8, len: 5592, mtime: Sun Jun 4 20:01:56 2023 | |
===================== |
正文完