HTTP 服务器程序

本文详细介绍了HTTP服务器的工作原理,包括HTTP消息的结构、请求消息和响应消息的格式,以及状态码的分类。此外,还展示了程序的主流程图,并提供了HTTP协议类`CHttpProtocol`的部分代码,用于处理请求、响应以及文件读取等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       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();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值