现在的位置: 首页 > 综合 > 正文

http服务器的实现1_网络服务器的实现

2013年06月30日 ⁄ 综合 ⁄ 共 3026字 ⁄ 字号 评论关闭

前段时间看了《深入理解计算机系统》,在网络编程这一章看到了一个http服务器的简单实现,然后也想自己在windows下面实现一个简单的http服务器。

       为了方面叙述,下面从实现的角度来一步步的说明怎么实现这个http服务器。其实说到http服务器也就是从浏览器发送给服务器一个http请求,服务器通过分析浏览器传过来的http包,解析并返回一个http响应给浏览器。所以说到底就是浏览器和服务器之间的网络通讯,通过操作系统给我们提供的socket接口函数,然后按照http协议打包数据就可以很容易的一个简单的http服务器。

       既然涉及到socket编程,那么我们就从socket接口方面入手来讨论http服务器。那么首先,我们必须明白http服务器是基于TCP协议的,而且默认端口为80,当然根据需要可以随时更换端口。

         要实现http服务器,第一步就是需要我们服务器在80端口上进行监听,等待客户端的连接。所以在程序的一开始,有如下的代码:

unsigned short usPort;

     printf("please input the port you want to listen:");

     scanf("%d",&usPort);

     SOCKETsocketListen=StartListen(usPort);

     if(socketListen==-1)

     {

         printf("Sorry,you can't open the listen socket.\n");

         return-1;

     }

     printf("启动web服务器成功,服务器地址为本机ip,端口为%d.\n",usPort);

StartListen这个函数里面创建了监听socket。

为了便于对程序流程的理解,暂时不在这里贴出StartListen的实现,大家只需要知道在这个函数里面服务器在usPort这个端口上实现了监听,并且返回监听套接字socketListen。

     开启了监听之后,服务器当然要等待客户端连接并处理连接,所以接下来肯定是要调用accept函数来,但是在怎么来调用accept函数呢,因为accpet函数的作用是等待客户端连接,并返回与客户端通讯的套接字。所以在这里我们必须要注意,我们做为服务器肯定不能只接受一个客户端请求,accept函数肯定要循环调用,调用完之后必须要与客户端进行交互,这里就有问题来了是直接在循环里面交互还是利用多线程进行交互?根据不同的交互模式有不同的模型。如果是单线程循环交互,那么一般就用select模型,如果多线程进行交互,就在accept成功返回后创建新的线程进行交互,在这里我用的是多线程模型,代码如下:

SOCKADDR_IN addrClient;

     intiAddr=sizeof(SOCKADDR_IN);

     SOCKETsocketSerice;

     SYSTEMTIMEst;

     while(1)

     {

         socketSerice=accept(socketListen,(SOCKADDR*)&addrClient,&iAddr);

         if(socketSerice<=0)

         {

              printf("sorry,you failed toaccept a client connect\n");

              continue;

         }

         GetLocalTime(&st);

         printf("有一个客户端连接.客户端的ip为:%s\t%d-%d-%d %d:%d:%d\n",inet_ntoa(addrClient.sin_addr),st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);

         unsigneduThreadID;

         _beginthreadex(NULL,0,ServerThread,(void*)socketSerice,0,&uThreadID);

     }

     WSACleanup();

上面就是我们http服务器的大致流程。

当然具体的http协议的交互在ServerThread里面与客户端进行交互。

下面来看StartListen的实现:

SOCKET StartListen(unsigned short usPort)

{

     InitSocket();//调用WSAStartup

     SOCKETsocketListen=socket(AF_INET,SOCK_STREAM,0);//创建TCP Socket

     if(socketListen<=0)

         return-1;

     intiVal=1;

     if(setsockopt(socketListen,SOL_SOCKET,SO_REUSEADDR,(const char*)&iVal,sizeof(int))<0)//使端口可以复用

         return-1;

     SOCKADDR_INaddrServer;

     memset(&addrServer,0,sizeof(addrServer));

     addrServer.sin_family=AF_INET;

     addrServer.sin_addr.s_addr=htonl(INADDR_ANY);

     addrServer.sin_port=htons(usPort);

     if(bind(socketListen,(SOCKADDR*)&addrServer,sizeof(addrServer))<0)

         return-1;

     if(listen(socketListen,1024)<0)//开启监听

         return-1;

     returnsocketListen;

}

接着来看线程函数ServerThread的实现:

unsigned WINAPI ServerThread(void*pVoid)

{

     SOCKETsocketSerice =(SOCKET)pVoid;

     charpcBuffer[MaxBuffer];

     intiRecv=0;

     RequestCotentrc;

     iRecv=GetData(socketSerice /*socketSerice*/,pcBuffer,MaxBuffer);//接收数据,也就是接受http请求

     if(iRecv<=0)

     {

         closesocket(socketSerice /*socketSerice*/);

         return-1;

     }

     rc=ParseData(pcBuffer,iRecv);//解析数据,也就是解析http包

     ResponseData(socketSerice /*socketSerice*/,rc);//根据解析的内容相应http请求

     closesocket(socketSerice /*socketSerice*/);//关闭该连接

     return0;

}

 

 

抱歉!评论已关闭.