簡單WEB服務器源碼

#include <afx.h> //爲了使用CFile 類:1、添加#include <afx.h>;2、工程中設置MFC的DLL
#include <stdio.h>
#include <iostream.h>
#include <winsock2.h>
#include <sys/stat.h>
#include <fstream.h>
#pragma comment(lib, "ws2_32")

/*******************
//創建服務器套接字
*******************/
SOCKET createServerSocket()
{
    WSADATA ws;
    WSAStartup(MAKEWORD(1,1), &ws);

    SOCKADDR_IN sockaddr;
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);  //inet_addr("127.0.0.1");
    sockaddr.sin_port = htons(6000);

 SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
 if (serverSocket == INVALID_SOCKET)
 {
  cout<<"創建服務器套接字失敗!"<<endl;
  return WSAGetLastError();
 }

 int err = bind(serverSocket, (SOCKADDR*)&sockaddr, sizeof(SOCKADDR));
 if (err == SOCKET_ERROR)
 {
  cout<<"綁定失敗!"<<endl;
  return WSAGetLastError();
 }
 ::listen(serverSocket, 2);

 return serverSocket;
}

/*****************************
//查找服務器根目錄下的文件清單
******************************/
void findAllFile(CString path, CString* fileNames, CString serverIP)
{
 CString subPath = path;
 CFileFind fileFinder;
 BOOL working = fileFinder.FindFile(path + "*.*");
 while(working)
 {
  working = fileFinder.FindNextFile();
  if (fileFinder.IsDots())
  {
   continue;
  }
  if (fileFinder.IsDirectory())
  {
   //subPath = subPath + fileFinder.GetFileName() + "/";
   //findAllFile(subPath, fileNames, serverIP);
   //cout<<"subPath:"<<subPath<<endl;

   continue;
  }
  CString filename = fileFinder.GetFileName();
  *fileNames = *fileNames + "<a href = HTTP://" + serverIP + "/" + filename + ">" + filename + "</a><br>";

 }
}

/**************************
//在指定串中查找服務器IP
**************************/
void getIP(char* requstSrc)
{
 char *IP = ::strstr(requstSrc, "Host:");
 char host[10];
 char sIP[30];
 ::sscanf(IP, "%s%s", host, sIP);
 ::memcpy(requstSrc, sIP, sizeof(sIP));

}

/*******************
//處理請求線程
*******************/
DWORD WINAPI AcceptProc(LPVOID lpParameter)
{
 SOCKET* pSocket = (SOCKET*)lpParameter;
 char buf[512];
 memset(buf, 0, 512);
 recv(*pSocket, buf, 512, 0);  //接受請求內容

 char commands[10];
 char arguments[512];
 char currentDirec[100];
 memset(commands, 0 ,10);
 memset(arguments, 0, 512);
 memset(currentDirec, 0, 100);

 ::GetCurrentDirectory(100, currentDirec);
 //訪問服務器根目錄
 char rootDirec[512];
 memcpy(rootDirec, currentDirec, sizeof(currentDirec));
 memcpy(arguments, currentDirec, sizeof(currentDirec));
 strcat(rootDirec, "/");
 cout<<rootDirec<<endl;

 sscanf(buf, "%s%s", commands, arguments + strlen(currentDirec));
 cout<<arguments<<endl; 

 //判斷請求方法
 if (strcmp(commands, "GET") != 0)
 {
  cout<<"請求方法出錯!"<<endl;
  return -1;
 }

 if (strcmp(arguments, rootDirec) ==0)
 {
  //獲取請求的服務器的IP及端口號
  getIP(buf);
  cout<<buf<<endl;

  CString filenames;
  findAllFile(arguments, &filenames, buf); //服務器根目錄文件列表
  cout<<filenames<<endl;


  char content[1024];
  memset(content, 0, 1024);
  sprintf(content, "<head><title>index.html</title></head><body>%s</body>", filenames);

  //發送目錄給客戶端
  char head[2048];
  memset(head, 0, 2048);
  sprintf(head, "HTTP/1.1 200 OK/r/nContent-Type: text/html/r/nContent-Length: %d/r/n/r/n%s", sizeof(content), content);
  send(*pSocket, head, strlen(head), 0);
  closesocket(*pSocket);

 }
 else
 {
  //判斷請求的文件是否存在
  struct stat file_info;
  int result = stat(arguments, &file_info);
  if (result != 0)
  {
   cout<<"請求文件不存在"<<endl;

   char content[512];
   memset(content, 0 ,512);
   sprintf(content, "<head><title>error.html</title></head><body>Not Found: %s</body>", arguments);
   char response[1024];
   memset(response, 0 ,1024);
   sprintf(response, "HTTP/1.1 200 OK/r/nContent-Type: text/html/r/nContent-Length: %d/r/n/r/n%s", strlen(content), content);

   send(*pSocket, response, sizeof(response), 0);
   closesocket(*pSocket);

   return -1;
  }

  //檢查請求文件的類型
  char *extension = ::strrchr(arguments, '.');
  //cout<<extension+1<<endl;
  char *Content_Type = "text/html";
  if (strcmp(extension + 1, "html") == 0)
  {
   Content_Type = "text/html";
  }
  else if(strcmp(extension + 1, "jpg") == 0){
   Content_Type = "image/jpeg";
  }

  //讀取請求路徑的文件
  CFile readFrom(arguments, CFile::typeBinary); //以二進制格式傳輸
  int fileLength = readFrom.GetLength();

  char head[512];
  memset(head, 0, 512);
  sprintf(head, "HTTP/1.1 200 OK/r/nContent-Type: %s/r/nContent-Length: %d/r/n/r/n", Content_Type, fileLength);

  int n = send(*pSocket, head, strlen(head), 0); //開始錯誤地用sizeof(head)
  cout<<"n: "<<n<<endl;

  memset(buf, 0, 512);
  int left = 0;
  int sended = 0;
  int readNum = 0;
  while(left < fileLength)
  {
   readNum = readFrom.Read(buf, 512);
   sended = send(*pSocket, buf, readNum, 0);
   left = left + sended;
  }
 }

    closesocket(*pSocket);

 return 0;
}

/*******************
//MIAN程序入口
*******************/
int main(int argc, char* argv[])
{
 cout<<"********************************************"<<endl;
 cout<<"             WEB服務器啓動..."<<endl;
 cout<<"********************************************"<<endl;

 SOCKET hSocket = createServerSocket();

    while (true)
    {
  SOCKADDR_IN clientaddr;
  int len = sizeof(SOCKADDR);
        SOCKET newSocket = accept(hSocket, (SOCKADDR*)&clientaddr, &len);

  //創建堆對象
  SOCKET* pSocket = new SOCKET;
  pSocket = &newSocket;

   //創建線程處理客戶端請求
  HANDLE hThread = ::CreateThread(NULL, 0, AcceptProc, pSocket, 0, NULL);
  ::CloseHandle(hThread);

  cout<<"創建客戶端請求線程: "<<*pSocket<<endl;
 
    }
    ::WSACleanup();
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章