Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

OWIN 웹 서버(EXE)를 IIS에서 호스팅하는 방법 - HttpPlatformHandler (Reverse Proxy)

지난 글에서 일반적인 웹 서버를 IIS에서 호스팅하는 방법을 살펴봤습니다.

사용자 정의 웹 서버(EXE)를 IIS에서 호스팅하는 방법 - HttpPlatformHandler (Reverse Proxy)
; https://www.sysnet.pe.kr/2/0/11434

그런데, OWIN으로 만든 웹 서버의 경우 HttpPlatformHandler를 이용해 호스팅하는 경우 w3wp.exe의 자식 프로세스로 웹 서버 EXE가 살았다 죽었다를 빠르게 반복하다가 결국 웹 브라우저에서는 다음과 같은 오류 메시지만을 보게 됩니다.

HTTP Error 502.3 - Bad Gateway
There was a connection error while trying to route the request.

Most likely causes:
* The CGI application did not return a valid set of HTTP errors.
* A server acting as a proxy or gateway was unable to process the request due to an error in a parent gateway.

Things you can try:
* Use DebugDiag to troubleshoot the CGI application.
* Determine if a proxy or gateway is responsible for this error.

Detailed Error Information:

Module httpPlatformHandler 

Notification ExecuteRequestHandler 

Handler httpplatformhandler 

Error Code 0x8007065f 

Requested URL http://localhost:8094/ 

Physical Path D:\owin_core 

Logon Method Anonymous 

Logon User Anonymous 

More Information:
This error occurs when a CGI application does not return a valid set of HTTP headers, or when a proxy or gateway was unable to send the request to a parent gateway. You may need to get a network trace or contact the proxy server administrator, if it is not a CGI problem. 

아울러 이벤트 로그에는 다음의 메시지들을 확인할 수 있습니다.

The description for Event ID 1000 from source HttpPlatformHandler cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.

If the event originated on another computer, the display information had to be saved with the event.

The following information was included with the event: 

Process '5744' failed to start. Port = 25608, Error Code = '-2147023265'.

Error Code인 -2147023265 값은 0x8007065F이며, 의미하는 바는 "The Windows Installer service failed to start. Contact your support personnel."입니다.




그런데 지난번 예제로 만들었던 소켓 서버는 잘 동작했는데 왜 Owin 서버는 문제가 발생하는 걸까요? 그 차이점을 알기 위해 netstat -ano 명령어로 살펴봤습니다.

// 소켓 서버에서 29501 포트로 대기한 경우,
C:\temp> netstat -ano | findstr 29501
  Proto  Local Address          Foreign Address        State           PID
  TCP    127.0.0.1:29501        0.0.0.0:0              LISTENING       4928

// Owin 서버에서 29501 포트로 대기한 경우,
C:\temp> netstat -ano | findstr 29501
  Proto  Local Address          Foreign Address        State           PID
  TCP    127.0.0.1:29501        0.0.0.0:0              LISTENING       4

차이점이 보이시나요? 동작을 제대로 한 소켓 서버의 소유권은 해당 프로세스가 소유한 반면, 정상적이지 못했던 Owin 서버는 소켓 소유권이 4번 프로세스(System)에 있습니다. 그러고 보니 System 프로세스가 소켓 소유권을 가지는 상황을 이전에 겪은 적이 있습니다.

IIS의 80 포트를 공유하는 응용 프로그램 만드는 방법
; https://www.sysnet.pe.kr/2/0/1555

정말 저것 때문에 그런 것인지 간단하게 HttpListener를 이용한 예제를 만들어,

using System;
using System.Net;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static int Main(string[] args)
        {
            StartHTTP();
            return 0;
        }

        private static void StartHTTP()
        {
            int port = GetPort();

            HttpListener httpServer = new HttpListener();

            httpServer.Prefixes.Add($"http://localhost:{port}/");
            httpServer.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
            httpServer.Start();

            httpServer.BeginGetContext(ProcessRequest, httpServer);

            Thread.Sleep(-1);
        }

        static void ProcessRequest(IAsyncResult ar)
        {
            HttpListener listener = ar.AsyncState as HttpListener;
            HttpListenerContext ctx = listener.EndGetContext(ar);

            HttpListenerRequest req = ctx.Request;
            HttpListenerResponse resp = ctx.Response;

            StringBuilder sb = new StringBuilder();
            sb.Append("<html><body><h1>" + DateTime.Now + "</h1>");
            sb.Append("</body></html>");

            byte[] buf = Encoding.UTF8.GetBytes(sb.ToString());
            resp.OutputStream.Write(buf, 0, buf.Length);
            resp.OutputStream.Close();

            listener.BeginGetContext(ProcessRequest, listener);
        }

        private static int GetPort()
        {
            int port = 29501;

            string value = Environment.GetEnvironmentVariable("HTTP_PLATFORM_PORT");
            if (int.TryParse(value, out int userPort) == true)
            {
                port = userPort;
            }

            return port;
        }
    }
}

(위의 코드는 첨부 파일에 포함되어 있습니다.)

지난번 글에서와 같이 테스트를 할 수 있습니다. 위의 예제 코드로 HttpPlatformHandler를 연결하면 Owin 서버와 마찬가지로 HTTP Error 502.3 - Bad Gateway 오류가 발생합니다.




실제로 Owin 서버는 내부적으로 HttpListener를 사용합니다. 그렇다면 Owin 서버를 HttpPlatformHandler와 연결하기 위해서는 HttpListener를 Socket으로 교체를 해야 합니다. 다행히 ^^ 찾아보면 이에 대한 작업을 github에서 볼 수 있습니다.

Bobris/Nowin 
; https://github.com/Bobris/Nowin

그래서 다음과 같이 Owin 서버를 만들게 되면,

// Install-Package Nowin -Version 0.26.0
// https://www.nuget.org/packages/Nowin/

static class Program
{
    static void Main(string[] args)
    {
        int port = GetPort();
        string baseAddress = $"http://127.0.0.1:{port}/";

        var options = new StartOptions(baseAddress)
        {
            ServerFactory = "Nowin",
        };

        using (WebApp.Start<Startup>(options))
        {
            Thread.Sleep(-1);
        }
    }

    private static int GetPort()
    {
        int port = 29501;

        string value = Environment.GetEnvironmentVariable("HTTP_PLATFORM_PORT");
        if (int.TryParse(value, out int userPort) == true)
        {
            port = userPort;
        }

        return port;
    }
}

(위의 코드는 첨부 파일에 포함되어 있습니다.)

정상적으로 HttpPlatformHandler와 연동이 되는 것을 확인할 수 있습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 1/16/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 16  17  18  19  20  21  22  23  24  25  26  27  28  [29]  30  ...
NoWriterDateCnt.TitleFile(s)
12897정성태1/2/20227851.NET Framework: 1128. C# - 화면 캡처한 이미지를 ffmpeg(FFmpeg.AutoGen)로 동영상 처리 [4]파일 다운로드1
12896정성태1/1/202210716.NET Framework: 1127. C# - FFmpeg.AutoGen 라이브러리를 이용한 기본 프로젝트 구성파일 다운로드1
12895정성태12/31/20219224.NET Framework: 1126. C# - snagit처럼 화면 캡처를 연속으로 수행해 동영상 제작 [1]파일 다운로드1
12894정성태12/30/20217173.NET Framework: 1125. C# - DefaultObjectPool<T>의 IDisposable 개체에 대한 풀링 문제 [3]파일 다운로드1
12893정성태12/27/20218710.NET Framework: 1124. C# - .NET Platform Extension의 ObjectPool<T> 사용법 소개파일 다운로드1
12892정성태12/26/20216701기타: 83. unsigned 형의 이전 값이 최댓값을 넘어 0을 지난 경우, 값의 차이를 계산하는 방법
12891정성태12/23/20216625스크립트: 38. 파이썬 - uwsgi의 --master 옵션
12890정성태12/23/20216760VC++: 152. Golang - (문자가 아닌) 바이트 위치를 반환하는 strings.IndexRune 함수
12889정성태12/22/20219173.NET Framework: 1123. C# - (SharpDX + DXGI) 화면 캡처한 이미지를 빠르게 JPG로 변환하는 방법파일 다운로드1
12888정성태12/21/20217365.NET Framework: 1122. C# - ImageCodecInfo 사용 시 System.Drawing.Image와 System.Drawing.Bitmap에 따른 Save 성능 차이파일 다운로드1
12887정성태12/21/20219418오류 유형: 777. OpenCVSharp4를 사용한 프로그램 실행 시 "The type initializer for 'OpenCvSharp.Internal.NativeMethods' threw an exception." 예외 발생
12886정성태12/20/20217361스크립트: 37. 파이썬 - uwsgi의 --enable-threads 옵션 [2]
12885정성태12/20/20217605오류 유형: 776. uwsgi-plugin-python3 환경에서 MySQLdb 사용 환경
12884정성태12/20/20216674개발 환경 구성: 620. Windows 10+에서 WMI root/Microsoft/Windows/WindowsUpdate 네임스페이스 제거
12883정성태12/19/20217516오류 유형: 775. uwsgi-plugin-python3 환경에서 "ModuleNotFoundError: No module named 'django'" 오류 발생
12882정성태12/18/20216614개발 환경 구성: 619. Windows Server에서 WSL을 위한 리눅스 배포본을 설치하는 방법
12881정성태12/17/20217159개발 환경 구성: 618. WSL Ubuntu 20.04에서 파이썬을 위한 uwsgi 설치 방법 (2)
12880정성태12/16/20216935VS.NET IDE: 170. Visual Studio에서 .NET Core/5+ 역어셈블 소스코드 확인하는 방법
12879정성태12/16/202113171오류 유형: 774. Windows Server 2022 + docker desktop 설치 시 WSL 2로 선택한 경우 "Failed to deploy distro docker-desktop to ..." 오류 발생
12878정성태12/15/20218219개발 환경 구성: 617. 윈도우 WSL 환경에서 같은 종류의 리눅스를 다중으로 설치하는 방법
12877정성태12/15/20216887스크립트: 36. 파이썬 - pymysql 기본 예제 코드
12876정성태12/14/20216721개발 환경 구성: 616. Custom Sources를 이용한 Azure Monitor Metric 만들기
12875정성태12/13/20216444스크립트: 35. python - time.sleep(...) 호출 시 hang이 걸리는 듯한 문제
12874정성태12/13/20216410오류 유형: 773. shell script 실행 시 "$'\r': command not found" 오류
12873정성태12/12/20217535오류 유형: 772. 리눅스 - PATH에 등록했는데도 "command not found"가 나온다면?
12872정성태12/12/20217342개발 환경 구성: 615. GoLang과 Python 빌드가 모두 가능한 docker 이미지 만들기
... 16  17  18  19  20  21  22  23  24  25  26  27  28  [29]  30  ...