当前位置: 首页 > news >正文

TCP/IP网络编程 第二十四章:制作HTTP服务器端

实现简单的Web服务器端

现在开始在HTTP协议的基础上编写Web服务器端。先给出Windows平台下的示例,再给出Linux下的示例。在这里我假设各位都有了有关HTTP的知识,如果不知道HTTP协议的具体内容可以参考的往期博客,有了这些基础就不难分析源代码。因此,除了一些简单的注释外,不再另行说明代码。

实现基于Windows的多线程Web服务器端

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

因此,我通过多线程模型实现Web服务器端。也就是说,客户端每次请求时,都创建1个新线程响应客户端请求。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<winsock2.h>
#include <process.h>#define BUF_SIZE 2048
#define BUF_SMALL 100unsigned 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;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_ntoa(clntAdr.sin_addr),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){SOCKET hClntSock=(SOCKET)arg;char buf[BUF_SIZE];char method[BUF_SMALL];char ct[BUF_SMALL];char fileName[BUF_SMALL];recv(hclntsock, buf, BUF_SIZE, 0);if(strstr(buf,"HTTP/")==NULL){//查看是否是HTTP提出的请求SendErrorMSG(hClntSock);closesocket(hClntSock);return 1;}strcpy(method,strtok(buf,"/"));if(strcmp(method,"GET"))//我这里只实现了GET的请求方式SendErrorMSG(hClntSock);strcpy(fileName,strtok(NULL,”/“)); //查看请求文件名strcpy(ct,ContentType(fileName));   //查看Content-typeSendData(hClntSock, ct, fileName);  //响应return 0;
}void SendData(SOCKET sock, char* ct, char* 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(cntType,"Content-type:%s\r\n\r\n",ct);if((sendFile=fopen(fileName,"r"))==NULL){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){ //区分Content-typechar extension[BUF_SMALL];char fileName[BUF_SMALL];strcpy(fileName, file);strtok(fileName,".");strcpy(extension, strtok(NULL,"."));if(!strcmp(extension, "html")||!strcmp(extension,"htm"))return "text/html";elsereturn "text/plain";
}void ErrorHandling(char* message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}

大家可以通过浏览器来访问一下自己的HTTP服务器,尝试一下结果。

实现基于 Linux的多线程Web服务器端

Linux下的Web服务器端与上述示例不同,将使用标准I/O函数。在此列出的目的主要是为了
让各位多复习各种知识点,没有任何特殊含义。

#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 100void* 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(reg_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,"/"));if(strcmp(method,"GET")!=0){//判断是否为实现的GEI方法,如果不是则结束连接send_error(clnt_write);fclose(clnt_read);fclose(clnt_write);return;}strcpy(file_name, strtok(NULL," /"));strcpy(ct,content_type(file_name));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";elsereturn"text/plain";
}void send_error(FILE* fp){char protocol[]="HTTP/1.0 400 Bad Request\r\n";char server[]="Server:Linux Web Server Ir\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);
}

以上就是网络编程的所有知识,大家也可以选择继续深入学习。

 

相关文章:

TCP/IP网络编程 第二十四章:制作HTTP服务器端

实现简单的Web服务器端 现在开始在HTTP协议的基础上编写Web服务器端。先给出Windows平台下的示例&#xff0c;再给出Linux下的示例。在这里我假设各位都有了有关HTTP的知识&#xff0c;如果不知道HTTP协议的具体内容可以参考的往期博客&#xff0c;有了这些基础就不难分析源代…...

React 前端应用中快速实践 OpenTelemetry 云原生可观测性(SigNoz/K8S)

OpenTelemetry 可用于跟踪 React 应用程序的性能问题和错误。您可以跟踪从前端 web 应用程序到下游服务的用户请求。OpenTelemetry 是云原生计算基金会(CNCF)下的一个开源项目&#xff0c;旨在标准化遥测数据的生成和收集。已成为下一代可观测平台的事实标准。 React(也称为 Re…...

Linux 多线程并发Socket服务端的实现( 11 ) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…...

2.7. Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符?

Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。 Java 的泛型是伪泛型&am…...

单例模式与构造器模式

单例模式 1、是什么 单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a;创建型模式&#xff0c;提供了一种创建对象的最佳方式&#xff0c;这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对象被创建 在应用程序运…...

SQL力扣练习(七)

1.行程和用户(262) 表&#xff1a;Trips ----------------------- | Column Name | Type | ----------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | reques…...

C语言假期作业 DAY 05

题目 一、选择题 1、如下程序的功能是&#xff08; &#xff09; #include <stdio.h> int main() { char ch[80] "123abcdEFG*&"; int j; puts(ch); for(j 0; ch[j] ! \0; j) if(ch[j] > A && ch[j] < Z) ch[j] ch[j] e - E; puts(ch)…...

php-golang-rpc使用roadrunner-server/goridge/v3/pkg/rpc和php的spiral/goridge3.2实践

golang代码&#xff1a; go get github.com/roadrunner-server/goridge/v3 package main import ( "fmt" "net" "net/rpc" goridgeRpc "github.com/roadrunner-server/goridge/v3/pkg/rpc" ) type App struct{} func (s *App) Hi(na…...

API常用签名验证方法(PHP实现)

使用场景 现在越来越多的项目使用的前后端分离的模式进行开发&#xff0c;后端开发人员使用API接口传递数据给到前端开发进行处理展示&#xff0c;在一些比较重要的修改数据接口&#xff0c;涉及金钱&#xff0c;用户信息等修改的接口如果不做防护验证&#xff0c;经常容易被人…...

kotlin高阶函数

kotlin高阶函数 函数式API:一个函数的入参数为Lambda表达式的函数就是函数式api 例子: public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {return filterTo(ArrayList<T>(), predicate) }上面这段函数: 首先这个函…...

kotlin list集合树

kotlin list集合树 记录一下 data class AreaSchemaManageDto(var id: Long? null,var pid: Long? null,var label: String? null,var children: MutableList<AreaSchemaManageDto>? null ) : Serializable { }逻辑 fun getAll(): List<AreaSchemaManageDto&g…...

基于Autoencoder自编码的64QAM星座图整形调制解调通信系统性能matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1星座图整形 4.2自编码器 4.3基于Autoencoder的星座图整形调制解调模型 4.4 实现过程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .…...

【Spring】Spring 总览

一、简单介绍一下 Spring Spring是一个全面的、企业应用开发的一站式解决方案&#xff0c;贯穿表现层、业务层、持久层&#xff0c;可以轻松和其他框架整合&#xff0c;具有轻量级、控制反转、面向切面、容器等特征。 轻量级 &#xff1a; 空间开销和时间开销都很轻量 控制反…...

微软、OpenAI用上“数据永动机” 合成数据是晨曦还是暮光?

微软、OpenAI、Cohere等公司已经开始测试使用合成数据来训练AI模型。Cohere首席执行官Aiden Gomez表示&#xff0c;合成数据可以适用于很多训练场景&#xff0c;只是目前尚未全面推广。 已有的&#xff08;通用&#xff09;数据资源似乎接近效能极限&#xff0c;开发人员认为&a…...

简单认识Redis 数据库的高可用

文章目录 一、Redis 高可用&#xff1a;1.简介&#xff1a;2、在Redis中实现高可用的技术 二、Redis持久化&#xff1a;1.持久化的功能&#xff1a;2.Redis 提供两种方式进行持久化&#xff1a; 三、RDB 持久化&#xff1a;1.简介&#xff1a;2.触发条件&#xff1a;4.启动时加…...

超级实用!,掌握这9个鲜为人知的CSS属性

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的&#xff0c;我们出的钱 体验地…...

深圳国际新能源及智能网联汽车全产业博览会今年10月举办

7月25日&#xff0c;深圳市工业和信息化局与励展博览集团共同在深圳举办Automotive World China 2023深圳国际新能源及智能网联汽车全产业博览会&#xff08;简称“AWC 2023”&#xff09;全球推介启动大会&#xff0c;该博览会将于2023年10月11日-13日在深圳国际会展中心盛大举…...

【具有非线性反馈的LTI系统识别】针对反馈非线性的LTI系统,提供非线性辨识方案(SimulinkMatlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码、Simulink仿真实现 &#x1f4a5;1 概述 本文为具有反馈非线性的LTI系统提供了一种非线性识别方案&#xff0c;这取决于输入和LTI系统输出。对于MEMS来说尤其如此&#…...

Stable diffusion 和 Midjourney 怎么选?

通过这段时间的摸索&#xff0c;我将和你探讨&#xff0c;对普通人来说&#xff0c;Stable diffusion 和 Midjourney 怎么选&#xff1f;最重要的是&#xff0c;学好影视后期制作对 AI 绘画创作有哪些帮助&#xff1f;反过来&#xff0c;AI 绘画对影视后期又有哪些帮助&#xf…...

c++网络编程

网络编程模型 c/s 模型&#xff1a;客户端服务器模型b/s 模型&#xff1a;浏览器服务器模型1.tcp网络流程 服务器流程&#xff1a; 1.创建套接字2.完善服务器网络信息结构体3.绑定服务器网络信息结构体4.让服务器处于监听状态5.accept阻塞等待客户端连接信号6.收发数据7.关闭套…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...