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

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

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

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

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

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

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

Для создания веб-сервера воспользуемся классом HttpListener из пространства имён System.Net
C#:
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 адрес: . А также создаёт динамическую страницу, которая содержит форму с текстовым полем и кнопкой типа Submit для отправки клиенту.

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

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

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

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

29844


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

29845


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

29846


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

29847


29848


Порт в строке uri является необязательным, если он не указывается, то (по умолчанию) будет использоваться порт 80.
C#:
//клиент будет обращаться к данному адресу
string uri = @"http://192.168.10.1/say";
Если указывается порт, то ip адрес или имя хоста (в строке uri) можно не указывать, а заменить его знаком плюс (+).
C#:
//сервер принимает все запросы на порт 8080
string uri = @"http://+:8080/";
Теперь на клиенте достаточно ввести только имя или ip адрес сервера и номер порта.
Код:
http://192.168.10.1:8080
Как вернуть значение клиенту?

1. Создадим поле name типа string, в котором будет храниться возвращаемое пользователю значение.
C#:
bool flag = true;
string name;
2. В методе ShowRequestData вместо либо после вызова метода MessageBox.Show присвоим переменной name значение, которое было передано клиентом.
C#:
MessageBox.Show("Ваше имя: " + text);
name = text;
3. В методе StartServer добавим возможность возврата полученного значения.
C#:
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);
29849


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

Сергей Попов

Кодебай
30.12.2015
4 727
6 723
BIT
447
САНЯ
15.01.2016 в 06:50
Админ привет)))) в общем хотя добавил «System.Web» Ошибка 1 Имя типа или пространства имен «HttpUtility» отсутствует в пространстве имен «System.Web»
(пропущена ссылка на сборку?) C:UsersпапаAppDataLocalTemporary ProjectsWindowsFormsApplication1Form1.cs 107 39 WindowsFormsApplication1

ADMIN
15.01.2016 в 18:29
Привет. В свойствах проекта есть пункт «Target framework» измени .Net Framework 4 Client Profile на просто .Net Framework 4

Саму сборку System.Web нужно добавить в Refferences из папки:
Код:
C:program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.0System.Web.dll
САНЯ
17.01.2016 в 00:51
все ошибка ушла, но теперь при нажатии кнопки, ошибка на server.start Неверный формат сетевого имени, блин что не так))) я уже тебя новерно задолбал))) сорри в общем)

ADMIN
17.01.2016 в 18:39
Исходник полностью рабочий.

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

САНЯ
20.01.2016 в 08:46
попробывал использовать IPv4 192хххх работает, но с мобильного что не то, в хроме прогружается но нету текстового поля и тд, со стандартного браузера ваще не грузит

ADMIN
20.01.2016 в 17:45
Форма зависает потому что работа ведется в синхронном режиме, вот здесь происходит блокировка:
Код:
HttpListenerContext context = server.GetContext();
Нужно делать асинхронный сервер, тогда и кнопочки будут нажиматься.
Просто задача была показать на примере, как можно решить твою задачу.

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

Например:
Код:
//с телефона пингуем сервер
ping 192.168.10.1
//обратный пинг с сервера на телефон
ping 192.168.10.10
Если оба видят друг друга, то тогда может быть firewall блокирует порт или роутер не работает маршрутизация, или проброс порта нужно сделать, причин много.

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

САНЯ
22.01.2016 в 22:33
админ сорри все разобрался, работает то что нужно, ты крут!!!!!!! спасибо

САНЯ
24.01.2016 в 11:59
)) а такой вопрос как можно получить ответь в браузер, так сказать в другое текстовое поле?

САНЯ
25.01.2016 в 07:28
и если возможно картинку, типо видео трансляции с пк на браузер?

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

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

САНЯ
27.01.2016 в 11:59
ну вот смотри, я отправляю что то в браузере, выпадает сообщение, а можно получить это обратно в браузер только в другую строку, ну к примеру, я отправляю «статус батареи» и он в ответ присылает процент заряда в другую строку.
и можно ли сделать так же видео трансляцию с пк в браузер?

ADMIN
28.01.2016 в 10:54
«Видео трансляцию с пк в браузер» — сделать можно, тем более, что исходников и статей на эту тему полно в инете. И вернуть значение в ответ можно, ведь сервер отправляет страницу клиенту.

САНЯ
29.01.2016 в 10:08
хм, чтоб получить текст обратно, нужно сделать другую строку.

делаю так, просто добавляю
Код:
string responseString = @"<b>Name: </b>
добавил, в итоге нет ничего;

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

ADMIN
30.01.2016 в 01:24
Добавил пример решения в конце статьи.

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

ADMIN
31.01.2016 в 22:13
«добавляю выдает ошибку» — я гадать на кофейной гуще не умею, что именно за ошибка и где возникает exception?

САНЯ
02.02.2016 в 10:27
посмотри как добавил в код, правильно?
Код:
string responseString = @"<b>Name: </b>";
string htmlpage = @"<b>Name: {0}</b>";
// Ошибка - в этой области видимости уже определена
// локальная переменная с именем "responseString"
string responseString = string.Format(htmlpage, name);
ADMIN
03.02.2016 в 06:41
Нужно было не создавать ещё одну переменную, а просто переименовать переменную responseString на htmlpage. {0} — место подстановки значения переменной name.

САНЯ
03.02.2016 в 22:21
Админ привет, делаю так чтоб получить заряд бука(%), но в сообщении возвращается 0,90 ну т.е 90%, а в браузере иероглифы)) как правильно сделать?
Код:
if (text == "статус")
{
string b = SystemInformation.PowerStatus.BatteryLifePercent.ToString();
text = b.ToString();
MessageBox.Show(text.ToString());
}
САНЯ
05.02.2016 в 09:58
Русский текст так же, отображается иероглифами

САНЯ
06.02.2016 в 03:25
И если сделать асинхронный сервер, что тося, в его работе?
просто нужно получать доступ к форме, можешь переделать?

ADMIN
07.02.2016 в 08:02
В исходнике добавил, как решить проблему с кодировкой.

ADMIN
08.02.2016 в 09:52
«И если сделать асинхронный сервер, что тося, в его работе? просто нужно получать доступ к форме, можешь переделать?»

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

GREEN16
08.02.2016 в 15:33
Добрый вечер! У меня ошибка при server.Start
Необработанное исключение типа «System.Net.HttpListenerException» в System.dll
Дополнительные сведения: Отказано в доступе
Вроде всё сделал правильно, в чём может быть проблема?

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

ИВАН
11.02.2016 в 11:04
в начале статьи бы написал 1-2 абзаца поподробнее что за веб-сервер, зачем он и как использовать

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

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

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

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

ADMIN
13.02.2016 в 21:03
У меня так же. Через localhost работает, а через 192.ххх -нет…

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

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

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

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

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

Соединение между пк (команда ping)
Запущен ли сервер, и на каком порту он ожидает соединения (команда netstat на сервере)
Файрвол (возможно включен)
Uri, который использует клиент для подключения к серверу
АННА
17.02.2016 в 03:00
Когда я хочу вернуть значение пользователю и в коде пишу

... <b>Name: {0}</b>...
то в браузере на странице так и отображается

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

АННА
18.02.2016 в 06:01
Всё выяснила!

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

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

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

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

Сергей Попов

Кодебай
30.12.2015
4 727
6 723
BIT
447
Да я видел, просто давно хотел спросить почему вы переносите материал ( заведомо очень старый ) не лучше ли чтоб он канул в лепту?
Ознакомьтесь пожалуйста с SEO. После чего напишите, можно ли удалить 700 статей, которые мы планируем перенести с блога на форум.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!