1、 HTTP只有两类消息:HTTP请求消息,由客户机端(如浏览器)向服务器发送的消息,用于请求服务器提供某种类型的服务;HTTP响应消息,服务器接收到请求消息之后返回给客户端的信息,表明服务器所作出的回答。两种消息具有相同的格式,通常分为消息头和消息体两个部分。消息头一定要有,消息体是可选的。消息头部的首行有特殊的格式,首行的后面有多个头部标题字段行,也简称为消息标题。每个头部标题行由标题字段名和字段值组成,他们之间有“:”隔开,标题字段名不区分大小写。
HTTP请求消息的一般格式:HTTP请求的头部细分为请求行和标题字段区域。头部请求行是HTTP请求报文的第一行,交代请求使用的方法,请求的目标,和HTTP的版本号。例:GET /index.html HTTP/1.1;HTTP请求的第二行起是头部的标题字段区域,可以安排一行或多行消息标题,常用字段有Accept 表示客户端期望接收的媒体类型,Host 表明请求资源所在的主机地址,Referer 用于记录客户端获得URL资源的地址,User-Agent 使用的用户代理,Connection 对TCP连接的处理方式。
典型的HTTP请求消息:
GET /path/file.html HTTP/1.0
User-Agent:HTTPTool/1.0
Connection:Close
HTTP响应消息的一般格式:HTTP响应消息由两大部分组成,消息头和消息体,两者之间使用一个空白行分开。消息头又可细分为响应的状态行和响应的标题字段,消息体是响应的实体数据。HTTP响应消息的第一行为状态行,由HTTP版本号、响应码和响应描述符文本构成,中间用空格相连。例:HTTP/1.1 200 ok。HTTP状态码分为5种类型:1xx 信息响应,表示接收到请求并且继续处理,2xx 处理成功响应,表示动作被成功接收、理解和接收、3xx 重定向响应,为了完成指定的动作,必须接受进一步处理,4xx 客户端错误,请求包含语法错误或者请求无法实现,5xx 服务器错误,服务器不能正确执行一个正确的请求。最常用的状态码有:
200 OK:请求成功,并且被请求的资源将会在响应消息中返回。
301 Moved Permanently:客户请求的对象已永久性迁移,新的URL在Location头中给出,浏览器会自动访问新的URL。
302 Moved Temporarily:所请求的对象被暂时迁移
400 Bad Request:服务器无法理解客户端的请求
404 Not Found:服务器不存在所请求的文档。客户端在对该请求作出更改前不应再次向服务器重复发送该请求
500 Server Error:服务器异常,不能完成客户的请求。
505 HTTP Version Not Supported:服务器不支持所请求的HTTP协议版本
HTTP响应可用的标题字段分为响应标题和实体标题两类:
响应标题有:Location 表示请求被重定向的URL的实际位置,使用绝对URL,并在响应字段返回3xx的响应码
Server 用于告知客户端服务器端使用的www服务器软件名称及版本信息
WWW-Authenticate 告知客户端受限资源所在的区域和要求的认证方法,同时应返回401响应码
实体标题有:Allow 告知客户机端他请求的资源所允许的请求方法
Content-Type 用于描述HTTP响应消息中所含有的实体数据的类型
Content-Length 用于描述消息内任何类型的实体数据长度
2、程序主流程图:
ClientThread流程图:
3、具体代码注释:
HTTPProtocol.h文件:
#ifndef _HTTPPROTOCOL_H
#define _HTTPPRPTOCOL_H
#pragma once
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib")
#define HTTPPORT 80
#define METHOD_GET 0
#define METHOD_POST 1
#define METHOD_HEAD 2
//响应码
#define HTTP_STATUS_OK "200 OK"
#define HTTP_STATUS_CREATED "201 Created"
#define HTTP_STATUS_ACCEPTED "202 Accepted"
#define HTTP_STATUS_NOCONTENT "204 No Content"
#define HTTP_STATUS_MOVEDPERM "301 Moved Permanently"
#define HTTP_STATUS_MOVEDTEMP "302 Moved Temporarily"
#define HTTP_STATUS_NOTMODIFIED "304 Not Modified"
#define HTTP_STATUS_BADREQUEST "400 Bad Request"
#define HTTP_STATUS_UNAUTHORIZED "401 Unauthorized"
#define HTTP_STATUS_FORBIDDEN "403 Forbidden"
#define HTTP_STATUS_NOTFOUND "404 File can not fonund!"
#define HTTP_STATUS_SERVERERROR "500 Internal Server Error"
#define HTTP_STATUS_NOTIMPLEMENTED "501 Not Implemented"
#define HTTP_STATUS_BADGATEWAY "502 Bad Gateway"
#define HTTP_STATUS_UNAVAILABLE "503 Service Unavailable"
typedef struct REQUEST
{
HANDLE hExit;
SOCKET Socket; //请求的socket
int nMethod; //请求的使用方法
DWORD dwRecv; //收到的字节数
DWORD dwSend; //发送的字节数
HANDLE hFile; //请求连接的文件
char szFileName[_MAX_PATH]; //文件的相对路径
char postfix[10]; //存储扩展名
char StatuCodeReason[100]; //响应码
bool permitted; //用户权限判断
char* authority; //用户提供的认证信息
char key[1024]; //正确认证信息
void* pHttpProtocol; //指向类CHttpProtocol的指针
}REQUEST,*PREQUEST;
#include <map>
#include <string>
using namespace std;
class CHttpProtocol
{
public:
HWND m_hwndDlg;
SOCKET m_listenSocket;
map<CString,char *> m_typeMap; //保存content-type和文件后缀的对应关系
CWinThread* m_pListenThread;
HANDLE m_hExit;
static HANDLE None; //标志是否有Client连接到服务器
static UINT ClientNum; //连接的Client数量
static CCriticalSection m_critSect; //互斥变量
CString m_strRootDir; //web的根目录
UINT m_nPort; //服务器的端口号
void CreateTypeMap(); //创建content-type和文件后缀map
void StopHttpSrv(); //关闭服务
bool StartHttpSrv(); //启动服务
static UINT ListenThread(LPVOID param); //监听线程
static UINT ClientThread(LPVOID param); //请求处理线程
bool RecvRequest(PREQUEST pReq, LPBYTE pBuf, DWORD dwBufSize);
int Analyze(PREQUEST pReq, LPBYTE pBuf);
void SendHeader(PREQUEST pReq);
int FileExist(PREQUEST pReq);
void SendFile(PREQUEST pReq);
bool SendBuffer(PREQUEST pReq, LPBYTE pBuf, DWORD dwBufSize);
bool GetContenType(PREQUEST pReq, LPSTR type);
CHttpProtocol(void);
~CHttpProtocol(void);
};
#endif _HTTPPROTOCOL_H
********************************************************************************************************************************
HTTPProtocol.cpp文件:
#include "stdafx.h"
#include "HttpProtocol.h