请帮我填充开发报告。1. 前言
1.1. 项目简要说明
本项目。
在此简要描述项目背景、需求。可参考立项报告或软件开发任务书,进行概括或补充。项目一般对应机型,如WR741N 1.0。
1.2. 任务概述
说明本任务是项目的全部,还是项目的子模块,是新设计模块,还是对原有模块或代码的修改,等等。任务一般对应模块,如WR741N 1.0的防火墙模块。
1.3. 可用资源
可选,说明不需要重新开发的可利用资源,如现成的模块、控件和软件等。
1.4. 术语定义
列举本文所用的专门术语的定义和英文缩写词的原文及解释。注意,术语之间如有引用关系,被引用者列在前面。
1.5. 参考资料
参考资料指概要设计中引用的开发流程文档或规范,或者有利于加深概要设计理解的资料(读者必须能容易获得)。请在下面列出资料,并给出这些文件资料的标题、作者、编号、版本号、发表日期和出版单位或资料的来源:
经批准的开发文档;
引用的软件开发标准和规范;
说明本文档中引用的其他文件和资料。
2. 需求分析
强烈鼓励单独撰写需求分析文档。
如果没有单独的需求分析文档,在此分层次对需求进行分析。主要是分析以下方面:
界定系统的对外提供的功能(将对应于概要设计中的模块接口或系统界面);
详细的功能项及功能的分类(将对应于概要设计中的模块划分);
功能分类之间的关系(将对应于概要设计中的模块关系);
功能的作用或流程(将对应于概要设计中的模块内部建模);
提供上述功能时需要达到的性能(将影响概要设计中协议、算法等的选择)。
3. 原理概述
本章分析任务的重点原理,如协议、算法等等。如果需要原理概述,本章为概要设计的重点内容。不需要时删除本章。
注意,原理不是实现的结果,而是实现的依据。如果属于协议设计,要说明为什么要这样设计。移植型的任务,原理着重讲移植要注意的平台差异。修改/增加型的任务,原理着重讲修改或增加的部分。
以下小节如果内容较多,请扩展成独立的一章。
3.1. 协议分析(或设计)
本节分析要使用并实现的协议标准(如PPTP协议),或根据需求设计新协议(如防火墙产品用户认证协议)及设计的出发点和思路。不需要时删除本节。
3.1.1. 协议描述
概述协议实现的目标、原理等。
3.1.2. 协议数据格式
协议使用的数据格式,如网络网络协议的帧格式。
3.1.3. 协议描述
描述协议的以下方面:
协议收发包的方式,如使用socket还是其他接口,是否阻塞,等等。
协议模块与任务(或线程)的关系,如果涉及多任务,说明任务间通信的方式。
双方或多方进行协议通信的互交图、状态图或其他形式的描述。
3.2. 重要算法与数据结构
本节分析要实现的重要算法(如防火墙项目策略模块查找算法设计)、相关数据定义以及算法依赖的数据结构。
4. 系统构架描述
4.1. 概述
概要地叙述模块划分的原则,如通过对需求进行分析得到几类功能,从而相应地将系统分成几个模块。
注意:这里说的模块,指的是本任务之下划分的模块。如果本任务是产品的一个模块,那么这里的模块实际上是产品模块中的子模块。
4.2. 模块结构
辅于模块结构图等形式,表述模块的划分情况(根据、命名、结果)和模块之间的关系,说明模块的相互关系是本节的重点。
说明:这是设计中对复杂系统“分而治之”的过程。注意“分”的合理性,并通过对模块关系的分析,保持系统的功能完整性。
4.3. 模块描述和建模
逐一说明每个模块的基本情况,包括:模块自身的功能;对项目以内或以外其他模块提供的功能;模块的简要流程或算法的名称;模块的重要性;等等。
如果划分的模块有比较复杂的(如存在多个对象),则对模块进行建模:
首先介绍模块及其包括对象的功能和属性。
其次可以描述对象之间的关系,如成绩管理模块中,学生、成绩、班级等对象的关系。
然后可以描述模块的主要流程,如加密过程。
5. 任务(或进程/线程)设计
必须描述的内容。
如果本任务需要单独的任务(或进程/线程)或采用多任务(进程/线程)、线程池等,在本章描述任务或进程/线程的使用设计(包括它们与模块的关系)。即使没有增加新的任务或进程/线程,也要描述代码的运行方式。如果涉及中断处理的,同样要说明。
5.1. 原因
说明使用新的任务(或进程/线程)、采用多个任务(或进程/线程)或线程池的原因。
5.2. 任务(或进程/线程)内部流程
依次说明每个任务/进程/线程实现什么流程,如果前面已经有流程,指出对应关系即可。
5.3. 任务(或进程/线程)间通信
每两个需要进行信息交互的任务,都要说明通信的信息内容、交互方式。
6. 内存管理
如果需要内存的特别使用和管理,在本章说明,否则删除本章。
6.1. 说明
说明哪些数据类型需要进行特别管理,如:
作用
被哪些模块、函数、任务(或线程)使用
6.2. 设计
如何对内存进行管理,包括但不限于以下内容:
是否要互斥和/或同步
是否要反复申请、释放
内存维护方式
7. 出错处理
可选。复杂项目需要统一的出错处理,否则删除本节。
8. 用户界面概要设计
可选,如有用户界面(包括GUI和CLI),在本章描述界面设计,否则删除本章节。先说明界面的关系,再对每个主要界面进行说明。
8.1. 界面组织
说明界面设计的指导原则。用图表描述不同界面间的组织关系。
8.2. 界面设计
对主要界面进行设计。
9. 接口概要设计
本章的接口指提供给其他模块调用的接口。如果需要给其他模块或对外提供接口,在本章说明,否则删除本章。
接口的设计要与使用模块的设计人进行协商。要注意完整性(能实现所有需要的功能)和易用性(不能让使用者需要经过复杂的准备或步骤才能调用)。
9.1. 概述
说明接口设计思想。要说明是否达到完整性,给出充分理由。
9.2. 接口分类与功能
接口设计,包括接口的分类及功能说明,大致的输入和输出,等等。如果接口提供给不同模块使用,或接口分不同的功能,要进行分类并说明。
如果一些对外功能需要调用若干个接口的组合才能实际,请说明。
10. 开发环境、测试环境及部署环境
10.1. 开发环境
指明开发所需环境,如:
硬件(交叉编译时包括宿主机和目标机)
OS(交叉编译时包括宿主机和目标机)
编译器、集成开发环境
其他
10.2. 测试环境
测试所需环境。如网络拓扑、测试设备等。
10.3. 部署环境
开发成果的部署环境。包括需要使用的硬件、软件、网络环境等。注意部署的层次性,如DHCP Client模块,部署到vxWorks平台的无线路由器(在WAN口使用),再描述无线路由器的部署。
《简要描述即可》项目具体如下,分别使用多线程,多进程,IO多路复用实现一个简单的web server(端口80)承载附件的web。对比这三种实现方式各自的优缺点。 下面给出了process多进程服务器的代码样例,其余两个改动不大。/* Copyright(c) Lianzhou International Co.Ltd.
*
* file process_server.c
* brief This is a simple muti-process server.
*
* author Sun Haoming
* version 1.0.0
* date 25Aug14
*
* history
* \arg 1.0.0, 25Aug14, Sun Haoming, Create the file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
/**************************************************************************************************/
/* DEFINES */
/**************************************************************************************************/
#define PORT 80
#define BUFFER_SIZE 2048
/**************************************************************************************************/
/* TYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* EXTERN_PROTOTYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* LOCAL_PROTOTYPES */
/**************************************************************************************************/
const char *get_content_type(const char *path);
void send_response(int client_fd, const char *path);
/**************************************************************************************************/
/* VARIABLES */
/**************************************************************************************************/
/**************************************************************************************************/
/* LOCAL_FUNCTIONS */
/**************************************************************************************************/
/* 根据拓展名返回类型 */
const char *get_content_type(const char *path) {
const char *ext = strrchr(path, '.'); /* strrchr从末尾查找至. */
if (ext) {
if (strcmp(ext, ".html") == 0) return "text/html";
if (strcmp(ext, ".css") == 0) return "text/css";
if (strcmp(ext, ".js") == 0) return "application/javascript";
if (strcmp(ext, ".png") == 0) return "image/png";
if (strcmp(ext, ".jpg") == 0) return "image/jpeg";
}
return "application/octet-stream"; /*默认返回二进制流*/
}
/* 发送HTTP响应给客户端 */
void send_response(int client_fd, const char *path) {
char header[BUFFER_SIZE]; /*响应头buffer*/
char buffer[BUFFER_SIZE]; /*内容buffer*/
struct stat st; /*文件状态*/
/* 文件不存在 */
if (stat(path, &st) == -1) {
printf("该文件未找到:%s\n", path);
/* 404 文件头 */
snprintf(header, BUFFER_SIZE,
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<h1>404 Not Found</h1>");
send(client_fd, header, strlen(header), 0);
return;
}
/*读取文件*/
int fd = open(path, O_RDONLY);
if (fd < 0) {
printf("打开该文件失败: %s\n", path);
return;
}
/* 200 OK 文件头 */
snprintf(header, BUFFER_SIZE,
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"\r\n",
get_content_type(path), st.st_size);
send(client_fd, header, strlen(header), 0);
printf("发送文件: %s (大小: %ld 字节)\n", path, st.st_size);
/*发送给客户端*/
ssize_t bytes_read;
while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) {
send(client_fd, buffer, bytes_read, 0);
}
close(fd);
}
/*客户端请求线程*/
void handle_client(int client_fd) { /*直接接受int*/
char buffer[BUFFER_SIZE];
char path[BUFFER_SIZE] = "."; /* 默认./ */
char method[16] = {0}; /*存储请求方法*/
int content_length = 0; /* POST内容长度*/
char request_path[BUFFER_SIZE] = {0}; /* 存储原始请求路径*/
/*读取客户端请求*/
ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
if (bytes_read <= 0) {
printf("读取客户端请求失败\n");
close(client_fd);
return;
}
buffer[bytes_read] = '\0';
/* 获取客户端IP */
struct sockaddr_in addr;/*地址结构*/
socklen_t addr_len = sizeof(addr);/*地址长度*/
getpeername(client_fd, (struct sockaddr*)&addr, &addr_len);/*获取当前socket的对端地址*/
char client_ip[INET_ADDRSTRLEN];/*存储IP*/
inet_ntop(AF_INET, &addr.sin_addr, client_ip, sizeof(client_ip));/*将二进制IP转为字符串*/
printf("收到来自 %s 的请求:\n%.*s\n", client_ip, (int)bytes_read, buffer);
/* 解析请求方法 */
sscanf(buffer, "%s %s", method, request_path);
/* 获取GET请求 */
if (strcmp(method, "GET") == 0) {
/* 根目录请求*/
if (strcmp(request_path, "/") == 0) {
strcat(path, "/Index.html");
}
else {
strncat(path, request_path, BUFFER_SIZE - strlen(path) - 1);
}
send_response(client_fd, path);
}
/* 处理POST请求 */
else if (strcmp(method, "POST") == 0) {
char *body_start = strstr(buffer, "\r\n\r\n");
if (body_start) {
body_start += 4;
char *content_len_ptr = strstr(buffer, "Content-Length: ");
if (content_len_ptr) {
sscanf(content_len_ptr, "Content-Length: %d", &content_length);
}
/*处理表单提交*/
if (strstr(path, "/submit") != NULL) {
char response[BUFFER_SIZE];
snprintf(response, BUFFER_SIZE,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<html><body>"
"<h1>表单已提交</h1>"
"<p>收到数据: %.*s</p>"
"</body></html>",
content_length, body_start);
send(client_fd, response, strlen(response), 0);
printf("处理POST数据: %.*s\n", content_length, body_start);
}
}
}
/* 其他请求方法*/
else {
const char *resp = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";
send(client_fd, resp, strlen(resp), 0);
}
close(client_fd);
printf("请求处理完成\n");
return;
}
int main() {
signal(SIGPIPE, SIG_IGN); /*忽略SIGPIPE管道信号*/
printf("Web服务器启动,监听端口 %d \n", PORT);
/*创建TCP套接字*/
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("创建套接字失败");
exit(EXIT_FAILURE);
}
/*允许快速重启,地址重用*/
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/*配置服务器地址结构*/
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = INADDR_ANY
};
/* 绑定 */
if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("绑定端口失败");
exit(EXIT_FAILURE);
}
/* 监听 */
if (listen(server_fd, 10) < 0) {
perror("监听失败");
exit(EXIT_FAILURE);
}
printf("服务器已启动\n");
/* 持续接收客户端连接*/
while (1) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
/*阻塞等到下一个客户端连接*/
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
perror("接受连接失败");
continue;
}
/*非阻塞的回收僵尸进程,WNOHANG无子进程退出立即返回*/
while (waitpid(-1, NULL, WNOHANG) > 0);
/*创建子进程处理客户端请求*/
pid_t pid = fork();
if (pid < 0) {
perror("fork失败");
close(client_fd);
} else if (pid == 0) {
close(server_fd);/*子进程不用监听服务端*/
handle_client(client_fd); /*子进程处理客户端请求*/
exit(0);
} else {
close(client_fd); /*父进程不要客户端*/
}
}
close(server_fd);
return 0;
}
最新发布