您的位置:首页 > 理论基础 > 计算机网络

HTTP 服务器程序

2015-08-01 14:35 716 查看
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"

#include "process.h"

#include "MFCHTTPSERVER.h"

#include "resource.h"

#include "MFCHTTPSERVERDlg.h"

//静态变量初始化

UINT CHttpProtocol::ClientNum = 0;

CCriticalSection CHttpProtocol::m_critSect; // 排斥区初始化

HANDLE CHttpProtocol::None = NULL;

CHttpProtocol::CHttpProtocol(void)

{

m_pListenThread=NULL;

m_hwndDlg=NULL;

}

CHttpProtocol::~CHttpProtocol(void)

{

}

void CHttpProtocol::CreateTypeMap()

{

// 初始化map

m_typeMap[".doc"] = "application/msword";

m_typeMap[".bin"] = "application/octet-stream";

m_typeMap[".dll"] = "application/octet-stream";

m_typeMap[".exe"] = "application/octet-stream";

m_typeMap[".pdf"] = "application/pdf";

m_typeMap[".ai"] = "application/postscript";

m_typeMap[".eps"] = "application/postscript";

m_typeMap[".ps"] = "application/postscript";

m_typeMap[".rtf"] = "application/rtf";

m_typeMap[".fdf"] = "application/vnd.fdf";

m_typeMap[".arj"] = "application/x-arj";

m_typeMap[".gz"] = "application/x-gzip";

m_typeMap[".class"] = "application/x-java-class";

m_typeMap[".js"] = "application/x-javascript";

m_typeMap[".lzh"] = "application/x-lzh";

m_typeMap[".lnk"] = "application/x-ms-shortcut";

m_typeMap[".tar"] = "application/x-tar";

m_typeMap[".hlp"] = "application/x-winhelp";

m_typeMap[".cert"] = "application/x-x509-ca-cert";

m_typeMap[".zip"] = "application/zip";

m_typeMap[".cab"] = "application/x-compressed";

m_typeMap[".arj"] = "application/x-compressed";

m_typeMap[".aif"] = "audio/aiff";

m_typeMap[".aifc"] = "audio/aiff";

m_typeMap[".aiff"] = "audio/aiff";

m_typeMap[".au"] = "audio/basic";

m_typeMap[".snd"] = "audio/basic";

m_typeMap[".mid"] = "audio/midi";

m_typeMap[".rmi"] = "audio/midi";

m_typeMap[".mp3"] = "audio/mpeg";

m_typeMap[".vox"] = "audio/voxware";

m_typeMap[".wav"] = "audio/wav";

m_typeMap[".ra"] = "audio/x-pn-realaudio";

m_typeMap[".ram"] = "audio/x-pn-realaudio";

m_typeMap[".bmp"] = "image/bmp";

m_typeMap[".gif"] = "image/gif";

m_typeMap[".jpeg"] = "image/jpeg";

m_typeMap[".jpg"] = "image/jpeg";

m_typeMap[".tif"] = "image/tiff";

m_typeMap[".tiff"] = "image/tiff";

m_typeMap[".xbm"] = "image/xbm";

m_typeMap[".wrl"] = "model/vrml";

m_typeMap[".htm"] = "text/html";

m_typeMap[".html"] = "text/html";

m_typeMap[".c"] = "text/plain";

m_typeMap[".cpp"] = "text/plain";

m_typeMap[".def"] = "text/plain";

m_typeMap[".h"] = "text/plain";

m_typeMap[".txt"] = "text/plain";

m_typeMap[".rtx"] = "text/richtext";

m_typeMap[".rtf"] = "text/richtext";

m_typeMap[".java"] = "text/x-java-source";

m_typeMap[".css"] = "text/css";

m_typeMap[".mpeg"] = "video/mpeg";

m_typeMap[".mpg"] = "video/mpeg";

m_typeMap[".mpe"] = "video/mpeg";

m_typeMap[".avi"] = "video/msvideo";

m_typeMap[".mov"] = "video/quicktime";

m_typeMap[".qt"] = "video/quicktime";

m_typeMap[".shtml"] = "wwwserver/html-ssi";

m_typeMap[".asa"] = "wwwserver/isapi";

m_typeMap[".asp"] = "wwwserver/isapi";

m_typeMap[".cfm"] = "wwwserver/isapi";

m_typeMap[".dbm"] = "wwwserver/isapi";

m_typeMap[".isa"] = "wwwserver/isapi";

m_typeMap[".plx"] = "wwwserver/isapi";

m_typeMap[".url"] = "wwwserver/isapi";

m_typeMap[".cgi"] = "wwwserver/isapi";

m_typeMap[".php"] = "wwwserver/isapi";

m_typeMap[".wcgi"] = "wwwserver/isapi";

}

bool CHttpProtocol::StartHttpSrv()

{

WORD wVersionRequested=WINSOCK_VERSION;

WSADATA wsaData;

int nRet;

//启动Winsock

nRet=WSAStartup(wVersionRequested,&wsaData);

if(nRet)

{

//错误处理

AfxMessageBox("Initialize WinSock Failed");

return false;

}

m_hExit=CreateEvent(NULL,TRUE,FALSE,NULL);

if(m_hExit==NULL)

{

return false;

}

//创建套接字

m_listenSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);

if(m_listenSocket==INVALID_SOCKET)

{

//异常处理

return false;

}

SOCKADDR_IN sockAddr;

// LPSERVENT lpServEnt;

if(m_nPort!=0)

{

sockAddr.sin_port=htons(m_nPort);

}

else

{

sockAddr.sin_port=htons(HTTPPORT);//默认端口号

}

sockAddr.sin_family=AF_INET;

char localName[256]; //本地机器名

gethostname(localName,256); //获取本机名

HOSTENT * pHost; //指向主机信息的指针

pHost=gethostbyname(localName);

sockAddr.sin_addr=*(in_addr *)pHost->h_addr_list[0];//设定IP地址

// 初始化content-type和文件后缀对应关系的map

CreateTypeMap();

//套接字绑定

nRet=bind(m_listenSocket,(LPSOCKADDR)&sockAddr,sizeof(sockaddr));

if(nRet==SOCKET_ERROR)

{

//绑定发生错误

closesocket(m_listenSocket); //断开连接

return false;

}

//套接字监听

nRet=listen(m_listenSocket,SOMAXCONN);

if(nRet==SOCKET_ERROR)

{

closesocket(m_listenSocket); //断开连接

return false;

}

//创建listening进程,接受客户机连接请求

m_pListenThread=AfxBeginThread(ListenThread,this);

if(!m_pListenThread)

{

closesocket(m_listenSocket);

return false;

}

CString *pStr1=new CString;

pStr1->Format("%s",localName);

CString strIP;

strIP=inet_ntoa(*(struct in_addr*)*(pHost->h_addr_list));

*pStr1=*pStr1+"["+strIP+"]"+"Port";

CString strTemp;

strTemp.Format("%d",htons(sockAddr.sin_port));

*pStr1=*pStr1+strTemp;

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr1,NULL);

return true;

}

UINT CHttpProtocol::ListenThread(LPVOID param)

{

CHttpProtocol *pHttpProtocol=(CHttpProtocol *)param;

SOCKET socketClient;

CWinThread* pClientThread;

SOCKADDR_IN SockAddr;

PREQUEST pReq;

int nLen;

//DWORD dwRet;

ClientNum=0;

HANDLE hNoClients;

hNoClients=CreateEvent(NULL,TRUE,TRUE,NULL);

while(1)

{

nLen=sizeof(SockAddr);

//套接字等待连接,返回对应已接受的客户机连接的套接字

socketClient=accept(pHttpProtocol->m_listenSocket,(LPSOCKADDR)&SockAddr,&nLen);

if(socketClient==INVALID_SOCKET)

{

continue;

}

//将客户端网络地址转换为用点分割的IP地址

CString *pStr=new CString;

pStr->Format("%s Connecting on socket:%d",inet_ntoa(SockAddr.sin_addr),socketClient);

SendMessage(pHttpProtocol->m_hwndDlg,LOG_MSG,(UINT)pStr,NULL);

pReq=new REQUEST;

if(pReq==NULL)

{

AfxMessageBox("No memory for request");

continue;

}

pReq->hExit=pHttpProtocol->m_hExit;

pReq->Socket=socketClient;

pReq->hFile=INVALID_HANDLE_VALUE;

pReq->dwRecv=0;

pReq->dwSend=0;

pReq->pHttpProtocol=pHttpProtocol;

//创建client进程,处理request

pClientThread=AfxBeginThread(ClientThread,pReq);

if(!pClientThread)

{

delete pReq;

}

}

//等待所有线程结束

WaitForSingleObject((HANDLE)pHttpProtocol->m_hExit,INFINITE);

//等待所有client进程结束

WaitForSingleObject(hNoClients,5000);

CloseHandle(None);

return 0;

}

UINT CHttpProtocol::ClientThread(LPVOID param)

{

int nRet;

BYTE buf[1024];

PREQUEST pReq=(PREQUEST)param;

CHttpProtocol *pHttpProtocol=(CHttpProtocol *)pReq->pHttpProtocol;

//进入临界区

m_critSect.Lock();

ClientNum++;

//离开临界区

m_critSect.Unlock();

//重置为无信号事件对象

ResetEvent(None);

if(!pHttpProtocol->RecvRequest(pReq,buf,sizeof(buf)))

{

closesocket(pReq->Socket);

delete pReq;

m_critSect.Lock();

if(ClientNum > 0)

{

ClientNum--;

}

// 离开排斥区

m_critSect.Unlock();

if(ClientNum < 1)

{

// 重置为有信号事件对象

SetEvent(None);

}

return 0;

}

nRet=pHttpProtocol->Analyze(pReq,buf);

if(nRet)

{

closesocket(pReq->Socket);

delete pReq;

m_critSect.Lock();

if(ClientNum > 0)

{

ClientNum--;

}

// 离开排斥区

m_critSect.Unlock();

if(ClientNum < 1)

{

// 重置为有信号事件对象

SetEvent(None);

}

return 0;

}

//生成并返回头部

pHttpProtocol->SendHeader(pReq);

if(pReq->nMethod==METHOD_GET)

{

pHttpProtocol->SendFile(pReq);

}

closesocket(pReq->Socket);

delete pReq;

//进入临界区

m_critSect.Lock();

if(ClientNum>0)

{

ClientNum--;

}

//离开临界区

m_critSect.Unlock();

if(ClientNum<1)

{

//重置为有信号事件对象

SetEvent(None);

}

return 0;

}

bool CHttpProtocol::RecvRequest(PREQUEST pReq, LPBYTE pBuf, DWORD dwBufSize)

{

WSABUF wsabuf; //发送/接收缓冲区结构

WSAOVERLAPPED over; //指向调用重叠操作时指定的WSAOVERLAPPED结构

DWORD dwRecv;

DWORD dwFlags;

DWORD dwRet;

HANDLE hEvents[2];

bool fPending;

int nRet;

memset(pBuf,0,dwBufSize); //初始化缓冲区

wsabuf.buf=(char *)pBuf;

wsabuf.len=dwBufSize;

over.hEvent=WSACreateEvent();

dwFlags=0;

fPending=FALSE;

//接收数据

nRet=WSARecv(pReq->Socket,&wsabuf,1,&dwRecv,&dwFlags,&over,NULL);

if(nRet!=0)

{

//错误代码WSA_IO_PENDING表示重叠操作成功启动

if(WSAGetLastError()!=WSA_IO_PENDING)

{

//重叠操作未能成功

CloseHandle(over.hEvent);

return false;

}

else

{

fPending=true;

}

}

if(fPending)

{

hEvents[0]=over.hEvent;

hEvents[1]=pReq->hExit;

dwRet=WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);

if(dwRet!=0)

{

CloseHandle(over.hEvent);

return false;

}

//重叠操作未完成

if(!WSAGetOverlappedResult(pReq->Socket,&over,&dwRecv,FALSE,&dwFlags))

{

CloseHandle(over.hEvent);

return false;

}

}

CloseHandle(over.hEvent);

return true;

}

int CHttpProtocol::Analyze(PREQUEST pReq, LPBYTE pBuf)

{

//分析接收到的信息

char szSeps[]="\n";

char *cpToken;

//cpToken=strtok((char *)pBuf,szSeps);// 缓存中字符串以“\n”为分解符分解为一组标记串,返回分解后的第一组字符串

// 防止非法请求

if (strstr((const char *)pBuf, "..") != NULL)//找到第二个字符串在第一个字符串第一次出现的位置

{

strcpy(pReq->StatuCodeReason, HTTP_STATUS_BADREQUEST);

return 1;

}

// 判断ruquest的mothed

cpToken = strtok((char *)pBuf, " "); // 缓存中字符串以“\n”为分解符分解为一组标记串,返回分解后的第一组字符串

//AfxMessageBox(cpToken);

//if(!_stricmp(cpToken,"GET"))

if(strstr(cpToken,"GET"))

{

pReq->nMethod=METHOD_GET;

}

//else if (!_stricmp(cpToken, "HEAD")) // HEAD命令

else if(strstr(cpToken,"HEAD"))

{

pReq->nMethod = METHOD_HEAD;

}

else

{

strcpy(pReq->StatuCodeReason, HTTP_STATUS_NOTIMPLEMENTED);

return 1;

}

//获取Request-URL

cpToken=strtok(NULL," "); //返回第二组字符串,即资源的路径

// AfxMessageBox(cpToken);

if(cpToken==NULL)

{

strcpy(pReq->StatuCodeReason,HTTP_STATUS_BADREQUEST);

return 1;

}

strcpy(pReq->szFileName,m_strRootDir);

if(strlen(cpToken)>1)

{

strcat(pReq->szFileName,cpToken); //把文件名添加到结尾处形成路径

}

else

{

strcat(pReq->szFileName,"/index.html");

}

// AfxMessageBox(pReq->szFileName);

return 0;

}

// 发送头部

void CHttpProtocol::SendHeader(PREQUEST pReq)

{

int n = FileExist(pReq);

if(!n)

{

return;

}

char Header[2048]="";

DWORD length;

length=GetFileSize(pReq->hFile,NULL);

char ContenType[50]="";

GetContenType(pReq,(char *)ContenType);

sprintf((char *)Header,"HTTP/1.0 %s\r\nServer:%s\r\nContent-Type:%s\r\nContent-Length:%d\r\n",

HTTP_STATUS_OK,

"My Http Server",

ContenType,

length);

//发送头部

send(pReq->Socket,Header,strlen(Header),0);

}

void CHttpProtocol::SendFile(PREQUEST pReq)

{

int n=FileExist(pReq);

if(!n)

{

return;

}

CString *pStr=new CString;

*pStr=*pStr+&pReq->szFileName[strlen(m_strRootDir)];

SendMessage(m_hwndDlg,LOG_MSG,UINT(pStr),NULL);

static BYTE buf[2048];

DWORD dwRead;

BOOL fRet;

int flag=1;

//读写数据直到完成

while(1)

{

//从file中读入到buffer中

fRet=ReadFile(pReq->hFile,buf,sizeof(buf),&dwRead,NULL);

if(!fRet)

{

static char szMsg[512];

wsprintf(szMsg,"%s",HTTP_STATUS_SERVERERROR);

//向客户端发送出错信息

send(pReq->Socket,szMsg,strlen(szMsg),0);

break;

}

//完成

if(dwRead==0)

{

break;

}

//将buffer内容传送给client

if(!SendBuffer(pReq,buf,dwRead))

{

break;

}

}

//关闭文件

if(CloseHandle(pReq->hFile))

{

pReq->hFile=INVALID_HANDLE_VALUE;

}

else

{

CString *pStr=new CString;

*pStr="Error occurs when closing file";

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr,NULL);

}

}

bool CHttpProtocol::SendBuffer(PREQUEST pReq,LPBYTE pBuf,DWORD dwBufSize)

{

//发送缓存中的内容

WSABUF wsabuf;

WSAOVERLAPPED over;

DWORD dwRecv;

DWORD dwFlags;

DWORD dwRet;

HANDLE hEvents[2];

BOOL fPending;

int nRet;

wsabuf.buf=(char *)pBuf;

wsabuf.len=dwBufSize;

over.hEvent=WSACreateEvent();

fPending=false;

//发送数据

nRet=WSASend(pReq->Socket,&wsabuf,1,&dwRecv,0,&over,NULL);

if(nRet!=0)

{

//错误处理

if(WSAGetLastError()==WSA_IO_PENDING)

{

fPending=true;

}

else

{

CString *pStr=new CString;

pStr->Format("WSASend() error:%d",WSAGetLastError());

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr,NULL);

CloseHandle(over.hEvent);

return false;

}

}

if(fPending)

{

hEvents[0]=over.hEvent;

hEvents[1]=pReq->hExit;

dwRet=WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);

if(dwRet!=0)

{

CloseHandle(over.hEvent);

return false;

}

//重叠操作未完成

if(!WSAGetOverlappedResult(pReq->Socket,&over,&dwRecv,FALSE,&dwFlags))

{

//错误处理

CString *pStr=new CString;

pStr->Format("WSAGetOverlappedResult() error:%d",WSAGetLastError());

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr,NULL);

CloseHandle(over.hEvent);

return false;

}

}

CloseHandle(over.hEvent);

return true;

}

int CHttpProtocol::FileExist(PREQUEST pReq)

{

pReq->hFile = CreateFile(pReq->szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

// int d=access(pReq->hFile,00);

// 如果文件不存在,则返回出错信息

AfxMessageBox(pReq->szFileName);

if (pReq->hFile == INVALID_HANDLE_VALUE)

{

strcpy(pReq->StatuCodeReason, HTTP_STATUS_NOTFOUND);

return 0;

}

else

{

return 1;

}

}

bool CHttpProtocol::GetContenType(PREQUEST pReq, LPSTR type)

{

// 取得文件的类型

CString cpToken;

cpToken = strstr(pReq->szFileName, ".");

strcpy(pReq->postfix, cpToken);

// 遍历搜索该文件类型对应的content-type

map<CString, char *>::iterator it = m_typeMap.find(pReq->postfix);

if(it != m_typeMap.end())

{

wsprintf(type,"%s",(*it).second);

}

return TRUE;

}

void CHttpProtocol::StopHttpSrv()

{

int nRet;

SetEvent(m_hExit);

nRet=closesocket(m_listenSocket);

nRet=WaitForSingleObject((HANDLE)m_pListenThread,10000);

if(nRet==WAIT_TIMEOUT)

{

CString *pStr=new CString;

*pStr="TIMEOUT waiting for ListenThread";

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr,NULL);

}

CloseHandle(m_hExit);

CString *pStr1=new CString;

*pStr1="Server Stopped";

SendMessage(m_hwndDlg,LOG_MSG,(UINT)pStr1,NULL);

}

*********************************************************************************************************************

MFCHTTPSERVERDlg.h文件:

// MFCHTTPSERVERDlg.h : 头文件

//

#include "HttpProtocol.h"

#pragma once

#define LOG_MSG (WM_USER+100)

// CMFCHTTPSERVERDlg 对话框

class CMFCHTTPSERVERDlg : public CDialog

{

// 构造

public:

CMFCHTTPSERVERDlg(CWnd* pParent = NULL); // 标准构造函数

CHttpProtocol *pHttpProtocol;

bool m_bStart;

// 对话框数据

enum { IDD = IDD_MFCHTTPSERVER_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现

protected:

HICON m_hIcon;

// 生成的消息映射函数

virtual BOOL OnInitDialog();

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

afx_msg LRESULT AddLog(WPARAM wParam, LPARAM lParam);

DECLARE_MESSAGE_MAP()

public:

UINT m_nPort;

CString m_strRootDir;

afx_msg void OnBnClickedStartStop();

afx_msg void OnBnClickedCancel();

};

******************************************************************************************************************************

MFCHTTPSERVERDlg.cpp文件:

// MFCHTTPSERVERDlg.cpp : 实现文件

//

#include "stdafx.h"

#include "MFCHTTPSERVER.h"

#include "MFCHTTPSERVERDlg.h"

#include "afxdialogex.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx

{

public:

CAboutDlg();

// 对话框数据

enum { IDD = IDD_ABOUTBOX };

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现

protected:

DECLARE_MESSAGE_MAP()

};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)

{

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

CDialogEx::DoDataExchange(pDX);

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)

END_MESSAGE_MAP()

// CMFCHTTPSERVERDlg 对话框

CMFCHTTPSERVERDlg::CMFCHTTPSERVERDlg(CWnd* pParent /*=NULL*/)

: CDialog(CMFCHTTPSERVERDlg::IDD, pParent)

, m_nPort(8000)

, m_strRootDir(_T(""))

{

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

void CMFCHTTPSERVERDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

DDX_Text(pDX, IDC_PORT, m_nPort);

DDX_Text(pDX, IDC_ROOTDIR, m_strRootDir);

}

BEGIN_MESSAGE_MAP(CMFCHTTPSERVERDlg, CDialog)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_MESSAGE(LOG_MSG, AddLog)

ON_BN_CLICKED(IDOK, &CMFCHTTPSERVERDlg::OnBnClickedStartStop)

ON_BN_CLICKED(IDCANCEL, &CMFCHTTPSERVERDlg::OnBnClickedCancel)

END_MESSAGE_MAP()

// CMFCHTTPSERVERDlg 消息处理程序

BOOL CMFCHTTPSERVERDlg::OnInitDialog()

{

CDialog::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);

if (pSysMenu != NULL)

{

BOOL bNameValid;

CString strAboutMenu;

bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);

ASSERT(bNameValid);

if (!strAboutMenu.IsEmpty())

{

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}

}

// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动

// 执行此操作

SetIcon(m_hIcon, TRUE); // 设置大图标

SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码

m_bStart=false;

return TRUE; // 除非将焦点设置到控件,否则返回 TRUE

}

void CMFCHTTPSERVERDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

if ((nID & 0xFFF0) == IDM_ABOUTBOX)

{

CAboutDlg dlgAbout;

dlgAbout.DoModal();

}

else

{

CDialog::OnSysCommand(nID, lParam);

}

}

// 如果向对话框添加最小化按钮,则需要下面的代码

// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,

// 这将由框架自动完成。

void CMFCHTTPSERVERDlg::OnPaint()

{

if (IsIconic())

{

CPaintDC dc(this); // 用于绘制的设备上下文

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// 使图标在工作区矩形中居中

int cxIcon = GetSystemMetrics(SM_CXICON);

int cyIcon = GetSystemMetrics(SM_CYICON);

CRect rect;

GetClientRect(&rect);

int x = (rect.Width() - cxIcon + 1) / 2;

int y = (rect.Height() - cyIcon + 1) / 2;

// 绘制图标

dc.DrawIcon(x, y, m_hIcon);

}

else

{

CDialog::OnPaint();

}

}

//当用户拖动最小化窗口时系统调用此函数取得光标

//显示。

HCURSOR CMFCHTTPSERVERDlg::OnQueryDragIcon()

{

return static_cast<HCURSOR>(m_hIcon);

}

LRESULT CMFCHTTPSERVERDlg::AddLog(WPARAM wParam, LPARAM lParam)

{

char szBuf[284];

CString *strTemp=(CString *)wParam;

CListBox* pListBox;

pListBox=(CListBox*)GetDlgItem(IDC_LOG);

SYSTEMTIME st;

GetLocalTime(&st);

wsprintf(szBuf,"%02d:%02d:%02d.%03d %s",st.wHour,st.wMinute,st.wSecond,

st.wMilliseconds,*strTemp);

pListBox->AddString(szBuf);

UpdateData(TRUE);

delete strTemp;

strTemp=NULL;

return 0;

}

void CMFCHTTPSERVERDlg::OnBnClickedStartStop()

{

// TODO: 在此添加控件通知处理程序代码

CWnd* pWndButton = GetDlgItem(IDOK);

if(!m_bStart)

{

UpdateData(TRUE);

pHttpProtocol=new CHttpProtocol;

pHttpProtocol->m_strRootDir=m_strRootDir;

pHttpProtocol->m_nPort=m_nPort;

pHttpProtocol->m_hwndDlg=m_hWnd;

if(pHttpProtocol->StartHttpSrv())

{

pWndButton->SetWindowTextA("停止服务");

m_bStart=true;

}

else

{

if(pHttpProtocol)

{

delete pHttpProtocol;

pHttpProtocol=NULL;

}

}

}

else

{

pHttpProtocol->StopHttpSrv();

pWndButton->SetWindowTextA("启动服务");

if(pHttpProtocol)

{

delete pHttpProtocol;

pHttpProtocol=NULL;

}

m_bStart=false;

}

//CDialog::OnOK();

}

void CMFCHTTPSERVERDlg::OnBnClickedCancel()

{

// TODO: 在此添加控件通知处理程序代码

if(m_bStart)

{

pHttpProtocol->StopHttpSrv();

}

if(pHttpProtocol)

{

delete pHttpProtocol;

pHttpProtocol=NULL;

}

m_bStart=false;

CDialog::OnCancel();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: