First off we need a TCP Listener, this helpful object sits there and tells us when someone is connecting on a specified port, the actual transmitting of data is handled via another object known as the socket but we'll get to that shortly
Public Class WebServer
Dim mthdServer As Thread
Dim mwebSession As WebSession
Dim mtcpListener As TcpListener
Public Sub New()
Try
' Get the IP address of the machine
Dim strHostName As String = Dns.GetHostName()
Dim ipServer As IPAddress = Dns.GetHostEntry(strHostName).AddressList(0)
' Specify which Port we'll be using.
Dim strPort As String = "81"
' Open a tcp listener on the port we've specified
mtcpListener = New TcpListener(ipServer, Int32.Parse(strPort))
' Start it up
mtcpListener.Start()
' Some internal info, you could also log this to a file or the event log.
Console.WriteLine("Web server started at: " & ipServer.ToString() & ":" & strPort)
' Start up the worker thread and pass it our listening item
mwebSession = New WebSession(mtcpListener)
mthdServer = New Thread(New ThreadStart(AddressOf mwebSession.ProcessThread))
mthdServer.Start()
Catch ex As Exception
' Bomb
Console.WriteLine(ex.StackTrace.ToString())
End Try
End Sub
' Clean up
Protected Overrides Sub Finalize()
MyBase.Finalize()
' clean up the thread
mthdServer.Abort() : mthdServer = Nothing
mwebSession = Nothing
' Stop listening on the port
mtcpListener.Stop() : mtcpListener = Nothing
End Sub
End Class
You'll notice above that we have a second class known as the webServer this is the core of the service and handles the transmission of the file data and is basically the work horse.
Public Class WebSession
' Internal store for the listener and also the socket for data movement
Private mtcpListener As System.Net.Sockets.TcpListener
Private msktClient As System.Net.Sockets.Socket
' We're passed the listener so store that away.
Public Sub New(ByVal tcpListener As System.Net.Sockets.TcpListener)
Me.mtcpListener = tcpListener
End Sub
' Since we're a thread this is a starting point, we're just gonna sit in a loop
' get a request for a file and then return it
Public Sub ProcessThread()
While (True)
Try
' Wait for a connection from the outside
msktClient = mtcpListener.AcceptSocket()
' Get information on the client using the IPEndPoint
Dim ipepClientInfo As IPEndPoint = CType(msktClient.RemoteEndPoint, IPEndPoint)
' Start a new thread for the request then the loop can go to process additional
' requests
Dim mthdClient As New Thread(New ThreadStart(AddressOf ProcessRequest))
mthdClient.Start()
' Fault? oh dear, let's bomb the current thread, the client will just
' get a connection fault and they'll have to try again.
Catch ex As Exception
Console.WriteLine(ex.StackTrace.ToString())
If msktClient.Connected Then
msktClient.Close()
End If
End Try
End While
End Sub
' This is where we figure what file the client wants and then throw it back via a stream
Protected Sub ProcessRequest()
Dim recvBytes(1024) As Byte
Dim strHTMLReq As String = Nothing
Dim intBytes As Int32
Try
' Receive the request from the client, we'll need some buffer space to shove
' it into
intBytes = msktClient.Receive(recvBytes, 0, msktClient.Available, SocketFlags.None)
' Transfer the buffer to a readable format
strHTMLReq = Encoding.ASCII.GetString(recvBytes, 0, intBytes)
' Could log this but I'm just using it to display what the request is
Console.WriteLine("HTTP Request: ")
Console.WriteLine(strHTMLReq)
' Get the path of to where our files are stored and the default page name
Dim strDefaultPage As String = "index.html"
Dim strPath As String = Directory.GetCurrentDirectory() & "\WWWRoot\"
' Some buffers we'll be using
Dim strArray() As String
Dim strRequest As String
' Chop up the request so it's eaier to Interpret
strArray = strHTMLReq.Trim.Split(" ")
' Determine the HTTP method, we only use GET, in here we use our
' HTMLResponse function which is where the data is streamed
If strArray(0).Trim().ToUpper.Equals("GET") Then
strRequest = strArray(1).Trim
' Do we have a file name?
If (strRequest.StartsWith("/")) Then
strRequest = strRequest.Substring(1)
End If
' No file Name then default page.
If (strRequest.EndsWith("/") Or strRequest.Equals("")) Then
strRequest = strRequest & strDefaultPage
End If
' Send the data
strRequest = strPath & strRequest
HTMLResponse(strRequest)
Else ' Not GET method, we'll go away passing back the errorpage.
strRequest = strPath & "Error\" & "400.html"
HTMLResponse(strRequest)
End If
' Fault? Just kill the connection
Catch ex As Exception
Console.WriteLine(ex.StackTrace.ToString())
If msktClient.Connected Then
msktClient.Close()
End If
End Try
End Sub
' This procedure will send back the file specified in a stream back to the client.
Private Sub HTMLResponse(ByVal httpRequest As String)
Try
' Open the file we've been given, we'll use the streamreader to pull everything
' into a string for easy transport.
Dim strData As StreamReader = New StreamReader(httpRequest)
Dim strBuff As String = strData.ReadToEnd()
strData.Close() : strData = Nothing
' Push the string into a byte array
Dim respByte() As Byte = Encoding.ASCII.GetBytes(strBuff)
' Set HTML Header, this is taken from the W3S consortium site, only thing
' you need to take note of is the GetContentType function used to pass
' back what type of document we're returning.
Dim htmlHeader As String = _
"HTTP/1.0 200 OK" & ControlChars.CrLf & _
"Server: Stews Webserver 1.0" & ControlChars.CrLf & _
"Content-Length: " & respByte.Length & ControlChars.CrLf & _
"Content-Type: " & getContentType(httpRequest) & _
ControlChars.CrLf & ControlChars.CrLf
' Again encode the header to bytes.
Dim headerByte() As Byte = Encoding.ASCII.GetBytes(htmlHeader)
' Send HTML Header back to Web Browser via our socket
msktClient.Send(headerByte, 0, headerByte.Length, SocketFlags.None)
' Send Contents back to Web Browser via our socet
msktClient.Send(respByte, 0, respByte.Length, SocketFlags.None)
' Close HTTP Socket connection
msktClient.Shutdown(SocketShutdown.Both)
msktClient.Close()
' Error? Bomb
Catch ex As Exception
Debug.Print(ex.Message)
If msktClient.Connected Then
msktClient.Close()
End If
End Try
End Sub
' Determines the type of returned content.
Private Function GetContentType(ByVal httpRequest As String) As String
If (httpRequest.EndsWith("html")) Then
Return "text/html"
ElseIf (httpRequest.EndsWith("htm")) Then
Return "text/html"
ElseIf (httpRequest.EndsWith("txt")) Then
Return "text/plain"
ElseIf (httpRequest.EndsWith("xml")) Then
Return "text/xml"
ElseIf (httpRequest.EndsWith("gif")) Then
Return "image/gif"
ElseIf (httpRequest.EndsWith("jpg")) Then
Return "image/jpeg"
ElseIf (httpRequest.EndsWith("jpeg")) Then
Return "image/jpeg"
ElseIf (httpRequest.EndsWith("pdf")) Then
Return "application/pdf"
ElseIf (httpRequest.EndsWith("pdf")) Then
Return "application/pdf"
ElseIf (httpRequest.EndsWith("doc")) Then
Return "application/msword"
ElseIf (httpRequest.EndsWith("xls")) Then
Return "application/vnd.ms-excel"
ElseIf (httpRequest.EndsWith("ppt")) Then
Return "application/vnd.ms-powerpoint"
Else
Return "text/plain"
End If
End Function
End Class
And that's about it, as you can see it's all a lot more simpler than it used to be in C++ but that's the power of .NET for you. You can always make changes to the HTMLResponse proc if you want to implement your own type of data response.
And just before I go some additional information, we use the following imports
Imports System.Net Imports System.Net.Sockets Imports System.Threading Imports System.Text Imports System.IO
and to run the webserver tis easy.
Dim myWebServer As WebServer = New WebServer
I do not load images in the web = /
ReplyDelete