(ASP.NET) ASP.NET (2008 год)

Этюды на ASP NET2. Наблюдаем за своим домом с работы.


Сейчас большинство новых вэб-камер выпускется с IP-интерфейсом, например камеры от Genius. Они имеют прошитый web-серверок и предоставляют пользователю изображение по iP-адресу, например при входе на адрес http://192.168.0.233 мы и увидим собственно изображение.

Но как же показать это изображение на своем сайте?

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


Итак, создадим проект нового сайта в Visual Studio 2008. Для начала добавим в него (в App_Code) вот такой новый класс - который будет выдергивать рисунки с нашей камеры:

00001: Imports Microsoft.VisualBasic
00002: 
00003: Public Class Class1
00004:     Public Shared Property MaxImageLength() As Integer
00005:         Get
00006:             Return _MaxImageLength
00007:         End Get
00008:         Set(ByVal value As Integer)
00009:             _MaxImageLength = value
00010:         End Set
00011:     End Property
00012:     Shared _MaxImageLength As Integer = 150000
00013: 
00014:     'считывает не более MaxImageLength байт без сообщений об ошибках - для пакетов (плюс добавлена аутентификация)
00015:     Public Shared Function GetImage(ByVal URL As String, ByVal BasicAU_Name As String, ByVal BasicAU_Pass As String) As Byte()
00016:         Try
00017:             'запрос по HTTP
00018:             Dim PageRequest As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(URL), System.Net.HttpWebRequest)
00019:             Dim NetCredential As New Net.NetworkCredential(BasicAU_Name, BasicAU_Pass)
00020:             PageRequest.Credentials = NetCredential
00021:             'Отправлен запрос
00022:             Dim PageResponse As System.Net.HttpWebResponse = PageRequest.GetResponse
00023:             'Получен ответ
00024:             Dim Reader As New System.IO.BinaryReader(PageResponse.GetResponseStream())
00025:             Dim GIF As Array = Reader.ReadBytes(_MaxImageLength)
00026:             Reader.Close()
00027:             'Загружено в память
00028:             Return GIF
00029:         Catch ex As Exception
00030:             Throw New Exception(ex.Message)
00031:         End Try
00032:     End Function
00033: 
00034:     'Считывает с сообщениями об ошибках - для отддельных считываний
00035:     Public Shared Function GetImage(ByVal URL As String) As Byte()
00036:         Try
00037:             'запрос по HTTP
00038:             Dim PageRequest As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(URL), System.Net.HttpWebRequest)
00039:             'Отправлен запрос
00040:             Dim PageResponse As System.Net.HttpWebResponse = PageRequest.GetResponse
00041:             'Получен ответ
00042:             Dim Reader As New System.IO.BinaryReader(PageResponse.GetResponseStream())
00043:             Dim GIF As Array = Reader.ReadBytes(_MaxImageLength)
00044:             Reader.Close()
00045:             'Загружено в память
00046:             Return GIF
00047:         Catch ex As Exception
00048:             Throw New Exception(ex.Message)
00049:         End Try
00050:     End Function
00051: 
00052: End Class

Как видите, это достаточно универсальный модуль с полиморфной функцией, которая позволит нам (при необходимости с аутенфикацией) дернуть с камеры рисункок. В режиме пакетной работы - как например для пауков - нам не нужны тут прерывания, но нужно ограничение по длине респонза - для борьбы с антипаучьими технологиями сайтов. Для нашего применения - эти усложнения нам не будут нужны.

Следующий компонент нашей мини-пирамидки - это хандлер, из которого собственно и будет вызываться наш класс. Итак, добавим в наш проект хандлер PROXY.ASHX:

00001: <%@ WebHandler Language="VB" Class="proxy" %>
00002: 
00003: Imports System
00004: Imports System.Web
00005: 
00006: Public Class proxy : Implements IHttpHandler
00007:     
00008:     Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
00009:         context.Response.ContentType = "image/bmp"
00010:         Try
00011:             If HttpContext.Current.Request("login") Is Nothing And HttpContext.Current.Request("pass") Is Nothing Then
00012:                 HttpContext.Current.Response.BinaryWrite(Class1.GetImage(HttpContext.Current.Request("Url")))
00013:             Else
00014:                 HttpContext.Current.Response.BinaryWrite(Class1.GetImage(HttpContext.Current.Request("Url"), HttpContext.Current.Request("login"), HttpContext.Current.Request("pass")))
00015:             End If
00016:         Catch ex As Exception
00017:             context.Response.ContentType = "text/plain"
00018:             context.Response.Write(ex.Message)
00019:         End Try
00020:     End Sub
00021:  
00022:     Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
00023:         Get
00024:             Return False
00025:         End Get
00026:     End Property
00027: 
00028: End Class

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

00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
00002: 
00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
00004: 
00005: <html xmlns="http://www.w3.org/1999/xhtml">
00006: <head runat="server">
00007:     <title>Web Proxy</title>
00008: </head>
00009: <body>
00010:     <form id="form1" runat="server">
00011:     <div>
00012:         <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
00013:             <asp:View ID="View1" runat="server">
00014:                     <asp:Label ID="Label1" runat="server" Text="URL рисунка (http://сервер/каталог/рисунок)"></asp:Label>
00015:                     <br />
00016:                     <asp:TextBox ID="TextBox1" runat="server" Width="700px"></asp:TextBox>
00017:                     <br />
00018:                     <asp:Label ID="Label2" runat="server" Text="Логин"></asp:Label>
00019:                     <br />
00020:                     <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
00021:                     <br />
00022:                     <asp:Label ID="Label3" runat="server" Text="Пароль"></asp:Label>
00023:                     <br />
00024:                     <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
00025:                     <br />
00026:                     (если оба поля оставлены пустыми - будет сделана попытка считать рисунок без аутентификации)
00027:                     <br />
00028:                     <br />
00029:                     <asp:Button ID="Button1" runat="server" Text="Считать" />
00030:             </asp:View>
00031:             <asp:View ID="View2" runat="server">
00032:                 <asp:Image ID="Image1" runat="server" />
00033:                 <br />
00034:                 <asp:Button ID="Button2" runat="server" Text="Повторить" />
00035:             </asp:View>
00036:         </asp:MultiView>  
00037:     
00038:     </div>
00039:     </form>
00040: </body>
00041: </html>

00001: 
00002: Partial Class _Default
00003:     Inherits System.Web.UI.Page
00004: 
00005:     Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
00006:         MultiView1.ActiveViewIndex = 1
00007:         Response.Redirect("proxy.ashx?url=" & TextBox1.Text & "&login=" & TextBox2.Text & "&pass=" & TextBox3.Text)
00008:     End Sub
00009: 
00010:     Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
00011:         MultiView1.ActiveViewIndex = 0
00012:     End Sub
00013: End Class


00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Index.aspx.vb" Inherits="Index" %>
00002: 
00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
00004: 
00005: <html xmlns="http://www.w3.org/1999/xhtml">
00006: <head runat="server">
00007:     <title>Web-Camera</title>
00008: </head>
00009: <body>
00010:     <form id="form1" runat="server">
00011:     <div>
00012:     
00013:     </div>
00014:     </form>
00015: </body>
00016: </html>

00001: 
00002: Partial Class Index
00003:     Inherits System.Web.UI.Page
00004: 
00005:     Protected Sub Index_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
00006:         Response.Redirect("proxy.ashx?url=http://192.168.0.233/jpg/image.jpg&login=webuser&pass=webpass")
00007:     End Sub
00008: End Class

В итоге этих простеньких манипуляций у нас должен получится вот такой крохотный сайтик:




И он должен работать! Вводя правильную аутентификацию - мы сможем увидеть на нем изображение с Web-камеры.


Осталось вытащить это изображение из локалки на внешний айпишник - и сделать периодическое обновление этого изображения.

Для этого на нашем внешнем сайте (на котором могут переключаться и десятки и сотни вот таких веб-камер) - добавляем вот такой код:

00101:     
00102: <img src="http://XXX.YYY.ZZZ.NNN:MMM/proxy.ashx?url=http://192.168.0.233/jpg/image.jpg&login=webuser&pass=webpass" id="Image1" width="800px" height="600px"  />
00103: <asp:Image ID="ImageButton1" runat="server" ImageUrl="~/video1.gif" />
00104: 
00105: 
00106: <script language="javascript" type="text/javascript">
00107: function timer_process()
00108: {
00109:     var Image1 = document.getElementById('Image1');
00110:     Image1.src='http://XXX.YYY.ZZZ.NNN:MMM/proxy.ashx?url=http://192.168.0.233/jpg/image.jpg&login=webuser&pass=webpass&i=' + (new Date()).getTime();
00111:     window.setTimeout("timer_process()", 500);
00112: 
00113: }
00114: 
00115: </script>

Это собственно единократная загрузка рисунка и Язва-скрип процедурка устаревания странички по таймауту.

Обратите внимание тут на пару моментов - XXX.YYY.ZZZ.NNN:MMM - это наш внешний айпишник и порт - где мы запустили наш сайт, созданный на предыдущем шаге. Или порт откуда мапируюся реквесты фаерволом на наш прокси-сайт, созданный выше. Кроме того, обратите внимание как тут я решил вопрос с кешированием рисунков в браузере - просто докрутил еще один параметр.


И чего тут не хватает? А не хватает последнего ключика головоломки - кода, запускающего процесс устаревания странички timer_process().

Для разнообразия внесем запускающий код в программный текст странички:

00001: 
00002: Partial Class video1
00003:     Inherits System.Web.UI.Page
00004: 
00005:     Protected Sub video1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
00006:         If Not IsPostBack Then
00007:             ClientScript.RegisterClientScriptBlock(Me.GetType, "StartTimer", "<script language='javascript' type='text/javascript'>" & vbCrLf & _
00008:                                        "window.setTimeout('timer_process()', 500);" & vbCrLf & _
00009:                                        "</script>")
00010:         End If
00011:     End Sub
00012: End Class

Вот теперь все сложилось. Причем даже так, что формируя параметры вызова PROXY.ASHX, мы можем с этой внешней странички нашего адреса видеть даже десятки или сотни камер - висящих у нас на внутренних адресах - в моем случае это для первой камеры 192.168.0.233.


Пример практического применения? Пожалуйста.

Ставите дома 10 камер (каждая на своем внутреннем айпишнике). И с работы входите по своему внешнему айпишнику на свой сайт - и наблюдаете с 10-ти позиций, чем там занимается дома ваша жена в ваше отсутствие. Для этого надо лишь пару простейших IP-камер, хабчик, и какой-нибудь нешумный barebone - в который и надо загрузить описанные тут проги. В реальности описанная здесь система видеонаблюдения может быть скомбинирована с электронным замком.



Comments ( )
Link to this page: //www.vb-net.com/asp2/41/index.htm
< THANKS ME>