Simple Http Server

자세한 소스는 github을 참고하세요.

https://github.com/lmk/SimpleHttpServer


SimpleHttpServer

  • very simple http server
  • default port: 8080
  • support: linux g++ 4.9.2

How to use

  • block server
HttpServer httpServer;

httpServer.Init(5, NULL);
httpServer.Run();
  • non-block
NBHttpServer* httpServer = NBHttpServer::getInstance();
httpServer->Init(5);
httpServer->Start();
sleep(60);
httpServer->Stop();


socket connect timeout


connection 할때 timeout 처리에 관해 찾아 보는 중.
nonblocking socket을 이용한 Rechard stevens의 소스가 있더군요.

Rechard stevens 소스 보기



예전에 포스팅 한 http socket client 에 적용하면서 windows 버전으로도 만들어 봤습니다.

int CHttpSocket::connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, struct timeval tval)
{
    int                flags, n, error;
    socklen_t        len;
    fd_set            rset, wset;

#ifdef WIN32
    int nonblocking =1;
    ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
    flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
#endif

    error = 0;
    if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
    {
#ifdef WIN32
        errno = WSAGetLastError();
#endif
        if (errno != EINPROGRESS && errno!= EWOULDBLOCK)
        {
            return(-1);
        }
    }

    /* Do whatever we want while the connect is taking place. */

    if (n == 0)
        goto done;    /* connect completed immediately */

    FD_ZERO(&rset);
    FD_SET(sockfd, &rset);
    wset = rset;

    if ( (n = select(sockfd+1, &rset, &wset, NULL,
                     ((tval.tv_sec>0) || (tval.tv_usec>0))? &tval : NULL)) == 0)
    {
        close(sockfd);        /* timeout */
        errno = ETIMEDOUT;
        return(-1);
    }

    if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
    {
#ifndef WIN32
        len = sizeof(error);
        if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
            return(-1);            /* Solaris pending error */
#endif
    } else
        return(-1); //err_quit("select error: sockfd not set");

done:
#ifdef WIN32
    nonblocking =0;
    ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
    fcntl(sockfd, F_SETFL, flags);    /* restore file status flags */
#endif

    if (error) {
        close(sockfd);        /* just in case */
        errno = error;
        return(-1);
    }
    return(0);
}


http socket client

급하게 필요해 날림으로 하루만에 뚝딱 만들었습니다.
아주 기본적인 동작만 합니다.

청크드 모드는 아직 구현되지 않았습니다.


-- History -------------------------------------------------------------------------

2006.08.31 : 생성 by newtype 
2006.11.24 : CHttpSocket::Request      메모리 릭 수정.
2007.03.31 : CHttpReqHeader::toString  메모리 덮어 쓰는 버그 수정
                 Windows에서도 컴파일 되게 수정
2007.05.29 : Connection 시점에도 timeout 적용(nonblocking socket사용)
2011.05.13 : Transfer-Encoding: chunked 모드 지원

-----------------------------------------------------------------------------------

사용예 보기


헤더 파일 보기


소스 파일 보기




Http프로토콜을 이용한 파일 다운로드

[CODE type=c++]
//-------------------------------------------------------------------------------------//
// Function    : GetFile
// Parameter: LPCTSTR url, LPCTSTR filename
// Return    : CString            
//            - 성공하면 "YES" 실패하면 에러메시지를 반환
// Note        : url의 파일을 받아서 filename에 저장한다.
//            LPCTSTR url      - http프로토콜을 이용해 받아올 파일의 전체경로
//            LPCTSTR filename - 파일을 저장할 local경로
//-------------------------------------------------------------------------------------//
CString CInternetImageCtrl::GetFile(LPCTSTR url, LPCTSTR filename)
{
  HINTERNET hInternet, hURL;

  // 연결
  hInternet = InternetOpen( L"HTTPFILE", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

  if ( hInternet == NULL )
     return L"인터넷이 연결되어 있지 않습니다.";

// url
  hURL = InternetOpenUrl( hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
  if ( hURL==NULL )
  {
     InternetCloseHandle( hInternet );
     return L"서버오류로 연결할 수 없습니다.";
  }

  // 연결정보 확인
  TCHAR szStatusCode[10000];
  DWORD dwInfoSize = 10000;
  HttpQueryInfo(hURL, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwInfoSize, NULL);


  long nStatusCode = _ttol(szStatusCode);
  if (nStatusCode == HTTP_STATUS_OK)
  { // 정상

     //  local file 생성
     HANDLE hFile;
     hFile = CreateFile( filename, GENERIC_WRITE, 0, NULL,
                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

     DWORD size;
     DWORD dwRead, dwWritten; //, Recv=0;
     char* buf = NULL;

     do
     {
        InternetQueryDataAvailable( hURL, &size, 0, 0 );
        buf = new char[size];
        InternetReadFile( hURL, buf, size, &dwRead );

        WriteFile( hFile, buf, dwRead, &dwWritten, NULL );
        delete buf;

     } while ( dwRead != 0 );

     CloseHandle( hFile );

  }
  else if (nStatusCode == HTTP_STATUS_NOT_FOUND)
  { // 404에러
     InternetCloseHandle( hInternet );
     InternetCloseHandle( hURL );
     return L"그림이 준비되지 않았습니다";
  } else
  { // 그외의 에러..
     InternetCloseHandle( hInternet );
     InternetCloseHandle( hURL );
     CString str;
     str.Format( L"Unknown Error
Err code : %d", nStatusCode);
     return str;
  }

  InternetCloseHandle( hInternet );
  InternetCloseHandle( hURL );

  return L"YES";
}


[/HTML][/CODE]

Http프로토콜을 이용한 파일 업로드

http서버에 올리는 소스이기 때문에
당연히 서버에 업로드 권한이 있어야 합니다.

[CODE type=c++]



void HttpPutFile(LPCTSTR wszServerURL, LPCTSTR wszRemoteFilePath,
                      LPCTSTR wszLocalFilePath, TCHAR nPort,
                      LPCTSTR wszLoginUserID, LPCTSTR wszLoginPassword )
{
/*
       TCHAR wszServerURL[100]         = L"solergy.com";
       TCHAR wszLocalFilePath[100]     = L"\Program Files\hanaro\Sign_AS\7250.bmp";
       TCHAR wszRemoteFilePath[100]  = L"/hanaro/sign/as/7250.bmp";
       TCHAR wszLoginUserID[100]       = L"";
       TCHAR wszLoginPassword[100]  = L"";
       TCHAR nPort                              = 80;
*/
       HINTERNET hInternet, hURL, hRequest;

       // 연결
       hInternet = InternetOpen( L"HTTPFILE", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
       if ( hInternet == NULL )
       {
               MessageBox( NULL, L"인터넷이 연결되어 있지 않습니다.", L"Warning", MB_OK);
               return;
       }

       // url
       hURL = InternetConnect( hInternet, wszServerURL, nPort,
                                                       wszLoginUserID, wszLoginPassword,
                                                       INTERNET_SERVICE_HTTP, 0, 0);
       if ( hURL==NULL )
       {
               InternetCloseHandle( hInternet );
               MessageBox( NULL, L"서버오류로 연결할 수 없습니다.", L"Warning", MB_OK);
               return;
       }

       INTERNET_BUFFERS        iBuf = {0};
       iBuf.dwStructSize = sizeof( INTERNET_BUFFERS );

       hRequest = HttpOpenRequest( hURL, L"PUT", wszRemoteFilePath, NULL, NULL, NULL, 0, 0 );
       if ( !hRequest )
       {
               InternetCloseHandle( hURL );
               InternetCloseHandle( hInternet );
               MessageBox( NULL, L"Request open Failed", L"Warning", MB_OK);
               return;
       }

       //  local file 오픈
       HANDLE hFile;
       hFile = CreateFile( wszLocalFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
       if ( hFile == INVALID_HANDLE_VALUE )
       {
               MessageBox( NULL, L"Invalid read File", L"warning", MB_OK);
               InternetCloseHandle( hRequest );
               InternetCloseHandle( hInternet );
               InternetCloseHandle( hURL );
               return;
       }


       DWORD dwWritten;
       DWORD dwFileSize, dwFilePos=0, dwRead;

       dwFileSize = GetFileSize( hFile, NULL );
       iBuf.dwBufferTotal = dwFileSize;

       if( !HttpSendRequestEx( hRequest, &iBuf, NULL, HSR_INITIATE, 0 ) )
       {
               MessageBox( NULL, L"SendRequest Failed", L"warning", MB_OK);
               CloseHandle( hFile );
               InternetCloseHandle( hRequest );
               InternetCloseHandle( hInternet );
               InternetCloseHandle( hURL );
               return;
       }

       char buf[512];
       DWORD cnt=0;
       dwFilePos = 0;
       do
       {
               SetFilePointer( hFile, dwFilePos, NULL, FILE_BEGIN );
               if( !ReadFile( hFile, buf, sizeof(buf), &dwRead, NULL) )
               {
                       MessageBox( NULL, L"Local File read error", L"Warning", MB_OK);
                       break;
               };

               InternetSetFilePointer( hRequest, dwFilePos, NULL, FILE_BEGIN, 0 );
               if( !InternetWriteFile( hRequest, buf, dwRead, &dwWritten ) )
               {
                       MessageBox( NULL, L"Remote File write error", L"Warning", MB_OK);
                       break;
               };
               dwFilePos += dwWritten;

       } while ( dwRead == sizeof(buf) );


       CloseHandle( hFile );

       if( !HttpEndRequest( hRequest, NULL, 0, 0 ) )
       {
               MessageBox( NULL, L"EndRequest Failed", L"warning", MB_OK);
       }

       InternetCloseHandle( hRequest );
       InternetCloseHandle( hInternet );
       InternetCloseHandle( hURL );

}

[/HTML][/CODE]