c++实现简单http服务器

http基于tcp协议的应用层协议,说白了就是写死的自定义协议,代码实现了简单的get请求,打开服务后,可以通过网站访问本地资源,适合新手学习的简单代码,有助于理解get和http报文,很简单

HttpService.h
#ifndef HTTP_SERVICE
#define HTTP_SERVICE


#include <stdio.h>
#include <winsock2.h>
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib")  /* WinSock使用的库函数 */
 
 
/* 定义常量 */
#define HTTP_PORT					 6080		 /* 连接的缺省端口 */
#define HTTP_BUF_SIZE				 1024		 /* 缓冲区的大小 */
#define HTTP_FILENAME_LEN			 999		 /* 文件名长度 */
#define	HTTP_FILEEXTENSION_LEN		 20			//文件后缀长度
#define	HTTP_CMD_LEN				 20			//命令长度


/* 定义文件类型对应的 Content-Type */
struct FileExtension
{
    char * pExtensive;	 /* 文件后缀 */
    char * pType;			/* Content-Type */
};


 


class HttpService
{
public:
		char cRecvBuffer[HTTP_BUF_SIZE];				//缓存请求命令
protected:
		char cRecvFile[HTTP_FILENAME_LEN];				//请求文件
		char cExtensive[HTTP_FILEEXTENSION_LEN];		//文件后缀
		char cHttpCmd[HTTP_CMD_LEN];
		
public:
	HttpService();
	~HttpService();


public:
	void AnalyRecvBuffer();
	void HttpResponse(SOCKET sSocket);
protected:
	void Cmd_Get(SOCKET sSocket);
	void Cmd_Post(SOCKET sSocket);
	char *AnalyExtensive();
};










#endif;




httpService类实现

HttpService.cpp


#include "HttpService.h"


char * pHttpHead = "HTTP/1.1 200 OK\r\nDate:%s\r\nServer: ZhaoYueYou's Server \r\n"
    "Accept-Ranges: bytes\r\nContent-Length: %d\r\nConnection: close\r\n"
    "Content-Type: %s\r\n\r\n";
struct FileExtension FileType[] = 
	{
		{"html",    "text/html"  },
		{"gif",     "image/gif"  },
		{"jpeg",    "image/jpeg" },
		{"jpg",     "image/jpeg" },
		{"png",		"image/png"},
		{ "js",		"text/javascript"},
		{"css",		"text/css"},
		{"txt",		"text/plain"},
		{"mp4",		"video/mp4"},
		{ NULL,      NULL        }
	};



HttpService::HttpService()
{
	memset(cRecvBuffer,0,HTTP_BUF_SIZE);
	memset(cRecvFile,0,HTTP_FILENAME_LEN);
	memset(cExtensive,0,HTTP_FILEEXTENSION_LEN);
	memset(cHttpCmd,0,HTTP_CMD_LEN); 
}

HttpService::~HttpService()
{

}

void HttpService::AnalyRecvBuffer()
{
	int nLength = 0;
    char *pBegin;
	char *pEnd;
	char *pFile;
	int	nHeadLen = 0;

 
    /* 查找 URL 的开始位置 */
    pBegin = strchr(cRecvBuffer, ' ');

	nHeadLen =  pBegin-cRecvBuffer;
	if(nHeadLen<HTTP_CMD_LEN && nHeadLen>0)
		  memcpy(cHttpCmd, cRecvBuffer, nHeadLen);
	else
		std::cout<<"命令头长度异常 "<<std::endl;

    pBegin += 1;
         
    /* 查找 URL 的结束位置 */
    pEnd = strchr(pBegin, ' ');
    *pEnd = 0;
 
    pFile = strchr(pBegin, '/');
    nLength = pEnd - pFile;


 
    /* 找到文件名的开始位置 */
    if ((*pFile == '/') || (*pFile == '\\'))
    {
        pFile++;
        nLength--;
    }
    /* 得到文件名 */
    if (nLength > 0 && nLength <HTTP_FILENAME_LEN )
    {
        memcpy(cRecvFile, pFile, nLength);
        cRecvFile[nLength] = 0;
 
        pBegin = strchr(cRecvFile, '.');
		int nExtensiveLen = pEnd-pBegin;
        if (pBegin && nExtensiveLen<HTTP_FILEEXTENSION_LEN)
            strcpy(cExtensive, pBegin + 1);
		else
			std::cout<<"后缀长度异常 "<<std::endl;
    }
	else
		std::cout<<"文件长度异常 "<<std::endl;
}

void HttpService::HttpResponse(SOCKET sSocket)
{
	if(!strcmp(cHttpCmd,"GET"))
		Cmd_Get(sSocket);
	else if(!strcmp(cHttpCmd,"POST"))
		Cmd_Post(sSocket);
	else
	{
		std::cout<<"其他命令 "<<cHttpCmd<<std::endl;
	}

}
void HttpService::Cmd_Get(SOCKET sSocket)
{
	int nHttpHeadLen =0;
	int	nFileLen = 0;
	int nSendLen = 0;
	int nRendLen = 0;
	char cReadBuf[HTTP_FILENAME_LEN] = {0};


	FILE *pFile;
	char *pFileType;
    pFile = fopen(cRecvFile, "rb+"); /* 用二进制格式打开文件 */
    if (pFile == NULL)
    {
        printf("[Web] The file [%s] is not existed\n", cRecvFile);
        return ;
    }
	fseek(pFile, 0, SEEK_END);
    nFileLen = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);

	pFileType = AnalyExtensive();
	if (pFileType == NULL)
    {
        printf("[Web] There is not the related content type\n");
        return ;
    }

	SYSTEMTIME sys;   
	GetLocalTime( &sys );   
	char ptr[40]={0};
	sprintf( ptr,"%4d/%02d/%02d %02d:%02d:%02d.%03d ",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek);   



	 /* 构造 HTTP 首部,并发送 */
	char HttpHeader[HTTP_FILENAME_LEN]={0};
    nHttpHeadLen = sprintf(HttpHeader, pHttpHead,ptr, nFileLen, pFileType);
    nSendLen = send(sSocket, HttpHeader, nHttpHeadLen, 0);
	std::cout<<HttpHeader<<std::endl;
    //send_len=1;
    if (nSendLen == SOCKET_ERROR)
    {
        fclose(pFile);
        printf("[Web] Fail to send, error = %d\n", WSAGetLastError());
        return ;
    }
 
    do /* 发送文件, HTTP 的消息体 */
    {
        nRendLen = fread(cReadBuf, sizeof(char), HTTP_FILENAME_LEN, pFile);
 
        if (nRendLen > 0)
        {
            nSendLen = send(sSocket, cReadBuf, nRendLen, 0);
            nFileLen -= nRendLen;
        }
    } while ((nRendLen > 0) && (nFileLen > 0));
 
    fclose(pFile);
}
void HttpService::Cmd_Post(SOCKET sSocket)
{
}
char *HttpService::AnalyExtensive()
{
   struct FileExtension *pType;
 
   for (pType = FileType; pType->pExtensive; pType++)
    {
        if (strcmp(pType->pExtensive, cExtensive) == 0)
			return pType->pType;
    }
 
    return NULL;
}

入口 main

 

#include "HttpService.h"


void main()
{
	WSADATA wsa_data;
    SOCKET  srv_soc = 0, acpt_soc;  /* socket 句柄 */
    struct sockaddr_in serv_addr;   /* 服务器地址  */
    struct sockaddr_in from_addr;   /* 客户端地址  */
    unsigned short port = HTTP_PORT;
    int from_len = sizeof(from_addr);
	int result = 0,recv_len = 0;

    WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 资源 */
     
    srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */
    if (srv_soc == INVALID_SOCKET)
    {
        printf("[Web] socket() Fails, error = %d\n", WSAGetLastError());
		system("pause");
        return ; 
    }
     
    /* 服务器地址 */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//inet_pton(AF_INET,"180.173.168.61",&serv_addr.sin_addr.s_addr);
 
    result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    if (result == SOCKET_ERROR) /* 绑定失败 */
    {
        closesocket(srv_soc);
		perror("bind:");
        printf("[Web] Fail to bind, error = %d\n", WSAGetLastError());

		system("pause");
        return ; 
    }
 
    result = listen(srv_soc, SOMAXCONN);
    printf("[Web] The server is running ... ...\n");


	 
    while (1)
    {
        acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len);
        if (acpt_soc == INVALID_SOCKET) /* 接受失败 */
        {
            printf("[Web] Fail to accept, error = %d\n", WSAGetLastError());
			system("pause");
            break; 
        }
       
        printf("[Web] Accepted address:[%s], port:[%d]\n", 
            inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
 
		HttpService hService;
		recv_len = recv(acpt_soc, hService.cRecvBuffer, HTTP_BUF_SIZE, 0);
        if (recv_len == SOCKET_ERROR) /* 接收失败 */
        {
            closesocket(acpt_soc);
            printf("[Web] Fail to recv, error = %d\n", WSAGetLastError());
			system("pause");
            break; 
        }
 
        hService.cRecvBuffer[recv_len] = 0;
		hService.AnalyRecvBuffer();
		hService.HttpResponse(acpt_soc);
		closesocket(acpt_soc);

	}
	closesocket(srv_soc);
    WSACleanup();
    printf("[Web] The server is stopped.\n");
 
    return ;
 
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现一个简单HTTP服务器,可以使用Windows平台上的C/C++编程语言。 首先,你需要了解HTTP协议的基本知识,例如请求和响应的格式、HTTP方法(GET、POST等)、状态码以及标头字段(例如Content-Type、Content-Length等)。 然后,你可以使用Winsock库来创建一个基于套接字的服务器。使用`socket`函数创建一个套接字,然后使用`bind`函数将其绑定到指定的IP地址和端口号。 接下来,你可以使用`listen`函数开始监听传入的连接请求。当有客户端发送连接请求时,你可以使用`accept`函数接受该连接,并返回一个新的套接字,用于与客户端进行通信。 在收到客户端请求后,你可以使用`recv`函数接收HTTP请求。解析请求的首部和URI路径,并根据请求确定要执行的操作。 对于GET请求,你可以打开请求的文件,并将文件内容作为HTTP响应返回给客户端。你可以使用`fopen`函数打开文件,然后使用`fread`函数读取文件内容,并使用`send`函数发送响应到客户端。 对于POST请求,你可以解析请求体中的数据,并根据需求执行相应的操作。例如,你可以解析表单数据、存储到数据库或者进行其他处理。 最后,你可以使用`closesocket`函数关闭套接字,并释放相关资源。 需要注意的是,这只是一个简单HTTP服务器实现示例,如果你想要一个更完整和稳定的服务器,你可能需要处理并发连接、多线程或者使用更成熟的HTTP服务器框架。 总结起来,实现一个简单的Windows平台上的C/C++ HTTP服务器涉及到使用Winsock库创建套接字、接受连接请求、解析HTTP请求、处理请求并发送响应等步骤。希望这个回答对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值