C语言写的 mini版的 http 服务器 , 很详细

文章目录

    • 效果展示
    • 整体架构流程
    • 技术细节
    • 完整代码

效果展示

例如:htpp://192.168.23.140/home.html     ->  正确的请求格式

home.html     这个资源是放在我们服务器里面的 , 并不是随便访问的资源,当然我们可以放很多的资源进去. 

整体架构流程

整个实现的流程其实很简单 , 简单的网络编程基础 , 和对 http 协议格式的基础了解,想要实现并不难.

这里我会对 http协议格式 进行简单的说明.

mini 版的实现 , 我们只处理 客户端发起的 get 请求  ,想要全部实现,还是很有难度的 . 

补充 :

HTTP协议的请求主要包括以下几种:

  1. GET:从服务器获取资源,通常用于请求页面、图片、视频等内容。

  2. POST:向服务器提交数据,通常用于提交表单、上传文件等操作。

  3. PUT:将数据上传到指定的URI,用于更新资源。

  4. DELETE:请求服务器删除指定的资源。

  5. HEAD:类似于GET请求,但服务器只返回请求行和头部,不返回实际内容,用于获取资源的元信息。

  6. OPTIONS:查询支持的HTTP方法,用于确定服务器支持的请求方法。

  7. TRACE:回显服务器收到的请求,用于测试或诊断。

  8. CONNECT:用于代理服务器,将连接转换为隧道。

技术细节

http 协议格式 :  初次基础这个协议的朋友 ,  有一个大概的印象就可以了 , 想要搞明白 http 协议也是相当有难度的  . 

我们这里的实现没有那么复杂.

我们进行收发数据的时候 , 都是一行一行的读取 , 这个很重要 .

每行数据的结尾都有一个明显的标志 , 一个回车符 + 一个换行符

特别注意的是 : 消息报头 和 响应正文  ,  请求头部  和请求数据之间有一个 回车符 + 换行符.

我们在进行数据收发的时候要严格遵循协议的格式.

 常见的错误 : 

提示:实现的模块说明

详细:

  • API 说明

1 . 实现按行读取 , 严格按照 http  格式 , 每一行的尾部是一个  换行符+回车符

是读取到尾部的重要标志

成功返回读取到的字符个数 ,失败返回 -1 

int get_line(int sock , char *buf ,int size ){
	//每次读取一个字符
	int count = 0 ;   //当前已经读取到的字符大小
    char ch = '\0';  
	int len = 0 ;
	while( (count < size -1) && ch!='\n'){
		len  = read(sock , &ch ,1);
		if( len == 1 ){  //正常读取成功
		    //处理 '\r(回车)  \n'
			if( ch=='\r')   continue;
			else if(ch=='\n'){
				//buf[count] = '\0';     //手动添加字符串结束符
				break;
			}
		//处理一般的字符
		buf[count++] = ch;
		}else if( len < 0 ){   //读取出错的情况
			perror("read fialed\n");
			count = -1;
			break;
		}else {   //len = 0 的情况   客户端关闭了sock连接
		    fprintf(stderr , "client close\n");
			count = -1 ;
			break;
		}
	}
	if( count >=0)  buf[count]='\0';
	//if(Debug)  printf("line information %s\n", buf);
	return count;  
}

2 .  处理客户端的请求  . 同时做好防御性编程 , 处理可能发生的情况 . 

实现过程 :   返回值 和 参数 设置都是和主函数中的线程进行匹配.  

读取http请求 +  解析 http 请求 .

都是按照上面 http 协议格式来的 , 如果不记得了 ,可以看看上面. 

void* do_http_request(void* pclient_sock){
	//读取http请求
	
	//按行读取请求头部
	int len = 0;
	char buf[256]={0};
	char method[64]={0}; //存放请求方法
	char url[256]={0};//存放url(请求的资源)
	char version[64]={0};//协议版本
	char path[256]={0};//url对应的路径
	int client_sock = *(int *)pclient_sock ; 
	
	len = get_line(client_sock , buf ,sizeof(buf) );
	
	if( len > 0 ){//读取到请求行
		int i=0 , j=0;
		while(!isspace(buf[j]) && i < sizeof(method)-1 ){
			method[i] = buf[j];
			i++;
			j++;
		}
		
		method[i] = '\0';
		if(Debug)   printf("request method = %s\n",method );
		//判断是否GET方法,这个服务器我们只处理get请求
	    if( strncasecmp( method ,"GET",i)==0 ){
			if(Debug)   printf("method GET\n");
			
			//继续读取请求资源
			while(isspace(buf[j++]));//跳过空格
			i = 0;
			while(!isspace(buf[j]) && i < sizeof(url)-1){
				url[i] = buf[j];
				i++;
				j++;
			}
			//手动加上字符串结束符
			url[i] = '\0';
			if(Debug)  printf("request url = %s\n",url);
			//printf("131 : %c\n",buf[j]);
			//读取协议版本
			
			while(isspace(buf[j++]));//跳过空格
			
			i = 0;
			while(!isspace(buf[j]) && i < sizeof(version)-1){
				version[i] = buf[j];
				i++;
				j++;
			}
			//手动加上字符串结束符
			version[i] = '\0';
			if(Debug)  printf("request version = %s\n",version);
			
			//打印请求头部
			do{
		       len = get_line(client_sock , buf ,sizeof(buf) );
		       printf("request head = %s\n" , buf );
	        }while(len > 0);
			
			//****定位到服务器本地的  html文件 ****
			//****如果需要修改资源 , 那么将这里的path 路径改成你自己资源对应的路径****
			
			//处理 url 中的?
			{
				char *pos = strchr( url ,'?');
				if(pos){
					*pos = '\0';
					printf("real url= %s\n",url);
				}
				sprintf(path ,"./html_file/%s", url );
				if(Debug)  printf("path = %s\n", path );
				
				//判断请求的资源是否存在 ,存在则进行响应
				struct stat st;      //保存文件信息的结构体
				if( stat( path , &st) == -1 ){//如果不存在则响应  404  NOT FOUND
				    fprintf( stderr ," stat :%s failed . reason :%s\n", path , strerror(errno));
					not_found( client_sock );
				}else{ //执行http响应
					
					if(S_ISDIR(st.st_mode)){ //如果是一个目录,则补全
						strcat(path , "/indext.html");
					}
					//响应给客户端
					do_http_response(client_sock , path );
				}
				
			}
			
		}else{ //客户端的请求方式不是 get  , 响应 501 Method Not Implemented
			fprintf(stderr ,"warning  other method[%s]\n",method);
			do{
		       len = get_line(client_sock , buf ,sizeof(buf) );
		       printf("request head = %s\n" , buf );
	        }while(len > 0);
			//响应客户端 501 Method Not Implemented
			unimplemented(client_sock);
		}	
	}else {   //客户端发送的请求格式有问题 相应 400  BAD REQUEST
		bad_request( client_sock);
	}
	close(client_sock);
	if( pclient_sock )free(pclient_sock);
	return NULL;
}

  3 . 将请求的资源,响应给客户端

  注意 :

 我们在将客户端请求的资源发送给客户端的时候 .

在消息报头的最后  我们要还要发送  请求资源的大小( Content-Length:%ld\r\n\r\n ). 

所以说在发送响应的时候 , 一般分两不进行:

- 1. 先发送     状态行 + 消息报头

- 2 . 发送   响应正文

void do_http_response( int client_sock , const char *path ){
	FILE  *fp = NULL;
	fp = fopen( path ,"rb");
	if( fp==NULL ){
		not_found(client_sock);
		return ;
	}
	//文件打开成功
	
	//1. 发送 http 头部 
	int ret = header(client_sock , fp);
	
	//2. 发送http body
	if( !ret ){	
		cat(client_sock , fp);
	}
	//3. 清理资源
	fclose( fp );
}

4. 发送 http 头部  (状态行 + 消息报头 )

成功返回 0  失败返回-1

int header(int client_sock ,FILE *fp){
	char buf[1024] = { 0 };
	char temp[64];
	int fpId = -1;
	struct stat st;
	
	strcat(buf , "HTTP/1.1 200 OK\r\n");
	strcat(buf , "Server:wServer\r\n");
	strcat(buf , "Content-Type:text/html\r\n");
	strcat(buf , "Connection:Close\r\n");
	
	fpId = fileno( fp );
	if( fstat( fpId ,&st) == -1  ){
		//响应客户端 500 Internal Server Error
		Internal_Error(client_sock); 
		return -1;
	}
	//将响应资源的大小加上
	snprintf( temp , 64 ,"Content-Length:%ld\r\n\r\n" , st.st_size );
	strcat( buf , temp);
	
	if(Debug) fprintf(stdout ," header :%s\n", buf );
	
	if( send( client_sock , buf , strlen(buf) , 0 ) < 0 ){
		fprintf( stderr ," send failed . reason: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}
5. 发送响应资源

因为我们的资源里面包括了图片和音乐

所以在进行文件操作的时候,我们要以二进制的方式进行,

没次读取一个字节.

void cat(int client_sock , FILE *fp){
	char buf[1024] = { 0 };
	
	// 1 .没次读取一个字符
	/*
	while( fread(buf , 1 , sizeof(buf), fp) >0 ){
		int len = write( client_sock , buf , strlen(buf));
		
		memset( buf , 0 ,sizeof(buf));
	}*/
	
	fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    // 为文件分配缓冲区
    char* buffer =  (char*)malloc(size);

    // 读取文件数据
    size_t bytesRead = fread(buffer, 1, size, fp);
    if (bytesRead != size) {
        printf("读取文件时发生错误\n");
       return ;
    }
	
    // 使用文件数据进行操作...
     printf("读取 %lu 字节的数据\n", bytesRead);
	 int len = write( client_sock , buffer , size);
	 if( len < 0){
		 fprintf(stderr , "write failed . reason :%s\n", strerror(errno));
	 }
   
    free(buffer);
}

好了 ,看到这里这个服务器已经搞定了 ,简单吧 ,核心代码就这么点.

完整版的代码 :   (方便大家复制 , 我给他写在了一个文件里面)

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<errno.h>
#include<sys/stat.h>
#include<pthread.h>

#define SERVER_PORT  80     //服务器的端口号

static int Debug = 1;

//处理http请求
void* do_http_request(void* client_sock);

//返回 -1 表示读取失败   0 表示读取到一个空行  >0 表示读取成功
int get_line(int sock ,char *buf ,int size );

//回复客户端请求
void do_http_response1( int client_sock );

void do_http_response( int client_sock , const char *path );

//响应404
void not_found( int client_sock );

//发送 http 头部 
int header(int client_sock ,FILE *fp);
	
//发送http body 
void cat(int client_sock , FILE *fp);

//响应501  客户端的请求方式异常
void unimplemented(int client_sock );

//响应400 客户端发送的请求格式有问题
void bad_request( int client_sock );

//500
void Internal_Error(int client_sock);


int main(void){
    
    int sock;//代表信箱
    struct sockaddr_in server_addr; //标签,保存端口号,ip地址等

    //1, 创建信箱
    sock = socket( AF_INET , SOCK_STREAM , 0);
    
    //2. 清空标签,写上地址和端口号
    bzero( &server_addr ,sizeof(server_addr));
    server_addr.sin_family = AF_INET; //选择协议族IPV4
    server_addr.sin_addr.s_addr = htonl( INADDR_ANY ); //监听本地所有ip地址
    server_addr.sin_port = htons( SERVER_PORT ); //绑定我们的端口号

    //3. 将我们的标签贴到信箱上
    bind(sock ,(struct sockaddr *)&server_addr,sizeof(server_addr));

    //4. 将我们的信箱挂到传达室,这样,保安就可以接收信件了
    listen(sock, 128);    //这里的128表示同时可以接收的信件数量

    //万事俱备,只等美女来信
    printf("等待美女的来信\n");
   
    int done =1;
    //不断接受来信
    while( done ){
    	struct sockaddr_in client;
		int client_sock,len;
		char client_ip[64];
		char buff[256];
		pthread_t id ;   //线程的句柄 
		int *pclient_sock=NULL;

		socklen_t client_addr_len;
		client_addr_len = sizeof(client);
		client_sock = accept(sock ,(struct sockaddr *)&client, &client_addr_len);
        //打印客户端ip地址和端口号
		printf("client ip: %s\t port : %d\n",
	      inet_ntop( AF_INET, &client.sin_addr.s_addr,client_ip,
		  sizeof(client_ip)), ntohs(client.sin_port));
	
		//5 、处理http请求 ,读取客户端发送的数据   read()
		//do_http_request(client_sock);
		// 5.1 启动线程实现并发
		pclient_sock = (int *)malloc( sizeof(int));
		*pclient_sock = client_sock;
		pthread_create( &id ,NULL , do_http_request ,(void *)pclient_sock );
		
		//6 . 响应客户端请求
		
		//close(client_sock);
		
    }
    close(sock);
    return 0;
}

void* do_http_request(void* pclient_sock){
	//读取http请求
	
	//按行读取请求头部
	int len = 0;
	char buf[256]={0};
	char method[64]={0}; //存放请求方法
	char url[256]={0};//存放url(请求的资源)
	char version[64]={0};//协议版本
	char path[256]={0};//url对应的路径
	int client_sock = *(int *)pclient_sock ; 
	
	len = get_line(client_sock , buf ,sizeof(buf) );
	
	if( len > 0 ){//读取到请求行
		int i=0 , j=0;
		while(!isspace(buf[j]) && i < sizeof(method)-1 ){
			method[i] = buf[j];
			i++;
			j++;
		}
		
		method[i] = '\0';
		if(Debug)   printf("request method = %s\n",method );
		//判断是否GET方法,这个服务器我们只处理get请求
	    if( strncasecmp( method ,"GET",i)==0 ){
			if(Debug)   printf("method GET\n");
			
			//继续读取请求资源
			while(isspace(buf[j++]));//跳过空格
			i = 0;
			while(!isspace(buf[j]) && i < sizeof(url)-1){
				url[i] = buf[j];
				i++;
				j++;
			}
			//手动加上字符串结束符
			url[i] = '\0';
			if(Debug)  printf("request url = %s\n",url);
			//printf("131 : %c\n",buf[j]);
			//读取协议版本
			
			while(isspace(buf[j++]));//跳过空格
			
			i = 0;
			while(!isspace(buf[j]) && i < sizeof(version)-1){
				version[i] = buf[j];
				i++;
				j++;
			}
			//手动加上字符串结束符
			version[i] = '\0';
			if(Debug)  printf("request version = %s\n",version);
			
			//打印请求头部
			do{
		       len = get_line(client_sock , buf ,sizeof(buf) );
		       printf("request head = %s\n" , buf );
	        }while(len > 0);
			
			//****定位到服务器本地的  html文件 ****
			//****如果需要修改资源 , 那么将这里的path 路径改成你自己资源对应的路径****
			
			//处理 url 中的?
			{
				char *pos = strchr( url ,'?');
				if(pos){
					*pos = '\0';
					printf("real url= %s\n",url);
				}
				sprintf(path ,"./html_file/%s", url );
				if(Debug)  printf("path = %s\n", path );
				
				//判断请求的资源是否存在 ,存在则进行响应
				struct stat st;      //保存文件信息的结构体
				if( stat( path , &st) == -1 ){//如果不存在则响应  404  NOT FOUND
				    fprintf( stderr ," stat :%s failed . reason :%s\n", path , strerror(errno));
					not_found( client_sock );
				}else{ //执行http响应
					
					if(S_ISDIR(st.st_mode)){ //如果是一个目录,则补全
						strcat(path , "/indext.html");
					}
					//响应给客户端
					do_http_response(client_sock , path );
				}
				
			}
			
		}else{ //客户端的请求方式不是 get  , 响应 501 Method Not Implemented
			fprintf(stderr ,"warning  other method[%s]\n",method);
			do{
		       len = get_line(client_sock , buf ,sizeof(buf) );
		       printf("request head = %s\n" , buf );
	        }while(len > 0);
			//响应客户端 501 Method Not Implemented
			unimplemented(client_sock);
		}	
	}else {   //客户端发送的请求格式有问题 相应 400  BAD REQUEST
		bad_request( client_sock);
	}
	close(client_sock);
	if( pclient_sock )free(pclient_sock);
	return NULL;
}

void do_http_response( int client_sock , const char *path ){
	FILE  *fp = NULL;
	fp = fopen( path ,"rb");
	if( fp==NULL ){
		not_found(client_sock);
		return ;
	}
	//文件打开成功
	
	//1. 发送 http 头部 
	int ret = header(client_sock , fp);
	
	//2. 发送http body
	if( !ret ){	
		cat(client_sock , fp);
	}
	//3. 清理资源
	fclose( fp );
}

int header(int client_sock ,FILE *fp){
	char buf[1024] = { 0 };
	char temp[64];
	int fpId = -1;
	struct stat st;
	
	strcat(buf , "HTTP/1.1 200 OK\r\n");
	strcat(buf , "Server:wServer\r\n");
	strcat(buf , "Content-Type:text/html\r\n");
	strcat(buf , "Connection:Close\r\n");
	
	fpId = fileno( fp );
	if( fstat( fpId ,&st) == -1  ){
		//响应客户端 500 Internal Server Error
		Internal_Error(client_sock); 
		return -1;
	}
	//将响应资源的大小加上
	snprintf( temp , 64 ,"Content-Length:%ld\r\n\r\n" , st.st_size );
	strcat( buf , temp);
	
	if(Debug) fprintf(stdout ," header :%s\n", buf );
	
	if( send( client_sock , buf , strlen(buf) , 0 ) < 0 ){
		fprintf( stderr ," send failed . reason: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}
	
void cat(int client_sock , FILE *fp){
	char buf[1024] = { 0 };
	
	// 1 .没次读取一个字符
	/*
	while( fread(buf , 1 , sizeof(buf), fp) >0 ){
		int len = write( client_sock , buf , strlen(buf));
		
		memset( buf , 0 ,sizeof(buf));
	}*/
	
	fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    // 为文件分配缓冲区
    char* buffer =  (char*)malloc(size);

    // 读取文件数据
    size_t bytesRead = fread(buffer, 1, size, fp);
    if (bytesRead != size) {
        printf("读取文件时发生错误\n");
       return ;
    }
	
    // 使用文件数据进行操作...
     printf("读取 %lu 字节的数据\n", bytesRead);
	 int len = write( client_sock , buffer , size);
	 if( len < 0){
		 fprintf(stderr , "write failed . reason :%s\n", strerror(errno));
	 }
   
    free(buffer);
	
	// 2. 没次发
	
	//-- 无图片的版本
	/*fgets( buf ,sizeof(buf) , fp);
	while( !feof(fp)){
		int len = write( client_sock , buf , strlen(buf));
		if(len < 0){
			fprintf(stderr , "write failed . reason :%s\n", strerror(errno));
			break;
		}
		fprintf(stdout , "%s", buf);
		fgets( buf ,sizeof(buf) , fp);
	}*/
}

void do_http_response1( int client_sock){
	//main_header   ->  状态行 + 消息报头
    //响应代号 200 服务器存在请求资源,可以响应给客户端
	const char *main_header = "\
HTTP/1.1 200 OK\r\n\
Server:wServer\r\n\
Content-Type:text/html\r\n\
Connection:Close\r\n";
	//回响正文
	const char* welcome_content="\
<html lang = \"zh-CN\">\n\
<head>\n\
<meta content = \"text/html;charset=utf-8\"http-equiv=\"Content-Type\">\n\
<title>Tihis is a test</title>\n\
</head>\n\
<body>\n\
<dir align = center height =\"500px\">\n\
<br/><br/><br/>\n\
<h2>早上好</h2><br/><br/>\n\
<form action = \"commit\"method = \"post\">\n\
尊姓大名:<input type =\"text\" name=\"name\"/>\n\
<br/> 芳龄几何:<input type =\"password\" name =\"age\"/>\n\
<br/><br/><br/><input type =\"submit\" value=\"提交\"/>\n\
<input type =\"reset\" value =\"重置\"/>\n\
</form>\n\
</dir>\n\
</body>\n\
</html>";
	
	if( Debug ) fprintf(stdout , ".....do http_response.....\n");
	
	// 1 .发送main_header
	int len = write( client_sock , main_header ,strlen(main_header));
	if(Debug) fprintf(stdout , "main_header[%d] : %s\n", len  ,main_header);
	
	// 2 .生成 Conten-Lenght(要发送的文件大小) ,并发送
	int wc_len = strlen( welcome_content );
	char sent_buf[64]={0};
	len = snprintf( sent_buf , 64 ,"Content-Length:%d\r\n\r\n" , wc_len );
	len = write(client_sock , sent_buf , len );
	if(Debug)  fprintf(stdout , "sent_buf[%d] : %s" , len ,sent_buf );
	
	// 3. 发送html文件
	len = write( client_sock , welcome_content , wc_len);
	if( Debug ) fprintf(stdout, "write[%d] : %s" , len , welcome_content );
								  
}

int get_line(int sock , char *buf ,int size ){
	//每次读取一个字符
	int count = 0 ;   //当前已经读取到的字符大小
    char ch = '\0';  
	int len = 0 ;
	while( (count < size -1) && ch!='\n'){
		len  = read(sock , &ch ,1);
		if( len == 1 ){  //正常读取成功
		    //处理 '\r(回车)  \n'
			if( ch=='\r')   continue;
			else if(ch=='\n'){
				//buf[count] = '\0';     //手动添加字符串结束符
				break;
			}
		//处理一般的字符
		buf[count++] = ch;
		}else if( len < 0 ){   //读取出错的情况
			perror("read fialed\n");
			count = -1;
			break;
		}else {   //len = 0 的情况   客户端关闭了sock连接
		    fprintf(stderr , "client close\n");
			count = -1 ;
			break;
		}
	}
	if( count >=0)  buf[count]='\0';
	//if(Debug)  printf("line information %s\n", buf);
	return count;  
}

void not_found( client_sock ){
	//状态行 + 消息报头
	const char *reply = "\
HTTP/1.1 404 NOT FOUND\r\n\
Server:wServer\r\n\
Content-Type:text/html\r\n\
Connection:Close\r\n";

	//404
	const char *sent_buf = "\
<!DOCTYPE html>\n\
<html lang=\"zh-CN\">\n\
<head>\n\
<meta charset=\"UTF-8\">\n\
<title>404 页面未找到</title>\n\
<style>\n\
body {\n\
text-align: center;\n\
padding: 150px;\n\
font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n\
}\n\
h1 {\n\
font-size: 50px;\n\
}\n\
body {\n\
font-size: 20px;\n\
}\n\
article {\n\
display: block;\n\
text-align: left;\n\
width: 650px;\n\
margin: 0 auto;\n\
}\n\
a {\n\
color: #00a2e8;\n\
text-decoration: none;\n\
}\n\
a:hover {\n\
text-decoration: underline;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<article>\n\
<h1>404 NOT FOUND</h1>\n\
<div>\n\
<p>抱歉,您试图访问的页面不存在。可能是链接错误或页面已被移除。</p>\n\
<p>您可以点击下面的链接返回<a href=\"/\">首页</a>或者进行搜索。</p>\n\
</div>\n\
</article>\n\
</body>\n\
</html>";
	
	
     int len = write( client_sock , reply ,strlen(reply));
	 if( Debug )  fprintf(stdout , "reply[%d] : %s",len , reply); 
	 // 发送 Conten-Lenght 
	 int sent_buf_size = strlen( sent_buf);
	 char content_lenght[64] ={0};
	 len = snprintf( content_lenght , 64 ,"Content-Length:%d\r\n\r\n", sent_buf_size );
	 len = write( client_sock , content_lenght , len );
	 if( Debug ) fprintf(stdout , "content_lenght[%d]:%s", len , content_lenght);
	 
	 // 3. 发送响应正文
	 len = write( client_sock , sent_buf , sent_buf_size );
	 if(Debug) fprintf(stdout ,"%s", sent_buf);
}

void unimplemented(int client_sock ){
		//状态行 + 消息报头
	const char *reply = "\
HTTP/1.1 501 Method Not Implemented\r\n\
Server:wServer\r\n\
Content-Type:text/html\r\n\
Connection:Close\r\n";

	//501
	const char *sent_buf = "\
<!DOCTYPE html>\n\
<html>\n\
<head>\n\
<meta charset=\"utf-8\">\n\
<title>HTTP 状态 501 – Method Not Implemented</title>\n\
<style type=\"text/css\">\n\
h1{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
font-size: 30px;\n\
}\n\
body{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: black;\n\
background-color: white;\n\
}\n\
b{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
p{\n\
font-family:Tahoma,Arial,scans-serif;\n\
background: white;\n\
color: black;\n\
}\n\
h3{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<h1 >HTTP 状态 501 – Method Not Implemented</h1>\n\
<hr class=\"line\">\n\
<p ><b >类型</b>异常报告</p>\n\
<p ><b>消息</b> 执行出异常</p>\n\
<p ><b>描述</b>  客户端请求方法有异常</p>\n\
<hr class=\"line\">\n\
<h3> Linux</h3>\n\
</body>\n\
</html>";
	
     int len = write( client_sock , reply ,strlen(reply));
	 if( Debug )  fprintf(stdout , "reply[%d] : %s",len , reply); 
	 // 发送 Conten-Lenght 
	 int sent_buf_size = strlen( sent_buf);
	 char content_lenght[64] ={0};
	 len = snprintf( content_lenght , 64 ,"Content-Length:%d\r\n\r\n", sent_buf_size );
	 len = write( client_sock , content_lenght , len );
	 if( Debug ) fprintf(stdout , "content_lenght[%d]:%s", len , content_lenght);
	 
	 // 3. 发送响应正文
	 len = write( client_sock , sent_buf , sent_buf_size );
	 if(Debug) fprintf(stdout ,"%s", sent_buf);
}

void bad_request( int client_sock ){
	//状态行 + 消息报头
	const char *reply = "\
HTTP/1.1 400 BAD REQUEST\r\n\
Server:wServer\r\n\
Content-Type:text/html\r\n\
Connection:Close\r\n";

	//400
	const char *sent_buf = "\
<!DOCTYPE html>\n\
<html>\n\
<head>\n\
<meta charset=\"utf-8\">\n\
<title>HTTP 状态 400 – Method Not Implemented</title>\n\
<style type=\"text/css\">\n\
h1{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
font-size: 30px;\n\
}\n\
body{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: black;\n\
background-color: white;\n\
}\n\
b{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
p{\n\
font-family:Tahoma,Arial,scans-serif;\n\
background: white;\n\
color: black;\n\
}\n\
h3{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<h1 >HTTP 状态 400 – Method Not Implemented</h1>\n\
<hr class=\"line\">\n\
<p ><b >类型</b>异常报告</p>\n\
<p ><b>消息</b> 执行出异常</p>\n\
<p ><b>描述</b>  客户端请求格式异常</p>\n\
<hr class=\"line\">\n\
<h3> Linux</h3>\n\
</body>\n\
</html>";
	
     int len = write( client_sock , reply ,strlen(reply));
	 if( Debug )  fprintf(stdout , "reply[%d] : %s",len , reply); 
	 // 发送 Conten-Lenght 
	 int sent_buf_size = strlen( sent_buf);
	 char content_lenght[64] ={0};
	 len = snprintf( content_lenght , 64 ,"Content-Length:%d\r\n\r\n", sent_buf_size );
	 len = write( client_sock , content_lenght , len );
	 if( Debug ) fprintf(stdout , "content_lenght[%d]:%s", len , content_lenght);
	 
	 // 3. 发送响应正文
	 len = write( client_sock , sent_buf , sent_buf_size );
	 if(Debug) fprintf(stdout ,"%s", sent_buf);
}

void Internal_Error(int client_sock){
	//状态行 + 消息报头
	const char *reply = "\
HTTP/1.1 500 Internal Server Error\r\n\
Server:wServer\r\n\
Content-Type:text/html\r\n\
Connection:Close\r\n";

	//500
	const char *sent_buf = "\
<!DOCTYPE html>\n\
<html>\n\
<head>\n\
<meta charset=\"utf-8\" />\n\
<title>HTTP 状态 500 – 内部服务器错误</title>\n\
<style type=\"text/css\">\n\
h1{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
font-size: 30px;\n\
}\n\
body{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: black;\n\
background-color: white;\n\
}\n\
b{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
p{\n\
font-family:Tahoma,Arial,scans-serif;\n\
background: white;\n\
color: black;\n\
}\n\
h3{\n\
font-family: Tahoma,Arial,scans-serif;\n\
color: white;\n\
background-color: #525d76;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<h1 >HTTP 状态 500 – Internal Server Error</h1>\n\
<hr class=\"line\">\n\
<p ><b >类型</b>异常报告</p>\n\
<p ><b>消息</b> 执行出异常</p>\n\
<p ><b>描述</b> 服务器收到请求, 因为自身原因没发响应。</p>\n\
<hr class=\"line\">\n\
<h3> Linux</h3>\n\
</body>\n\
</html>";
	
	
     int len = write( client_sock , reply ,strlen(reply));
	 if( Debug )  fprintf(stdout , "reply[%d] : %s",len , reply); 
	 // 发送 Conten-Lenght 
	 int sent_buf_size = strlen( sent_buf);
	 char content_lenght[64] ={0};
	 len = snprintf( content_lenght , 64 ,"Content-Length:%d\r\n\r\n", sent_buf_size );
	 len = write( client_sock , content_lenght , len );
	 if( Debug ) fprintf(stdout , "content_lenght[%d]:%s", len , content_lenght);
	 
	 // 3. 发送响应正文
	 len = write( client_sock , sent_buf , sent_buf_size );
	 if(Debug) fprintf(stdout ,"%s", sent_buf);
}



总结:

代码资源 + 数据 

链接:https://pan.baidu.com/s/1Mrq7EAeVYFkxXrK68yp9vA?pwd=0307 
提取码:0307 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/249730.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

源码解析:Apache RocketMQ重置消费位点

引入 reset offset&#xff0c;即重置消费进度&#xff0c;一般在以下场景中使用&#xff1a; 需要重新消费已经消费过的消息&#xff0c;重置到最早位置或根据时间进行重置。消息积压&#xff0c;不需要消费积压的消息&#xff0c;重置到最新位置&#xff0c;使其从最新位置…

订单管理系统开发经验的总结:优化流程、提升效率的关键实践

前言 一.订单管理系统的架构设计 二.订单系统的详细设计 1.拆分 2.换货 3.发货 4.拦截 5.取消 6.物流回传 三.订单系统的订单状态流转 初始状态 中间状态 异常状态 终态 四.订单系统的关键代码逻辑 五.结语 前言 两年来&#xff0c;整个订单管理系统经过大大小…

[MySQL]数据库概述

目录 1.什么是数据库 2.数据库分类 2.1关系型数据库 2.2非关系型数据库 1.什么是数据库 我们知道&#xff0c;存储数据可以使用文件来存储。那么为什么我们还要大费周章的去设计和使用数据库呢&#xff1f; 因为文件保存数据有以下几个缺点&#xff1a; 1.文件的安全性不…

Attention机制学习

写在前面 注意力机制是一个很不错的科研创新点方向&#xff0c;但是没有系统记录过学习过程&#xff0c;这里记录科研中遇到的各种注意力机制。 1. Attention机制解释 本质上来说用到attention的任务都有Query&#xff0c;Key&#xff0c;Value三个关键components&#xff0c;…

扩展学习|大数据挖掘与智能体ABM建模

出处&#xff1a;计算社会科学_中南大学_中国大学MOOC(慕课) (icourse163.org)https://www.icourse163.org/course/CSU-1466004186 ps&#xff1a;相关内容来自于本人笔记&#xff0c;若有需要请联系原作者&#xff01;个人学习留存&#xff0c;侵权必删&#xff01; 一…

可回收资源的环保螺旋盖葡萄酒

在酿酒师中&#xff0c;选择哪种瓶盖来保存一瓶葡萄酒主要取决于葡萄酒的种类和酿酒师自己的偏好。在20世纪70年代&#xff0c;澳洲朋友引进并推广了一种保存葡萄酒的新方法&#xff0c;这种新方法螺旋盖并在70年代获得专利&#xff0c;投入商业使用&#xff0c;澳大利亚的酿酒…

【STM32】STM32学习笔记-OLED显示屏(10)

00. 目录 文章目录 00. 目录01. OLED显示屏接线图02. OLED函数库03. OLED测试代码04. Keil调试05. 程序下载06. 附录 01. OLED显示屏接线图 02. OLED函数库 oled.h #ifndef __OLED_H #define __OLED_Hvoid OLED_Init(void); void OLED_Clear(void); void OLED_ShowChar(uint8…

图片变成动图如何操作?掌握这个办法就够了

生动有趣的gif动画图片是怎么制作的呢&#xff1f;其实&#xff0c;制作gif动图的方法很简单&#xff0c;无需下载任何软件&#xff0c;使用gif动图制作&#xff08;https://www.gif.cn/&#xff09;工具-GIF中文网。只需要上传jpg、png格式的图片&#xff0c;轻松一键就能在线…

Reinfocement Learning 学习笔记PartⅡ

文章目录 Reinfocement Learning六、随机近似与随机梯度下降&#xff08;Stochastic Approximation & Stochastic Gradient Descent&#xff09;6.1 Robbins-Monro Algorithm6.2 随机梯度下降 七、时序差分方法&#xff08;Temporal-Difference Learning&#xff09;7.1 TD…

OpenAI 承认 ChatGPT 最近的懒惰:由于用户体验到响应缓慢和无用的输出,调查正在进行中

文章目录 一. ChatGPT 指令遵循能力下降引发用户投诉1.1 用户抱怨回应速度慢、敷衍回答、拒绝回答和中断会话 二. OpenAI 官方确认 ChatGPT 存在问题&#xff0c;展开调查三. OpenAI 解释模型行为差异&#xff0c;回应用户质疑四. GPT-4 模型变更受人事动荡和延期影响 一. Chat…

【设计模式--行为型--中介者模式】

设计模式--行为型--中介者模式 中介者模式定义结构案例实现优缺点使用场景 中介者模式 定义 又叫调停模式&#xff0c;定义一个中介角色来封装一系列对象之间的交互&#xff0c;使原有对象之间的耦合松散&#xff0c;且可以独立的改变它们之间的交互。 结构 抽象中介者角色…

IntelliJ IDEA 运行 若依分离版后端

一、本地运行 一、选择打开IntelliJ IDEA项目 二、选择若依项目 如&#xff1a;java123 三、等待右下角的准备工作&#xff08;有进度条的&#xff09;完成 四、修改MySQL 五、修改资源上传目录 六、修改redis 七、然后点击运行 八、成功图 九、测试访问 二、部署服务器运行 …

策略+工厂完成支付方式选择(微信/支付宝),简单实现

需求 传参String payType wechat 使用微信支付传参String payType ali 使用支付宝支付代码不允许出现if-else 思路 把支付当作一个行为&#xff0c;代码中当作一个接口&#xff0c;payService。2个实现类&#xff0c;分别是微信支付实现类WeChatPayServiceImpl&#xff0c…

【数据结构】单链表的定义和操作

目录 1.单链表的定义 2.单链表的创建和初始化 3.单链表的插入节点操作 4.单链表的删除节点操作 5.单链表的查找节点操作 6.单链表的更新节点操作 7.完整代码 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助…

汽车充电协议OpenV2G的平替cbexigen!!

纵所周知&#xff0c;开源欧规协议 CCS 的 OpenV2G 协议不支持 ISO15118-20:2022 协议&#xff0c;并且软件维护者已经明确不在进行该软件的维护。 前几天在 Github 上冲浪发现了一个宝藏开源项目&#xff0c;完美的实现的 OpenV2G 的 Exidizer 工具的功能&#xff1a;cbexigen…

Goldstein枝切法对存在间断相位缺陷的解缠研究

摘要: Goldstein枝切法作为相位解缠中路径积分法的重要算法之一&#xff0c;其解缠结果易受到噪声或间断相位缺陷所引起的残差点影响。为了研究相位间断缺陷对解缠算法的影响&#xff0c;模拟了具有间断相位缺陷的数据&#xff0c;采用 Gold-stein枝切法进行了系统的解缠研究。…

嵌入式C语言变量、数组、指针初始化的多种操作

在敲代码的时候&#xff0c;我们会给变量一个初始值&#xff0c;以防止因为编译器的原因造成变量初始值的不确定性。 对于数值类型的变量往往初始化为0&#xff0c;但对于其他类型的变量&#xff0c;如字符型、指针型等变量等该如何初始化呢&#xff1f; 数值类变量初始化 整…

巴贝拉葡萄酒是单一品种还是混合品种制成的?

大多数巴贝拉葡萄酒都是由单一的巴贝拉葡萄品种制成的&#xff0c;许多意大利葡萄酒商开始尝试在巴贝拉葡萄酒中加入其它葡萄品种&#xff0c;其中两个最受欢迎的意大利品种是皮埃蒙特的巴贝拉德阿尔巴和达斯蒂。和朋友在一家意大利餐厅吃饭&#xff0c;被酒单吓到了&#xff1…

MySQL数据库 入门

目录 一、MySQL概述 二、MySQL安装 安装数据库 配置数据库 启动停止数据库 客户端连接数据库 三、数据模型 四、SQL 一、MySQL概述 先来讲解三个概念&#xff1a;数据库、数据库管理系统、 SQL 。 而目前主流的关系型数据库管理系统的市场占有率排名如下&#xff1a; …

Android--Jetpack--数据库Room详解一

人生何须万种愁&#xff0c;千里云烟一笑收 一&#xff0c;定义 Room也是一个ORM框架&#xff0c;它在SQLite上提供了一个抽象层&#xff0c;屏蔽了部分底层的细节&#xff0c;使用对象对数据库进行操作&#xff0c;进行CRUD就像对象调用方法一样的简单。 二&#xff0c;角色介…