开源一个HTTP服务器的实现,不知道大家感兴趣否

bluemei-lee 2013-06-30 06:57:25
发这个是想看看坛子里有木有对小项目感兴趣的淫,如果比较多的话,接下来想开源最近完成的一个小编译器,也算是个铺垫.小编译器是为了解释小脚本(用于汽车电子行业的故障诊断及标定).
回到正题,这个http服务器是当年做的网络编程的课程设计,只能算一个用于学习的版本,还有很多不完善.
先总体的说说,主要包括3部分:
1.底层Socket实现. 这里用的是select模型.
2.HTTP协议,请求,回应,解析等.
3.逻辑方面处理.
上两个图
功能图(暂不管中间的点歌功能,重点讲HTTP)

流程图
...全文
173 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复
基础的Socket有了,接下类是第二部分:HTTP协议 HTTP协议本身我就不多说了,不了解的话可以去看看这两个链接:http://www.blogjava.net/zjusuyong/articles/304788.html http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html 2.1.接收HTTP请求,并解析请求内容 首先通过tcp套接字将用户请求读入到STL的string中,之后判断是否为http请求,也就是看是否在首行存在“HTTP”字串,然后判断是否为Post或Get或其它的方式,也是搜索字符串,接着是解析出其请求内容,比如“Get /index.html HTTP/1.1 …”,那么可以用substr方法截取出“index.html”来。其它头的解析还包括请求类型Content Type、请求报文长度Content Length等。表单和cookie的解析通过拆分子串实现,并将解析出的结果存入map中。最后将解析出的内容全部封装到HttpRequest类里。 2.2.分析请求内容,处理用户请求内容 通过解析之后,根据HttpRequest对象的各个成员变量来处理用户请求,如通过“type”来决定保存用户上传文件还是给用户读入所请求文件抑或是点歌,而通过“Content Length”来读取大小为contentLength的上传文件。 2.3.根据请求给予应答 处理好请求之后,准备响应,首先写入HTTP响应头,包括通用头、响应头、实体头,包括最主要的状态码“Status”,服务器名称Server头、是否保连接Connection头等响应头,以及通用头如时间Date头、缓存时长Cache Control头、,还有实体头如响应内容的类型Content Type头、长度Content Length头。
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复
Select模型中:1、创建监听套接字并绑定端口及进入侦听状态,初始化套接字集合,用FD_SET将套接字加入集合;2、利用select函数选择出请求建立连接的用户与之建立连接即调用accept;3、利用select函数选择出可读套接字,调用recv读取数据。循环往复的执行2、3步骤。 服务器套接字接收请求、读写操作 在服务套接字侦听状态时,以while循环来选择请求连接用户与之建立连接、选择可读套接字读入数据,分别调用accept()、recv()方法,这里将内容读入到了string中: len= readBytes(buf , BUFFER_SIZE , socket); requestContent+=string(buf,len); readBytes()是浅层封装了recv的一个方法,其中加入了异常处理。 发送回应时调用send()函数。
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复

class SelectModelServer
{
public:
	SelectModelServer(ReceiveAble& receiver);
	~SelectModelServer();
private:
	int m_nCurrentConCount;
	SOCKET m_serverSocket;  
	SOCKET m_socketArray[FD_SETSIZE];
	//bool m_bUseableArray[FD_SETSIZE];
	//sockaddr_in peerAddrs[MAXIMUM_WAIT_OBJECTS];

	ReceiveAble* m_pReceiver;
private:
	void onAccept();
	void onReceive(SOCKET&  clientSocket);
	void onClose(SOCKET&  clientSocket);
public:
	void init(unsigned short port);
	void startServer();
	void closeServer();
	void close(const SOCKET&  socket);
}; 
#endif

#include "SelectModelServer.h"

#include "ReceiveAble.h"

#pragma comment(lib,"ws2_32.lib")

SelectModelServer::SelectModelServer(ReceiveAble& receiver)
{
	this->m_pReceiver=&receiver;
	m_nCurrentConCount=0;
	/*for (int i=0;i<FD_SETSIZE;i++)
	{
		m_bUseableArray[i]=true;
	}*/
	for (int i=0;i<FD_SETSIZE;i++)
	{
		m_socketArray[i]=INVALID_SOCKET;
	}
}
SelectModelServer::~SelectModelServer()
{
	closeServer();
}
void SelectModelServer::init(unsigned short port)
{
	cout<<"init server(port:"<<port<<")..."<<endl;
	if(m_nCurrentConCount!=0)
		return;
	//1.初始化环境
	SocketTools::initSocketContext();
	//2.创建套接字
	m_serverSocket=socket(AF_INET,SOCK_STREAM,0);
	if(m_serverSocket<0)
		throw SocketException(WSAGetLastError(),"创建服务套接字失败");
	//3.绑定本地ip和端口
	sockaddr_in local_addr;
	int length =sizeof(sockaddr_in);
	memset(&local_addr,0,length);
	local_addr.sin_family=AF_INET;
	local_addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//htonl(inet_addr("127.0.0.1"));
	local_addr.sin_port=htons(port);
	if(bind(m_serverSocket,(struct sockaddr*)&local_addr,length) == SOCKET_ERROR)		
		throw SocketException(WSAGetLastError(),"绑定失败");
	//4.侦听端口
	if(listen(m_serverSocket,SOMAXCONN)== SOCKET_ERROR)		
		throw SocketException(WSAGetLastError(),"侦听失败");
	//5.设置非阻塞
	unsigned long nonBlock=1;
	if(ioctl(m_serverSocket,FIONBIO,&nonBlock)==SOCKET_ERROR) 
		throw SocketException(WSAGetLastError(),"设置为非阻塞失败"); 
	//6.加入集合
	this->m_socketArray[0]=m_serverSocket;
	m_nCurrentConCount++;
}
void SelectModelServer::startServer()
{
	cout<<("star server success.\n");
	int nReturn,i;
	struct timeval timeDelay;
	timeDelay.tv_sec=0;
	timeDelay.tv_usec=1000*10;
	fd_set readFdSet;
	while (true)
	{
		FD_ZERO(&readFdSet);
		for (i = 0; i <FD_SETSIZE; i++)// m_nCurrentConCount
		{
			if(m_socketArray[i]!=INVALID_SOCKET)
				FD_SET(this->m_socketArray[i],&readFdSet);
		}	
		nReturn=select(0,&readFdSet,NULL,NULL,&timeDelay);//返回 大于0--有效数 等于0--超时 小于0--异常
		if(nReturn==0)//超时
		{
			if(timeDelay.tv_usec<1000*1000)//1秒
				timeDelay.tv_usec+=10;//增加0.01毫秒
			continue;
		}
		else if(nReturn==SOCKET_ERROR)
		{			
			cout<<"select error:"<<SocketTools::getWinsockErrorMsg(::WSAGetLastError())<<endl;
			continue;
		}
		if(timeDelay.tv_usec>1000*2)//不超时时,若延时大于2毫秒则减少
		{
			timeDelay.tv_usec-=1000;//减少1000微秒
		}
#ifdef _DEBUG_TIME
		{	
			//正常
			printf("select sleep time:%d usecond\n",timeDelay.tv_usec);
		}
#endif
		//如何判断对方关闭
		for (i=0;i<FD_SETSIZE;i++)
		{
			if (FD_ISSET(m_socketArray[i], &readFdSet))
			{
				if(i==0)
					onAccept();
				else
					onReceive(m_socketArray[i]);
			}
		}
	}
}
void SelectModelServer::closeServer()
{
	//7.关闭服务套接字
	closesocket(m_serverSocket);
	//8.清除环境
	SocketTools::cleanUpSocketContext();
}
void SelectModelServer::onAccept()
{	
	//5.接收连接
	sockaddr_in peerAddr;
	int length=sizeof(sockaddr);
	//clientSocket=accept(m_serverSocket,(struct sockaddr*)(peerAddrs+m_nCurrentConCount),&length);
	SOCKET clientSocket=accept(m_serverSocket,(struct sockaddr*)(&peerAddr),&length);
	if(clientSocket==INVALID_SOCKET)
	{
		printf("accept error\n");	
		return;
	}
	//连接达到上限
	if(m_nCurrentConCount>=FD_SETSIZE-1)
	{
		closesocket(clientSocket);
		printf("reached max con:%d\n",m_nCurrentConCount);	
		return;
	}
	//数组前面的某个socket关闭了
	if(m_socketArray[m_nCurrentConCount]!=INVALID_SOCKET)
	{
		int i;
		for(i=0;i<m_nCurrentConCount;i++)
		{
			if(m_socketArray[i]==INVALID_SOCKET)
			{
				m_socketArray[i]=clientSocket;
				break;
			}
		}
		if(i==m_nCurrentConCount)//异常
		{
			printf("error when deal with con:%d\n",m_nCurrentConCount);
			closesocket(clientSocket);
			return;
		}
	}
	else
	{
		this->m_socketArray[m_nCurrentConCount]=clientSocket;
	}
	//增加一个连接		
	{		
		m_pReceiver->addPeerAddr(clientSocket,peerAddr);
		m_nCurrentConCount++;
	}
}
void SelectModelServer::onReceive(SOCKET& clientSocket)
{
	//6.接收信息
	/*
	char buf[1024];
	int length=recv(clientSocket,buf,sizeof(buf),0);
	if(length<=0 ||  strcmp(buf,"exit")==0)
	{
		printf("\n error\n");
		onClose(clientSocket);
		return;
	}
	buf[length]='\0';
	printf("收到信息(字节数%d):%s",length,buf);
	//*/
	unsigned long length=0;
	ioctl(clientSocket,FIONREAD,&length);
	if(length==0)
	{
		this->onClose(clientSocket);
		return;
	}
	this->m_pReceiver->onReceive(clientSocket,*this);
}
void SelectModelServer::onClose(SOCKET& clientSocket)
{
	if(clientSocket==INVALID_SOCKET)
		return;
	int n=closesocket(clientSocket);
	if(n==SOCKET_ERROR)
	{
		printf("close socket error\n");
		return;
	}
	m_pReceiver->removePeer(clientSocket);
	clientSocket=INVALID_SOCKET;
	m_nCurrentConCount--;
}
void SelectModelServer::close(const SOCKET&  socket)
{
	this->onClose((SOCKET)socket);
}
  • 打赏
  • 举报
回复
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复
接下来就是上面说的第一部分了:Socket实现
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复

class MainClass
{
public:
	void run(unsigned int port)
	{
		try{
			SocketChanel receiver;//处理数据类
			SelectModelServer server(receiver); //监听类,并注入receiver
			server.init(port); //初始化端口
			server.startServer();//进入select循环
		}catch(Exception& e)
		{
			e.printException();
		}
	}
};
int main()
{
	printf("欢迎使用网络081班点歌系统^-^\n");
	printf("请将您的歌曲目录添加到config/dirList.txt里面即可点播.\n");
	MainClass mainClass; 
	mainClass.run(8000);
	system("pause");
	return 0;
}
bluemei-lee 2013-06-30
  • 打赏
  • 举报
回复
咱们也按着程序的顺序来,先上主函数,伤不起的程序猿

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧