.Net ile Basit Web Server Yapımı

  • 18.33.2016
  • tayyipyetis
  • .Net Framework

How tu make Web ServerMerhaba arkadaşlar, bu makalede meraklıları için bir web server yazılımı örneği paylaşacağım. Web sunucusunun kısa bir tanımını yapmak gerekirse Web Server(ya da Web Sunucusu); Hosting ya da "barındırma" işlemini İnternet protokolü üzerinden sunan bir yazılımdır, Diğer bir ifade ile hosting, bir Web sitesinde yayınlanmak istenen sayfaların, resimlerin veya dokümanların İnternet kullanıcıları tarafından erişebileceği bir bilgisayarda tutulmasıdır. (Bakınız Vikipedi

Öncelikle şunu söyleyeyim ki  bu konuyu günlük hayatta pek kullanma gereği duymayabilirsiniz çünkü IIS ya da ApacheNgnixGlassFishNaviServer ve diğerleri gibi bir çok hazır web sunucusu bulunmaktadır ve bunlar geniş ölçekli web sitelerini yayınlamak için güçlü bir yapıya sahiptirler. Buna rağmen ben gerçek bir yazılımcının her konuda "Tamam da bu nasıl çalışıyor?" sorusunu sorması gerektiğine inanıyorum dolayısıyla bir web sunucusunun nasıl çalıştığına dair benim de yoğun araştırmalarım sonucu elde ettiğim bilgi ve örnekleri paylaşacağım. Github üzerinde aksakalli isimli kullanıcının açmış olduğu SimpleHTTPServer projesini bir sunucunun çalışma mantığını en basit şekilde anlattığı için burada paylaşmak için seçtim fakat bunların dışında sizler sourceforge, Githubcodehostingcodeplex üzerindeki örnekleri inceleyebilirsiniz.

Sunucumuzun yayın yapacağı index.html sayfası da aşağıda. bu sayfayı bin/debug klasörü altına atın. sunucunuzun çalışması için konsol uygulamanızı yönetici olarak çalıştırmalısınız visual studio üzerinden debug yapmaya çalışırsanız "Erişim engellendi (Access Denied)" hatası alırsınız. Build edip exe uygulamasını manuel olarak çalıştırın uygulama açık olduğu sürece http://localhost:8085/index.html adresinden demo sayfanıza ulaşabilirsiniz. port numarasını sisteminizde çalışan diğer uygulamalar ile (local IIS, Mail-FTP server vs.) çakışmadığı sürece istediğiniz gibi değiştirebilirsiniz. Yayın yapılacak dosyaların (html, js, css vs.) bulunduğu klasörü de değiştirebilirsiniz.

Örnek için; Visual Studio üzerinde(bu örnek v2012 Express üzerinde yapılmıştır) File > New Project > Visual C# > Windows > Console Application yolunu izleyerek bir konsol uygulaması açın. Projenize SimpleHTTPServer isimli bir class ekleyin. Class içeriği aşağıdaki gibidir. Genel çalışma mantığı; HttpListener Class'ı ile sisteme http protokolü üzerinden belirtilen port numarasına düşen istekleri dinliyor ve bir istek düştüğünde Thread başlatıp Process metoduna HttpListenerContext tipinde gelen isteğe dair tüm bilgileri barındırıyor bunu ASP.Net uygulamalarındaki HttpContext tipine benzetebilirsiniz. Cevap olarak byte türünden bir veri göndereceğiniz için HTML, Resim, Ses, Stream gibi geniş ölçekli işlemleri yapabilirsiniz. Ayrıca bir Windows Service yazıp bunu sunucunuzda 80 portunda çalıştırıp IIS kullanmadan yayın web yayını yapabilirsiniz fakat burada şöyle bir durum var ki aşağıdaki yapı ile sadece talep dinleyip byte olarak cevap veriyorsunuz dolayısıyla ASPX, ASP, PHP gibi sunucu taraflı dinamik sayfaları Render etmeniz mümkün değil fakat yapıyı daha da geliştirip örneğin CodePlex üzerindeki açık kaynak kodlu RazorEngine kütüphanesini kullanıp dinamik sayfalar oluşturabilirsiniz bu tamamen sizin hayal gücü ve becerinize kalmış.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
class SimpleHTTPServer {
 private readonly string[] _indexFiles = {
  "index.html",
  "index.htm",
  "default.html",
  "default.htm"
 };

 private static IDictionary < string, string > _mimeTypeMappings = new Dictionary < string, string > (StringComparer.InvariantCultureIgnoreCase) {#
  region extension to MIME type list {
   ".aspx",
   "application/octet-stream"
  }, #endregion
 };
 private Thread _serverThread;
 private string _rootDirectory;
 private HttpListener _listener;
 private int _port;

 public int Port {
  get {
   return _port;
  }
  private set {}
 }

 public SimpleHTTPServer(string path, int port) {
  this.Initialize(path, port);
 }

  this.Initialize(path, port);
 }
 public void Stop() {
  _serverThread.Abort();
  _listener.Stop();
 }
 private void Listen() {
  _listener = new HttpListener();
  _listener.Prefixes.Add("http://localhost:8085/");
  _listener.Start();

  while (true) {
   try {
    HttpListenerContext context = _listener.GetContext();
    Process(context);
   } catch (Exception ex) {

   }
  }
 }

 private void Process(HttpListenerContext context) {
  string filename = context.Request.Url.AbsolutePath;
  Console.WriteLine(filename);
  filename = filename.Substring(1);

  if (string.IsNullOrEmpty(filename)) {
   foreach(string indexFile in _indexFiles) {
    if (File.Exists(Path.Combine(_rootDirectory, indexFile))) {
     filename = indexFile;
     break;
    }
   }
  }

  filename = Path.Combine(_rootDirectory, filename);

  if (File.Exists(filename)) {
   try {
    Stream input = new FileStream(filename, FileMode.Open);

    //Adding permanent http response headers
    string mime;
    context.Response.ContentType = _mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out mime) ? mime : "application/octet-stream";
    context.Response.ContentLength64 = input.Length;
    context.Response.AddHeader("Date", DateTime.Now.ToString("r"));
    context.Response.AddHeader("Last-Modified", System.IO.File.GetLastWriteTime(filename).ToString("r"));

    byte[] buffer = new byte[1024 * 16];
    int nbytes;
    while ((nbytes = input.Read(buffer, 0, buffer.Length)) > 0)
     context.Response.OutputStream.Write(buffer, 0, nbytes);
    input.Close();

    context.Response.StatusCode = (int) HttpStatusCode.OK;
    context.Response.OutputStream.Flush();
   } catch (Exception ex) {
    context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
   }

  } else {
   context.Response.StatusCode = (int) HttpStatusCode.NotFound;
  }
  context.Response.OutputStream.Close();
  context.Response.OutputStream.Flush();
 }

 private void Initialize(string path, int port) {
  this._rootDirectory = path;
  this._port = port;
  _serverThread = new Thread(this.Listen);
  _serverThread.Start();
 }
}

Umarım faydalı olmuştur.

Mustafa Tayyip YETİŞ
Yazılım Geliştirme Uzmanı

Yorum Yap