Source Code for Me (s-c.me)

Allows you to paste souce code to blogs! Adapted for Twitter! Here is Search Form in case you missed your code.
Tags: CSharp,Client,Server,FileStream,TcpListener,Thread,ParameterizedThreadStart, Created At: 7/8/2017 12:41:48 PMViews:

HTML view:
Copy Source | Copy HTML
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net.Sockets;
  5. using System.Net;
  6. using System.Threading;
  7. using System.Text.RegularExpressions;
  8. using System.IO;
  9. namespace HTTPServer
  10. {
  11.     // Класс-обработчик клиента
  12.     class Client
  13.     {
  14.         // Отправка страницы с ошибкой
  15.         private void SendError(TcpClient Client, int Code)
  16.         {
  17.             // Получаем строку вида "200 OK"
  18.             // HttpStatusCode хранит в себе все статус-коды HTTP/1.1
  19.             string CodeStr = Code.ToString() + " " + ((HttpStatusCode)Code).ToString();
  20.             // Код простой HTML-странички
  21.             string Html = "<html><body><h1>" + CodeStr + "</h1></body></html>";
  22.             // Необходимые заголовки: ответ сервера, тип и длина содержимого. После двух пустых строк - само содержимое
  23.             string Str = "HTTP/1.1 " + CodeStr + "\nContent-type: text/html\nContent-Length:" + Html.Length.ToString() + "\n\n" + Html;
  24.             // Приведем строку к виду массива байт
  25.             byte[] Buffer = Encoding.ASCII.GetBytes(Str);
  26.             // Отправим его клиенту
  27.             Client.GetStream().Write(Buffer,  0, Buffer.Length);
  28.             // Закроем соединение
  29.             Client.Close();
  30.         }
  31.         // Конструктор класса. Ему нужно передавать принятого клиента от TcpListener
  32.         public Client(TcpClient Client)
  33.         {
  34.             // Объявим строку, в которой будет хранится запрос клиента
  35.             string Request = "";
  36.             // Буфер для хранения принятых от клиента данных
  37.             byte[] Buffer = new byte[1024];
  38.             // Переменная для хранения количества байт, принятых от клиента
  39.             int Count;
  40.             // Читаем из потока клиента до тех пор, пока от него поступают данные
  41.             while ((Count = Client.GetStream().Read(Buffer,  0, Buffer.Length)) >  0)
  42.             {
  43.                 // Преобразуем эти данные в строку и добавим ее к переменной Request
  44.                 Request += Encoding.ASCII.GetString(Buffer,  0, Count);
  45.                 // Запрос должен обрываться последовательностью \r\n\r\n
  46.                 // Либо обрываем прием данных сами, если длина строки Request превышает 4 килобайта
  47.                 // Нам не нужно получать данные из POST-запроса (и т. п.), а обычный запрос
  48.                 // по идее не должен быть больше 4 килобайт
  49.                 if (Request.IndexOf("\r\n\r\n") >=  0 || Request.Length > 4096)
  50.                 {
  51.                     break;
  52.                 }
  53.             }
  54.             // Парсим строку запроса с использованием регулярных выражений
  55.             // При этом отсекаем все переменные GET-запроса
  56.             Match ReqMatch = Regex.Match(Request, @"^\w+\s+([^\s\?]+)[^\s]*\s+HTTP/.*|");
  57.             // Если запрос не удался
  58.             if (ReqMatch == Match.Empty)
  59.             {
  60.                 // Передаем клиенту ошибку 400 - неверный запрос
  61.                 SendError(Client, 400);
  62.                 return;
  63.             }
  64.             // Получаем строку запроса
  65.             string RequestUri = ReqMatch.Groups[1].Value;
  66.             // Приводим ее к изначальному виду, преобразуя экранированные символы
  67.             // Например, "%20" -> " "
  68.             RequestUri = Uri.UnescapeDataString(RequestUri);
  69.             // Если в строке содержится двоеточие, передадим ошибку 400
  70.             // Это нужно для защиты от URL типа http://example.com/../../file.txt
  71.             if (RequestUri.IndexOf("..") >=  0)
  72.             {
  73.                 SendError(Client, 400);
  74.                 return;
  75.             }
  76.             // Если строка запроса оканчивается на "/", то добавим к ней index.html
  77.             if (RequestUri.EndsWith("/"))
  78.             {
  79.                 RequestUri += "index.html";
  80.             }
  81.             string FilePath = "www/" + RequestUri;
  82.             // Если в папке www не существует данного файла, посылаем ошибку 404
  83.             if (!File.Exists(FilePath))
  84.             {
  85.                 SendError(Client, 404);
  86.                 return;
  87.             }
  88.             // Получаем расширение файла из строки запроса
  89.             string Extension = RequestUri.Substring(RequestUri.LastIndexOf('.'));
  90.             // Тип содержимого
  91.             string ContentType = "";
  92.             // Пытаемся определить тип содержимого по расширению файла
  93.             switch (Extension)
  94.             {
  95.                 case ".htm":
  96.                 case ".html":
  97.                     ContentType = "text/html";
  98.                     break;
  99.                 case ".css":
  100.                     ContentType = "text/stylesheet";
  101.                     break;
  102.                 case ".js":
  103.                     ContentType = "text/javascript";
  104.                     break;
  105.                 case ".jpg":
  106.                     ContentType = "image/jpeg";
  107.                     break;
  108.                 case ".jpeg":
  109.                 case ".png":
  110.                 case ".gif":
  111.                     ContentType = "image/" + Extension.Substring(1);
  112.                     break;
  113.                 default:
  114.                     if (Extension.Length > 1)
  115.                     {
  116.                         ContentType = "application/" + Extension.Substring(1);
  117.                     }
  118.                     else
  119.                     {
  120.                         ContentType = "application/unknown";
  121.                     }
  122.                     break;
  123.             }
  124.             // Открываем файл, страхуясь на случай ошибки
  125.             FileStream FS;
  126.             try
  127.             {
  128.                 FS = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
  129.             }
  130.             catch (Exception)
  131.             {
  132.                 // Если случилась ошибка, посылаем клиенту ошибку 500
  133.                 SendError(Client, 500);
  134.                 return;
  135.             }
  136.             // Посылаем заголовки
  137.             string Headers = "HTTP/1.1 200 OK\nContent-Type: " + ContentType + "\nContent-Length: " + FS.Length + "\n\n";
  138.             byte[] HeadersBuffer = Encoding.ASCII.GetBytes(Headers);
  139.             Client.GetStream().Write(HeadersBuffer,  0, HeadersBuffer.Length);
  140.             // Пока не достигнут конец файла
  141.             while (FS.Position < FS.Length)
  142.             {
  143.                 // Читаем данные из файла
  144.                 Count = FS.Read(Buffer,  0, Buffer.Length);
  145.                 // И передаем их клиенту
  146.                 Client.GetStream().Write(Buffer,  0, Count);
  147.             }
  148.             // Закроем файл и соединение
  149.             FS.Close();
  150.             Client.Close();
  151.         }
  152.     }
  153.     class Server
  154.     {
  155.         TcpListener Listener; // Объект, принимающий TCP-клиентов
  156.         // Запуск сервера
  157.         public Server(int Port)
  158.         {
  159.             Listener = new TcpListener(IPAddress.Any, Port); // Создаем "слушателя" для указанного порта
  160.             Listener.Start(); // Запускаем его
  161.             // В бесконечном цикле
  162.             while (true)
  163.             {
  164.                 // Принимаем нового клиента
  165.                 TcpClient Client = Listener.AcceptTcpClient();
  166.                 // Создаем поток
  167.                 Thread Thread = new Thread(new ParameterizedThreadStart(ClientThread));
  168.                 // И запускаем этот поток, передавая ему принятого клиента
  169.                 Thread.Start(Client);
  170.             }
  171.         }
  172.         static void ClientThread(Object StateInfo)
  173.         {
  174.             // Просто создаем новый экземпляр класса Client и передаем ему приведенный к классу TcpClient объект StateInfo
  175.             new Client((TcpClient)StateInfo);
  176.         }
  177.         // Остановка сервера
  178.         ~Server()
  179.         {
  180.             // Если "слушатель" был создан
  181.             if (Listener != null)
  182.             {
  183.                 // Остановим его
  184.                 Listener.Stop();
  185.             }
  186.         }
  187.         static void Main(string[] args)
  188.         {
  189.             // Создадим новый сервер на порту 80
  190.             new Server(80);
  191.         }
  192.     }
  193. }

Based on Manoli.Net's CodeFormatter. Made by Topbot (c) 2008-2017