[C#] 웹서버 개발하기


Development note/C#  2012. 10. 15. 18:27

안녕하세요. 명월입니다.


이번 포스팅에서는 C#으로 웹 서버를 개발하는 것에 대해 알아보도록 하겠습니다. 웹 서버는 이미 아파치와 IIS 등등 좋은 웹서버는 많이 있습니다. 그래서 따로 이렇게 개발 안해도 무료로 좋은 웹서버가 많습니다. 그래도 웹 서버를 연습으로 만들어 보면 웹서버가 어떻게 이루어 지는 지 알 수 있고, 웹 서버가 아니더라도 다른 서버 프로그램을 개발할 때 응용이 가능합니다.

 

웹 서버를 만들기 전에 웹 프로토콜을 알아야 하는데 예전에 소개한 포스팅이 있습니다.

바로가기 - 프로토콜이란

 

먼저 아파치 서버를 이용해서 웹 서버에 접속하는 테스트 클라이언트 프로그램을 만들겠습니다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace blog_20121015
{
  class Program
  {
    static void Main(string[] args)
    {
      new Program();
      Console.ReadLine();
    }
    public Program()
    {
      IPHostEntry host = Dns.Resolve("nowonbun.tistory.com");
      IPAddress IP = host.AddressList[0];
      Console.WriteLine(IP.ToString());

      IPEndPoint ipep = new IPEndPoint(IP, 80);
      Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      client.Connect(ipep);
      String Send = @"GET / HTTP/1.1\r\n
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n
Accept-Language: ko\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; InfoPath.2)\r\n
Accept-Encoding: gzip, deflate\r\n
Host: 127.0.0.1\r\n
Connection: Keep-Alive\r\n";
      client.Send(Encoding.Default.GetBytes(Send));
      client.Send(Encoding.Default.GetBytes("\r\n"));
      client.Send(Encoding.Default.GetBytes("\r\n"));
      byte[] _data = new byte[4096];
      client.Receive(_data);
      client.Close();
      Console.WriteLine(Encoding.Default.GetString(_data));
    }
  }
}

String Send 에 있는 부분에 HTTP 프로토콜 규약에 맞추어 Send를 보내는 부분 입니다.

위 결과 화면은 비록 400 Bad Request 라고 응답이 호출 되었지만 분명 tistory 에서는 프로토콜에 맞게 응신이 왔습니다. (Tistory 는 Apache 를 쓰는 군요. ㅎㅎㅎ)

 

여기까지 참고 소스 첨부하겠습니다.

첨부 파일 - blog_20121015.zip

 

여기 까지 됐으면 반대로 서버를 만들어 보도록 하겠습니다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace Test20121011
{
  class Program
  {
    static void Main(string[] args)
    {
      new Program();
    }
    public Program()
    {
      IPEndPoint ipep = new IPEndPoint(IPAddress.Any,9999);
      Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      server.Bind(ipep);
      server.Listen(20);
      while (true)
      {
        Socket client = server.Accept();
        try
        {
          String file = Recieve(client);
          FileInfo FI = new FileInfo(file);
          client.Send(Header(client, FI));
        }
        finally
        {
          client.Close();
        }
      }
    }
    public String Recieve(Socket client)
    {
      String _data_str = "";
      byte[] _data = new byte[4096];
      client.Receive(_data);
      Console.WriteLine(Encoding.Default.GetString(_data).Trim('\0'));
      String[] _buf = Encoding.Default.GetString(_data).Split("\r\n".ToCharArray());
      if (_buf[0].IndexOf("GET") != -1)
      {
        _data_str = _buf[0].Replace("GET ", "").Replace("HTTP/1.1", "").Trim();
      }
      else
      {
        _data_str = _buf[0].Replace("POST ", "").Replace("HTTP/1.1", "").Trim();
      }
      if (_data_str.Trim() == "/")
      {
        _data_str += "index.html";
      }
      int pos = _data_str.IndexOf("?");
      if (pos > 0)
      {
        _data_str = _data_str.Remove(pos);
      }
      return "web"+_data_str;
    }
    public byte[] Header(Socket client,FileInfo FI)
    {
      byte[] _data2 = new byte[FI.Length];
      try
      {
        FileStream FS = new FileStream(FI.FullName, FileMode.Open, FileAccess.Read);
        FS.Read(_data2, 0, _data2.Length);
        FS.Close();

        String _buf = "HTTP/1.0 200 ok\r\n";
        _buf += "Data: " + FI.CreationTime.ToString() + "\r\n";
        _buf += "server: Myung server\r\n";
        _buf += "Content-Length: " + _data2.Length.ToString() + "\r\n";
        _buf += "content-type:text/html\r\n";
        _buf += "\r\n";
        client.Send(Encoding.Default.GetBytes(_buf));
      }
      catch
      {
        String _buf = "HTTP/1.0 100 BedRequest ok\r\n";
        _buf += "server: Myung server\r\n";
        _buf += "content-type:text/html\r\n";
        _buf += "\r\n";
        client.Send(Encoding.Default.GetBytes(_buf));
        _data2 = Encoding.Default.GetBytes("Bed Request");
      }
      return _data2;
    }
  }
}

위 소스에서 보면 요청이 오면 index.html 파일을 전송하는 것으로 만들었습니다.

그러면 index.html 를 만들어 보도록하겠습니다.

실제 웹서버처럼 이미지도 넣어보고 marquee 태그도 넣어보고 js도 넣어 보았습니다.

그럼 서버를 올려보도록 하겠습니다.

실제 서버처럼 작동을 합니다. 물론 서버스크립트를 붙히지 않아 html 밖에 되지는 않겠지만 이 정도면 기본적인 웹서버 기능은 작동 하겠습니다.

 

( 사실 프로토콜의 개념을 함께 설명하려고 했으나 너무 코드위주의 설명이 되어버렸습니다. 그러나 한번 따라서 코딩해보면 프로토콜 개념이 한번에 잡히니 한번 따라 코딩해 보시길 추천합니다.)

 

참조 파일 : Test20121011.zip