c# Создание веб-сервера с помощью класса HttpListener

Как создать веб-сервер с помощью класса HttpListener?

В этой небольшой статье рассмотрим на простом примере, как создать веб-сервер с помощью языка c#, который будет работать в синхронном режиме.

Дано: два компьютера: «A» (192.168.10.10) и «Б» (192.168.10.1).

Компьютер “A” (клиент) – отправляет запросы веб-серверу с помощью веб-браузера (хром, опера и так далее).

Компьютер “Б” — это веб-сервер, который принимает и обрабатывает входящие запросы, отправленные методами: GET и POST, а так же динамически создаёт html страницу для отправки клиенту в качестве ответа.

Создание веб-сервера

Для начала создадим новый проект типа Windows Forms Application, после чего добавим на форму элемент управления Button (кнопку).

Для создания веб-сервера воспользуемся классом HttpListener из пространства имён System.Net

using System.Net; //добавить
public partial class Form1 : Form
{
HttpListener server;
bool flag = true;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//ресурс, который будет запрашивать пользователь
string uri = @"http://192.168.10.1:8080/say/";
StartServer(uri);
}
private void StartServer(string prefix)
{
server = new HttpListener();
// текущая ос не поддерживается
if (!HttpListener.IsSupported) return;
//добавление префикса (say/)
//обязательно в конце должна быть косая черта
if (string.IsNullOrEmpty(prefix))
throw new ArgumentException("prefix");
server.Prefixes.Add(prefix);
//запускаем север
server.Start();
this.Text = "Сервер запущен!";
//сервер запущен? Тогда слушаем входящие соединения
while (server.IsListening)
{
//ожидаем входящие запросы
HttpListenerContext context = server.GetContext();
//получаем входящий запрос
HttpListenerRequest request = context.Request;
//обрабатываем POST запрос
//запрос получен методом POST (пришли данные формы)
if (request.HttpMethod == "POST")
{
//показать, что пришло от клиента
ShowRequestData(request);
//завершаем работу сервера
if (!flag) return;
}
//формируем ответ сервера:
//динамически создаём страницу
string responseString = @"<!DOCTYPE HTML>
<html><head></head><body>
<form method=""post"" action=""say"">
<p><b>Name: </b><br>
<input type=""text"" name=""myname"" size=""40""></p>
<p><input type=""submit"" value=""send""></p>
</form></body></html>";
//отправка данных клиенту
HttpListenerResponse response = context.Response;
response.ContentType = "text/html; charset=UTF-8";
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
using (Stream output = response.OutputStream)
{
output.Write(buffer, 0, buffer.Length);
}
}
}
private void ShowRequestData(HttpListenerRequest request)
{
//есть данные от клиента?
if (!request.HasEntityBody) return;
//смотрим, что пришло
using (Stream body = request.InputStream)
{
using (StreamReader reader = new StreamReader(body))
{
string text = reader.ReadToEnd();
//оставляем только имя
text = text.Remove(0, 7);
//преобразуем %CC%E0%EA%F1 -> Макс
text = System.Web.HttpUtility.UrlDecode(text, Encoding.UTF8);
//выводим имя
MessageBox.Show("Ваше имя: " + text);
flag = true;
//останавливаем сервер
if (text == "stop")
{
server.Stop();
this.Text = "Сервер остановлен!";
flag = false;
}
}
}
}
}
}

Метод StartServer &#8212; запускает сервер, принимает входящие запросы, отправленные методами: GET или POST на uri адрес: http://192.168.10.1:8080/say. А также создаёт динамическую страницу, которая содержит форму с текстовым полем и кнопкой типа Submit для отправки клиенту.

Для вызова метода Start требуются права администратора (запустить Visual Studio от имени Администратора), иначе возникает ошибка &#171;Отказано в доступе”.

Метод ShowRequestData &#8212; обрабатывает http запросы, отправленные методом POST, и выводит введённое имя. Если клиент отправляет слово stop, то веб-сервер приостанавливает свою работу. Если вместо метода Stop вызвать метод Close, то сервер полностью завершит свою работу.

Запуск сервера

1. Запускаем веб-сервер, нажав на кнопку &#171;Запустить&#187;.

кнопка

2. На клиенте открывает любой доступный веб-браузер, и в адресной строке вводим адрес нужного нам ресурса, в результате появиться форма. Вводим имя и нажимаем на кнопку.

веб-браузер

3. На сервере появляется сообщение, которое содержит введенное имя.

messagebox

4. Для остановки сервера отправляем слово stop (можно заменить любым другим).

текстовое поле

форма

Порт в строке uri является необязательным, если он не указывается, то (по умолчанию) будет использоваться порт 80.

//клиент будет обращаться к данному адресу
string uri = @"http://192.168.10.1/say";

Если указывается порт, то ip адрес или имя хоста (в строке uri) можно не указывать, а заменить его знаком плюс (+).

//сервер принимает все запросы на порт 8080
string uri = @"http://+:8080/";

Теперь на клиенте достаточно ввести только имя или ip адрес сервера и номер порта.

http://192.168.10.1:8080

Как вернуть значение клиенту?

1. Создадим поле name типа string, в котором будет храниться возвращаемое пользователю значение.

bool flag = true;
string name;

2. В методе ShowRequestData вместо либо после вызова метода MessageBox.Show присвоим переменной name значение, которое было передано клиентом.

MessageBox.Show("Ваше имя: " + text);
name = text;

3. В методе StartServer добавим возможность возврата полученного значения.

string htmlpage = @"<!DOCTYPE HTML>
<html><head></head><body>
<form method=""post"" action=""say"">
<p><b>Name: {0}</b><br>
<input type=""text"" name=""myname"" size=""40""></p>
<p><input type=""submit"" value=""send""></p>
</form></body></html>";
string responseString = string.Format(htmlpage, name);

поле формы

Читайте также:

38 комментариев

  1. саня says:

    Админ привет)))) в общем хотя добавил &#171;System.Web&#187;
    Ошибка 1 Имя типа или пространства имен &#171;HttpUtility&#187; отсутствует в пространстве имен &#171;System.Web&#187; (пропущена ссылка на сборку?) C:UsersпапаAppDataLocalTemporary ProjectsWindowsFormsApplication1Form1.cs 107 39 WindowsFormsApplication1

  2. Привет. В свойствах проекта есть пункт &#171;Target framework&#187; измени .Net Framework 4 Client Profile на просто .Net Framework 4

    Саму сборку System.Web нужно добавить в Refferences из папки:

    C:Program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.0System.Web.dll
  3. саня says:

    все ошибка ушла, но теперь при нажатии кнопки, ошибка на server.start Неверный формат сетевого имени, блин что не так))) я уже тебя новерно задолбал))) сорри в общем)

  4. Исходник полностью рабочий.

  5. саня says:

    h_t_t_p://127.0.0.1:7777/say/ работает именно так и все отлично, но с телефона так работать не будет(бред но попробывал) в чем может быть проблема? почему не подходит 192,хххххххх, бук подключен к вайфаю может из за этого? и такой вопрос, после запуска форма зависает, не передвинуть не закрыть в общем ничего.

  6. саня says:

    попробывал использовать IPv4 192хххх работает, но с мобильного что не то, в хроме прогружается но нету текстового поля и тд, со стандартного браузера ваще не грузит

  7. Форма зависает потому что работа ведется в синхронном режиме, вот здесь происходит блокировка:

    HttpListenerContext context = server.GetContext();

    Нужно делать асинхронный сервер, тогда и кнопочки будут нажиматься.
    Просто задача была показать на примере, как можно решить твою задачу.

    Для начала нужно проверить видят ли друг друга сервер и телефон. Для этого нужно выполнить команду ping

    Например:

    //с телефона пингуем сервер
    ping 192.168.10.1
    //обратный пинг с сервера на телефон
    ping 192.168.10.10

    Если оба видят друг друга, то тогда может быть firewall блокирует порт или роутер не работает маршрутизация, или проброс порта нужно сделать, причин много.

  8. саня says:

    в общем пингуеться 192,168,10,1 основной флюз с телефона, с пк пингуетсья телефон 192,168,10,103, а вот сервер с телефона 192,168,10,102(IPv4) не пингуеться

  9. саня says:

    админ сорри все разобрался, работает то что нужно, ты крут!!!!!!! спасибо

  10. саня says:

    )) а такой вопрос как можно получить ответь в браузер, так сказать в другое текстовое поле?

  11. саня says:

    и если возможно картинку, типо видео трансляции с пк на браузер?

  12. много может быть способов: ajax, вернуть форму со значением, DOM и так далее.

    &#171;и если возможно картинку, типо видео трансляции с пк на браузер?&#187; &#8212; Что?

  13. саня says:

    ну вот смотри, я отправляю что то в браузере, выпадает сообщение, а можно получить это обратно в браузер только в другую строку, ну к примеру, я отправляю &#171;статус батареи&#187; и он в ответ присылает процент заряда в другую строку.
    и можно ли сделать так же видео трансляцию с пк в браузер?

  14. &#171;Видео трансляцию с пк в браузер&#187; &#8212; сделать можно, тем более, что исходников и статей на эту тему полно в инете. И вернуть значение в ответ можно, ведь сервер отправляет страницу клиенту.

  15. саня says:

    хм, чтоб получить текст обратно, нужно сделать другую строку.

    делаю так, просто добавляю

    string responseString = @"<b>Name: </b>

    добавил, в итоге нет ничего;

    и подскажи где в коде делать отправку обратно в браузер, в эту строку?

  16. Добавил пример решения в конце статьи.

  17. саня says:

    походу руки у меня кривые) что то не могу сделать все правильно! может ты раскидаешь в самой статье? добавляю выдает ошибку! спасибо
    string responseString = string.Format(htmlpage, name);

  18. &#171;добавляю выдает ошибку&#187; &#8212; я гадать на кофейной гуще не умею, что именно за ошибка и где возникает exception?

  19. саня says:

    посмотри как добавил в код, правильно?

    string responseString = @"<b>Name: </b>";
    string htmlpage = @"<b>Name: {0}</b>";
    // Ошибка - в этой области видимости уже определена
    // локальная переменная с именем "responseString"
    string responseString = string.Format(htmlpage, name); 
  20. Нужно было не создавать ещё одну переменную, а просто переименовать переменную responseString на htmlpage. {0} &#8212; место подстановки значения переменной name.

  21. саня says:

    Админ привет, делаю так чтоб получить заряд бука(%), но в сообщении возвращается 0,90 ну т.е 90%, а в браузере иероглифы)) как правильно сделать?

    if (text == "статус")
    {
    string b = SystemInformation.PowerStatus.BatteryLifePercent.ToString();
    text = b.ToString();
    MessageBox.Show(text.ToString());
    }
  22. саня says:

    Русский текст так же, отображается иероглифами

  23. саня says:

    И если сделать асинхронный сервер, что то измениться, в его работе?
    просто нужно получать доступ к форме, можешь переделать?

  24. В исходнике добавил, как решить проблему с кодировкой.

  25. &#171;И если сделать асинхронный сервер, что то измениться, в его работе?
    просто нужно получать доступ к форме, можешь переделать?&#187;

    Переделывать никто ничего не будет &#8212; это не сайт заказов (для этого есть фриланс).
    Будет время добавлю статью, а в данный момент возможности сделать это &#8212; нет.
    Про работу с потоками можно погуглить инфы очень много, в том числе можно легко найти, как получить доступ к форме из другого потока.

  26. green16 says:

    Добрый вечер! У меня ошибка при server.Start
    Необработанное исключение типа &#171;System.Net.HttpListenerException&#187; в System.dll
    Дополнительные сведения: Отказано в доступе
    Вроде всё сделал правильно, в чём может быть проблема?

  27. Привет. В статье вроде всё написано: Для вызова метода Start требуются права администратора (запустить Visual Studio от имени Администратора), иначе возникает ошибка «Отказано в доступе”.

  28. Иван says:

    в начале статьи бы написал 1-2 абзаца поподробнее что за веб-сервер, зачем он и как использовать

  29. Я думаю, что в этом нет смысла, потому что эта статья изначальна была рассчитана на тех, кто уже знает, что такое веб-сервер.

  30. Максим says:

    &#171;саня
    19.08.2015 в 10:10
    все ошибка ушла, но теперь при нажатии кнопки, ошибка на server.start Неверный формат сетевого имени, блин что не так))) я уже тебя новерно задолбал))) сорри в общем)&#187;

    У меня так же. Через localhost работает, а через 192.ххх -нет&#8230;

    Запускаю с бука, а с телефона не открывает

  31. У меня так же. Через localhost работает, а через 192.ххх -нет…

    Указанный адрес 192.xxx заканчивается на символ / ?

    Добавьте код.

  32. Максим says:

    Код использовал из вашего примера(адрес свой IPv4). Если подключаюсь с телефона или пк, то страница долго грузится и в итоге так и не загружается

  33. Пример из данной статьи проверялся уже много раз, поэтому ошибка либо в коде, либо в сети.

    Как вариант нужно проверить:

        Соединение между пк (команда ping)
        Запущен ли сервер, и на каком порту он ожидает соединения (команда netstat на сервере)
        Файрвол (возможно включен)
        Uri, который использует клиент для подключения к серверу
  34. Анна says:

    Когда я хочу вернуть значение пользователю и в коде пишу

    ... <b>Name: {0}</b>...

    то в браузере на странице так и отображается

    Name: {0}

    а введенное значение не отображается. В чем может быть дело?

  35. Анна says:

    Всё выяснила!

  36. Возможно пропущена или добавлена лишняя кавычка(и) при создании строки с html кодом.

  37. Алексей says:

    Всё равно ругается, когда ввожу адрес 192.168.10.1:8080/say/, а например с 127.0.0.1:7777/say/ всё ок)
    И от имени администратора запускал)) От чего только не запускал, всё равно ошибка(

    Необработанное исключение типа &#171;System.ObjectDisposedException&#187; в System.dll
    Дополнительные сведения: Доступ к ликвидированному объекту невозможен.

  38. Для начала стоит поставить пару точек остановы и посмотреть в каком месте возникает исключение, тогда хотя бы станет понятно, почему объект уничтожен (ObjectDisposedException).

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*