网络编程——实现HTTP服务器端

2023-10-27

参考

  1. 《TCP/IP网络编程》 尹圣雨

Web服务器端

概述

Web服务器端是,基于HTTP(Hypertext Transfer Protocol)协议,将网页对应文件传输给客户端的服务器端。

Hypertext(超文本)是可以根据客户端请求而跳转的结构化信息。

HTTP协议是以超文本传输为目的而设计的应用层协议,同样基于TCP/IP实现。

浏览器属于基于套接字的客户端,因为连接到任意Web服务器端时,浏览器内部也会创建套接字。只是浏览器将服务器端传输的HTML格式的超文本解析为可读性较强的视图。

HTTP协议特点

无状态的Stateless协议

服务器端响应客户端请求后立即断开连接,即服务器端不会维持客户端状态。即使同一客户端再次发送请求,服务器还是以相同的方式处理新请求

为此,Web编程中通常会使用Cookie和Session技术

请求消息的结构

请求消息可以分为请求行、消息头、消息体等

(1)请求行

GET /index.html HTTP/1.1

含义是,请求(GET)index.html文件,希望以1.1版本的HTTP协议进行通信

请求行只能通过1行发送。请求行含有请求方式(目的)信息。典型的请求方式有GET和POST,GET主要用于请求数据,POST主要用于传输数据

(2)消息头

User Agent : Mozilla/5.0
Accept: image/gif, image/jpeg
......

消息头中包含发送请求的浏览器信息、用户认证信息等关于HTTP消息的附加信息
(3)空行
避免边界问题
(4)消息体
消息体仅在以POST方式请求时插入

消息体中装有客户端向服务器端传输的数据

响应消息的结构

响应消息由状态行、头信息、消息体等3个部分构成

(1)状态行

HTTP/1.1 200 OK

含义是,我想用HTTP1.1版本进行响应,你的请求已正确处理(200 OK)

状态行含有关于客户端请求的处理结果。表示“客户端请求的执行结果”的数字称为状态码,例如:

  1. 200 OK:成功处理了请求
  2. 404 Not Found:请求的文件不存在
  3. 400 Bad Request:请求方式错误,请检查

(2)消息头

Server : SimpleWebServer
Content-type : text/html
Content-length : 2048
......

含义是,服务器端名为SimpleWebServer,传输的数据类型为text/html,数据长度不超过2048字节

消息头中含有传输的数据类型和长度等信息

(3)空行
(4)消息体

<html>
......
<body>
......
</html>

通过消息体发送客户端请求的文件数据

实现Web服务器端

Web服务器端采用HTTP协议,即使用IOCP或epoll模型也不会大幅提升性能,因为客户端和服务器端交换1次数据后将立即断开连接,没有足够时间发挥IOCP或epoll的优势。在服务器端和客户端保存较长连接的前提下频繁发送大小不一的消息时(如网游服务器端),才能发挥这2种模型的优势

下面通过多线程模型实现Web服务器端。客户端每次请求时,都创建1个新线程响应
(1)基于Windows

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include <process.h>
#include <WS2tcpip.h>
#define BUF_SIZE 2048
#define BUF_SMALL 100

unsigned WINAPI RequestHandler(void* arg);
char* ContentType(char* file);
void SendData(SOCKET sock, char* ct, char* fileName);
void SendErrorMSG(SOCKET sock);
void ErrorHandling(char* message);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hServSock, hClntSock;
	SOCKADDR_IN servAdr, clntAdr;

	HANDLE hThread;
	DWORD dwThreadID;
	int clntAdrSize;
	char tmpbuf[20] = { 0 };

	if (argc != 2)
	{
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		ErrorHandling("WSAStartup() error!");
	}

	hServSock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAdr.sin_port = htons(atoi(argv[1]));

	if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
	{
		ErrorHandling("bind() error");
	}
	if (listen(hServSock, 5) == SOCKET_ERROR)
	{
		ErrorHandling("listen() error");
	}

	/*请求及响应*/
	while (1)
	{
		clntAdrSize = sizeof(clntAdr);
		hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);
		printf("Connection Request : %s:%d\n", inet_ntop(AF_INET, &clntAdr.sin_addr, tmpbuf, sizeof(tmpbuf)), ntohs(clntAdr.sin_port));
		hThread = (HANDLE)_beginthreadex(NULL, 0, RequestHandler, (void*)hClntSock, 0, (unsigned*)&dwThreadID);
	}
	closesocket(hServSock);
	WSACleanup();
	return 0;
}

unsigned WINAPI RequestHandler(void* arg)
{
	printf("RequestHandler\n");
	SOCKET hClntSock = (SOCKET)arg;
	char buf[BUF_SIZE];
	char method[BUF_SMALL];
	char ct[BUF_SMALL];
	char fileName[BUF_SMALL];
	char* tmp = NULL;

	recv(hClntSock, buf, BUF_SIZE, 0);
	if (strstr(buf, "HTTP/") == NULL)                         // 查看是否为HTTP提出的请求
	{
		SendErrorMSG(hClntSock);
		closesocket(hClntSock);
		return 1;
	}

	strcpy_s(method, BUF_SMALL, strtok_s(buf, " /", &tmp));
	if (strcmp(method, "GET"))                                // 查看是否为GET方式请求 
	{
		SendErrorMSG(hClntSock);
	}

	strcpy_s(fileName, BUF_SMALL, strtok_s(NULL, " /", &tmp));// 查看请求文件名
	strcpy_s(ct, BUF_SMALL, ContentType(fileName));           // 查看Content-type
	SendData(hClntSock, ct, fileName);                        // 响应
	return 0;
}

void SendData(SOCKET sock, char* ct, char* fileName)
{
	printf("SendData\n");
	printf("filename:%s\n", fileName);
	char protocol[] = "HTTP/1.0 200 OK\r\n";
	char servName[] = "Server:simple web server\r\n";
	char cntLen[] = "Content-length:2048\r\n";
	char cntType[BUF_SMALL];
	char buf[BUF_SIZE];
	FILE* sendFile;

	sprintf_s(cntType, BUF_SMALL, "Content-type:%s\r\n\r\n", ct);
	if ((fopen_s(&sendFile, fileName, "r")) != 0)
	{
		SendErrorMSG(sock);
		return;
	}

	/*传输头信息*/
	send(sock, protocol, strlen(protocol), 0);
	send(sock, servName, strlen(servName), 0);
	send(sock, cntLen, strlen(cntLen), 0);
	send(sock, cntType, strlen(cntType), 0);
	/*传输请求数据*/
	while (fgets(buf, BUF_SIZE, sendFile) != NULL)
	{
		send(sock, buf, strlen(buf), 0);
	}

	closesocket(sock);                               // 由HTTP协议响应后断开
}

void SendErrorMSG(SOCKET sock)                       // 查看错误时传递信息
{
	char protocol[] = "HTTP/1.0 400 Bad Request\r\n";
	char servName[] = "Server:simple web server\r\n";
	char cntLen[] = "Content-length:2048\r\n";
	char cntType[] = "Content-type:text/html\r\n\r\n";
	char content[] = "<html><head><title>NETWORK</title></head>"
		"<body><font size=+5><br> 发生错误!查看请求文件名和请求方式!"
		"</font></body></html>";
	send(sock, protocol, strlen(protocol), 0);
	send(sock, servName, strlen(servName), 0);
	send(sock, cntLen, strlen(cntLen), 0);
	send(sock, cntType, strlen(cntType), 0);
	send(sock, content, strlen(content), 0);
	closesocket(sock);
}

char* ContentType(char* file)                        // 区分Conteent-type
{
	char extension[BUF_SMALL];
	char fileName[BUF_SMALL];
	char* tmp;

	strcpy_s(fileName, BUF_SMALL, file);
	strtok_s(fileName, ".", &tmp);
	strcpy_s(extension, BUF_SMALL, strtok_s(NULL, ".", &tmp));
	if (!strcmp(extension, "html") || !strcmp(extension, "htm"))
	{
		return "text/html";
	}
	else
	{
		return "text/plain";
	}
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

(2)基于Linux

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define BUF_SIZE 1024
#define SMALL_BUF 100

void* request_handler(void* arg);
void send_data(FILE* fp, char* ct, char* file_name);
char* content_type(char* file);
void send_error(FILE* fp);
void error_handling(char* message);

int main(int argc, char* argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	int clnt_adr_size;
	char buf[BUF_SIZE];
	pthread_t t_id;
	if (argc != 2)
	{
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}

	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family = AF_INET;
	serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_adr.sin_port = htons(atoi(argv[1]));
	if (bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
	{
		error_handling("bind() error");
	}
	if (listen(serv_sock, 20) == -1)
	{
		error_handling("listen() error");
	}

	while (1)
	{
		clnt_adr_size = sizeof(clnt_adr);
		clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_size);
		printf("Connection Request : %s:%d\n", inet_ntoa(clnt_adr.sin_addr), ntohs(clnt_adr.sin_port));
		pthread_create(&t_id, NULL, request_handler, &clnt_sock);
		pthread_detach(t_id);
	}
	close(serv_sock);
	return 0;
}

void* request_handler(void* arg)
{
	int clnt_sock = *((int*)arg);
	char req_line[SMALL_BUF];
	FILE* clnt_read;
	FILE* clnt_write;

	char method[10];
	char ct[15];
	char file_name[30];

	clnt_read = fdopen(clnt_sock, "r");
	clnt_write = fdopen(dup(clnt_sock), "w");
	fgets(req_line, SMALL_BUF, clnt_read);
	if (strstr(req_line, "HTTP/") == NULL)
	{
		send_error(clnt_write);
		fclose(clnt_read);
		fclose(clnt_write);
		return;
	}

	strcpy(method, strtok(req_line, " /"));
	strcpy(file_name, strtok(NULL, " /"));
	strcpy(ct, content_type(file_name));
	if (strcmp(method, "GET") != 0)
	{
		send_error(clnt_write);
		fclose(clnt_read);
		fclose(clnt_write);
		return;
	}

	fclose(clnt_read);
	send_data(clnt_write, ct, file_name);
}

void send_data(FILE* fp, char* ct, char* file_name)
{
	char protocol[] = "HTTP/1.0 200 OK\r\n";
	char server[] = "Server:Linux Web Server \r\n";
	char cnt_len[] = "Content-length:2048\r\n";
	char cnt_type[SMALL_BUF];
	char buf[BUF_SIZE];
	FILE* send_file;

	sprintf(cnt_type, "Content-type:%s\r\n\r\n", ct);
	send_file = fopen(file_name, "r");
	if (send_file == NULL)
	{
		send_error(fp);
		return;
	}

	/*传输头信息*/
	fputs(protocol, fp);
	fputs(server, fp);
	fputs(cnt_len, fp);
	fputs(cnt_type, fp);

	/*传输请求数据*/
	while (fgets(buf, BUF_SIZE, send_file) != NULL)
	{
		fputs(buf, fp);
		fflush(fp);
	}
	fflush(fp);
	fclose(fp);
}

char* content_type(char* file)
{
	char extension[SMALL_BUF];
	char file_name[SMALL_BUF];
	strcpy(file_name, file);
	strtok(file_name, ".");
	strcpy(extension, strtok(NULL, "."));

	if (!strcmp(extension, "html") || !strcmp(extension, "htm"))
	{
		return "text/html";
	}
	else
	{
		return "text/plain";
	}
}

void send_error(FILE* fp)
{
	char protocol[] = "HTTP/1.0 400 Bad Request\r\n";
	char server[] = "Server:Linux Web Server \r\n";
	char cnt_len[] = "Content-length:2048\r\n";
	char cnt_type[] = "Content-type:text/html\r\n\r\n";
	char content[] = "<html><head><title>NETWORK</title></head>"
		"<body><font size=+5><br>发生错误!查看请求文件名和请求方式"
		"</font></body></html>";

	fputs(protocol, fp);
	fputs(server, fp);
	fputs(cnt_len, fp);
	fputs(cnt_type, fp);
	fflush(fp);
}

void error_handling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络编程——实现HTTP服务器端 的相关文章

  • JS 库请求的常见 HTTP 标头是什么?

    使用JavaScript 框架原型 http www prototypejs org 我注意到 Ajax 请求通过一个名为X Requested With 其他 JavaScript 库 如 jQuery dojo 和 YUI 是否会向其
  • iOS WKWebView 处理文件下载

    我面临以下问题 在 Web 界面中 文件下载是通过锚标记触发的 如下所示 a href bla blabla a 虽然 Safari 浏览器可以处理此请求并打开一个对话框来处理文件 但 WKWebView 将此视为普通链接并且不对其执行任何
  • 使用 python requests 模块时出现 HTTP 503 错误

    我正在尝试发出 HTTP 请求 但当前可以从 Firefox 浏览器访问的网站响应 503 错误 代码本身非常简单 在网上搜索一番后我添加了user Agent请求参数 但也没有帮助 有人能解释一下如何消除这个 503 错误吗 顺便说一句
  • put方法中的Angularjs文件上传不起作用

    我有一个简单的待办事项应用程序 我试图在其中上传照片和单个待办事项 现在我已经创建了这个工厂函数来负责待办事项的创建 todosFactory insertTodo function todo return http post baseUr
  • 在 HTTP 标头中发送 UTF-8 值会导致 Mojibake

    我想使用 servlet 发送阿拉伯语数据HTTPServletResponse给客户 我正在尝试这个 response setCharacterEncoding UTF 8 response setHeader Info arabicWo
  • 是否可以检测 http git 远程是智能还是愚蠢?

    我正在我的应用程序中实现一个选项来使用 depth 1制作 git repo 的最小功能克隆 我刚刚意识到愚蠢的 http 传输不支持 depth 我想自动检测 http 远程是愚蠢的还是聪明的 这样我就可以省略 depth与哑 http
  • Android httpclient文件上传数据损坏和超时问题

    我在 Android 中上传图像时遇到问题 我正在使用 apache httpmime 4 1 lib 代码是这样的 MultipartEntity reqEntity new MultipartEntity HttpMultipartMo
  • 流星图像、CSS、“普通”Web 服务

    我经常看到这个问题出现 如何在我的 Meteor 网站上放置图像 如何使用 Meteor 托管 标准 网页内容 我尝试添加一个 img src img myimage png 标签但没有图像显示 如何在 Meteor 站点上托管一些文件 将
  • 尝试克隆一个 git 存储库,但它卡在克隆到中

    我使用的是 Windows 10版本 10 0 19042 内部版本 19042 GIT Ver 2 32当尝试使用 git bash 执行以下命令时git clone depth 1 b carla https github com Ca
  • ASP.NET HTTP 请求是否会转换为 1 个线程?

    可以安全地假设当用户通过 HTTP 请求 aspx 页面时 ASP NET 至少为其创建 1 个线程吗 如果是这样 持续多久 如果 1000 人向同一个 aspx 页面发出 HTTP 请求 是否会涉及一些线程回收 因此不会产生不同的 100
  • Go客户端程序生成大量TIME_WAIT状态的socket

    我有一个 Go 程序 它从多个 goroutine 生成大量 HTTP 请求 运行一段时间后 程序报错 connect cannot allocaterequestedaddress 当检查时netstat 我得到大量 28229 个连接T
  • 如何设置响应文件名而不强制“另存为”对话框

    我在某些响应中返回一个流 设置适当的content type标头 我正在寻找的行为是这样的 如果浏览器能够呈现给定内容类型的内容 那么它应该将其显示在浏览器窗口中 如果浏览器不知道如何呈现内容 那么它应该显示 另存为 对话框 其中文件名应该
  • C# HTTP 请求解析器[重复]

    这个问题在这里已经有答案了 可能的重复 将原始 HTTP 请求转换为 HTTPWebRequest 对象 https stackoverflow com questions 318506 converting raw http reques
  • 使用 JSON 的 Pentaho HTTP Post

    我是 Pentaho 的新手 我正在尝试执行以下工作流程 从数据库中读取一堆行 做一些转换 将它们以 JSON 格式发布到 REST Web 服务 我已经使用输入步骤和 Json 输出步骤解决了前两个问题 但是 我在执行最后一步时遇到两个问
  • cookie 在会话结束时或在特定时间过期?

    cookie 是否可以在会话结束时或在特定时间过期 是的 这很简单 HttpCookie newCookie new HttpCookie myCookie newCookie Expires DateTime Today AddDays
  • 无效数据的 REST 响应代码

    如果出现以下情况 应将什么响应代码传递给客户端 用户注册时传递了无效数据 例如电子邮件格式错误 用户名 电子邮件已存在 我选择了403 我还发现了以下我觉得可以用的 维基百科 412 前提条件失败 服务器不满足请求者要求的先决条件之一 提出
  • HTTP请求的内容长度>正文大小

    我正在管理一个网站 该网站过去几个月在使用 MVC 3 0 ASP net 构建的 IIS 7 5 上运行良好 当我们的 AJAX POST 请求 通过 jQuery 触发 因发布的 JSON 被截断而失败时 我们时不时地会遇到一个问题 到
  • 是什么导致“线程被中止”异常随机发生并向浏览器显示 HTTP 标头和部分 HTML?

    发生的情况偶尔是随机的 而不是像您期望的那样将 HTML 返回到浏览器 它看起来有点像这样 线程正在中止 HTTP 1 1 200 OK 标题的其余部分 如 HTML 的 1 10 就是这样 他们实际上在浏览器窗口中收到了一堆文本 它不会一
  • AngularJS 1.X 中的异步调用是如何工作的? $Http 调用没有返回值

    我有以下名为的函数getvalue 它与控制器一起位于 AngularJS 模块内 我试图在单击事件上调用此函数 调用控制器中的另一个函数 我希望我很清楚 功能 function getvalue Data http var value u
  • 如何解决 302 重定向上的 POST 更改为 GET 的问题?

    我网站的某些部分只能通过 HTTPS 访问 不是整个网站 安全与性能妥协 并且如果通过纯 HTTP 发送请求 则 HTTPS 是通过对安全部分的请求进行 302 重定向来强制执行的 问题是对于所有主流浏览器来说 如果您在 POST 上执行

随机推荐

  • 【AD21】keepout层和机械1层怎么相互转换

    1 从keepout转换为Mechanical 1层 见下图 图1 图2 图3 图4 2 从keepout转换为Mechanical 1层 见下图 如果想要将keepout层转换成机械1层 可以先全选中想要转换的keepoutz层 然后在c
  • Docker之旅:在Docker容器中创建第一个程序

    Docker的概念 Docker是开发人员和系统管理员 使用容器开发 部署和运行应用程序的平台 使用Linux容器来部署应用程序称为集装箱化 容器不是新的事物 但它们用于轻松部署应用程序 一 测试一下Docker的版本 1 查看Docker
  • 实用工具推荐,浏览器必备宝藏插件:Wetab新标签页

    打开浏览器 你的起始页是否充满了广告和各种乱七八糟的信息呢 或者过于单调 而失去了某些你想要的功能 这里给大家推荐一个在Chrome浏览器和edge浏览器上都能愉快使用的浏览器插件 Wetab新标签页 没有广告 页面干净美观且具备各种实用功
  • android live 电视 源码,GitHub - mxiaoguang/LivePlayback: Android TV直播电视节目 ,包含各央视频道及卫视频道...

    Android TV直播电视节目 更多技术博客 项目 欢迎关注公众号 Android TV开发交流群 135622564 传统电视直播节目 在Android TV上起着越来越重要的作用 央视 各地卫视 满足观众日益增长的多元化需求 看下效果
  • IV转换电路原理图

    毫安级IV转换电路如下 如果要uA级转换 可把运放改为 D795 SG 8210 L C6482等输入偏置电流在pA级的运
  • tomcat配置443端口

  • true_type与false_type

    std true type和std false type 实际上是类型别名 是两个类型 类模板 注意区分true type与false type与true和false区别 true type false type代表类型 true fals
  • 【项目实战】Python基于局部离群因子LOF算法(LocalOutlierFactor)实现信用卡数据异常值检测项目实战

    说明 这是一个机器学习实战项目 附带数据 代码 文档 代码讲解 如需数据 代码 文档 代码讲解可以直接到文章最后获取 1 项目背景 异常检测是数据挖掘领域研究的基本问题之一 已被广泛应用于网络入侵检测 信用卡欺诈侦查等领域 局部离群因子 简
  • 以太坊客户端Geth命令用法-参数详解

    Geth是在以太坊智能合约开发中最常用的工具 必备开发工具 一个多用途的命令行工具 熟悉Geth可以让我们有更好的效率 大家可收藏起来作为Geth命令用法手册 本文主要是对geth help的翻译 基于最新的geth 1 7 3 stabl
  • sqlite3查看数据库中有哪些表(代码)

    说实话 用代码实现sqlite3查看数据库中有哪些表我还真的没找到现成资源 网上提供的语句还真用不了 而且大多都是命令行语句 由于的做的MFC项目要用到这个功能 特意学习了下 下面分享我的成果 希望可以帮到你 环境 VS2005 inclu
  • FPGA中值滤波实现并Modelsim仿真,与MATLAB中值滤波进行对比

    文章目录 一 中值滤波算法 二 FPGA实现中值滤波 2 1 3 3窗口的生成 2 2 排序模块 2 3中值滤波模块 2 4 整体RTL图 三 modeslim仿真 四 matlab中值滤波 五 效果对比 一 中值滤波算法 1 中值滤波算法
  • 解决wangEditor表格边框显示不出来、没有的问题

    仔细阅读文档 不过我一直找表格或者边框搜索 发现没有特定的栏目 所以忽略了 当然也有我不够仔细的原因 有点着急莽荒了 链接 在官网的这个页面 从官网贴下来的 把这段复制到想要的地方就可以了
  • 自定义表单控件 [(ngModel)]

    ngModel 拆分 ngModel 将 输入 输出组合起来 进行双向数据绑定 拆分开来 输入属性 ngModel ngModelChange 输出监听元素值的变化 并同步view value与model value
  • 头都给我找烂

    mysql5 6下载 https dev mysql com downloads file id 487425 win10添加本地用户和组 https blog csdn net qq 40151857 article details 89
  • 【Linux命令集】top命令的用法详解

    在使用linux系统中 我们最长用的查看系统性能的方式就是使用命令top 通知我们只关心总体的cpu和内存的使用情况 对其他的参数基本无视 也看不懂 下面来介绍一下top的详细参数的意义 top视图 进入top的基本视图 我们来结合这个视图
  • 电容选型及计算

    一 电容容值计算 1 电容整流波形分析 经过整流后三相电压整流为六脉波电压 电压波形如下图 上图中各时期充电过程如下 在t0 t3阶段是一个T 6周期 一个完整波头阶段 在t0 t1阶段 电容放电 给负载提供能量 此时输入电压小于电容电压
  • openEuler实验之A-Tune智能调优

    1 A Tune介绍 A Tune是一款基于AI开发的系统性能优化引擎 它利用人工智能技术 对业务场景建立精准的系统画像 感知并推理出业务特征 进而做出智能决策 匹配并推荐最佳的系统参数配置组合 使业务处于最佳运行状态 1 1 A Tune
  • redis docker安装、进入命令行后启动服务

    下载redis镜像 首先查看一下redis是否正确 docker search redis 显示 NAME DESCRIPTION STARS OFFICIAL AUTOMATED redis Redis is an open source
  • 一文读懂工厂MES系统的详细功能介绍

    一 工单管理 MES通过工单来管理生产执行 工单状态有 创建 下达 执行 完成 取消 计划员创建工单 审核通过后释放到设备或产线 仓库可收到工单下达的通知 及时备料 产线只能看到已下达的工单 执行工单 完成后登记报工 将相关信息反馈回ERP
  • 网络编程——实现HTTP服务器端

    参考 TCP IP网络编程 尹圣雨 Web服务器端 概述 Web服务器端是 基于HTTP Hypertext Transfer Protocol 协议 将网页对应文件传输给客户端的服务器端 Hypertext 超文本 是可以根据客户端请求而