get file in other computer?

Hostium

Member
Joined
Jan 23, 2009
Messages
21
Programming Experience
Beginner
Hello ,

I have an application that collects information and stores it into a HTML file. My goal is to use any web browser and type in my IP & port to access that HTML file from work.

I think I can get a TcpListener working in my application, I just don't know how to make it listen for a Http request, and when it gets the request which file to send ... does that make sense?
 
Last edited by a moderator:
It works! Yay!

Now I just need to get it to work when there are JPG's and a CSS file in the Root DIR. It's loading up the html instantly, it's stalling on the rest though, just keeps loading.
 
The sendHTMLResponse method of that sample server uses a StreamReader to get the bytes of file requested, the StreamReader can only read text files. If you change this part of code:
VB.NET:
' Get the file content of HTTP Request 
Dim streamReader As IO.StreamReader = New IO.StreamReader(httpRequest)
Dim strBuff As String = streamReader.ReadToEnd()
streamReader.Close()
streamReader = Nothing

' The content Length of HTTP Request
Dim respByte() As Byte = Encoding.ASCII.GetBytes(strBuff)
To this:
VB.NET:
Dim respByte() As Byte = My.Computer.FileSystem.ReadAllBytes(httpRequest)
Then the server will return the file bytes no matter which file.

To limit memory impact on server for larger files I will suggest you add a little more code to read the file in chunks that you write to stream. So instead of reading the whole file in one go to resbByte array open a FileInfo:
VB.NET:
Dim info As New IO.FileInfo(httpRequest)
supply the file size to content length header:
VB.NET:
"Content-Length: " & info.Length
Replace the clientSocket.Send(respByte...) call that sends all file bytes with this loop:
VB.NET:
Dim stream As IO.FileStream = info.OpenRead
Dim buffer(10000) As Byte
Dim read As Integer = -1
Do Until read = 0
    read = stream.Read(buffer, 0, buffer.Length)
    clientSocket.Send(buffer, 0, read, SocketFlags.None)
Loop
stream.Close()
 
I'm sometimes getting this error..

Connection Interrupted
The connection to the server was reset while the page was loading.
The network link was interrupted while negotiating a connection. Please try again.

Is there a fix in the code to correct that, or is that just simply a problem with my internet connection?
 
I only tested 5 requests that worked out fine. I noticed one possible problem, for each request it gets rootpath from GetCurrentDirectory, this is a dynamic function that can return different paths as the application in various situations can cause the current directory to change. Application.StartupPath or other paths that can not change during runtime will be safer. It does not look to be a current problem though. And not related to connection problems.

The most likely cause is that the code keeps a single clientSocket variable declared at class level to serve all requests. As you know a regular webpage may consist of many file elements (images, linked scripts, stylesheets etc) that is all requested individually approximately at the same time by the browser when user navigates to that page. If either of these is not completed the current code will replace the socket reference with the next request, causing all kinds of problems. Then imagine two or more browser clients accessing this server at the same time! It is an easy fix, move the declaration of clientSocket variable from class to the ProcessThread method and pass the socket reference as parameter to ProcessRequest and sendHTMLResponse methods. Do you know how to add a parameter to a method? For threading you can use ParameterizedThreadStart delegate instead of ThreadStart delegate.
 
That does make a lot of sense. I'm still very new to VB and programming in general, i'm not sure how to add a paramater to a method, i'll figure it out now that I know what the problem most likely is. :)
 
VB.NET:
Sub sendHTMLResponse(ByVal httpRequest As String)
httpRequest is here a parameter for sendHTMLResponse method, and it's type is String. You need to add a paramter to pass on the Socket reference.
 
I think i've done what you've asked, with errors no doubt.... although this code isn't showing up with any warnings or errors it's crashing my application when I request the HTML.

VB.NET:
        Private Sub HttpServer()
            Dim hostName As String = Dns.GetHostName()
            Dim serverIP As IPAddress = Dns.Resolve(hostName).AddressList(0)

            ' Web Server Port
            Dim Port As String = txtPort.Text

            Dim tcpListener As New TcpListener(serverIP, Int32.Parse(Port))

            tcpListener.Start()

            Console.WriteLine("Web server started at: " & serverIP.ToString() & ":" & Port)
            Me.tcpListener = tcpListener
            Dim serverThread As New Thread(New ParameterizedThreadStart(AddressOf ProcessThread))

            serverThread.Start()

        End Sub

       Public Sub ProcessThread(ByVal clientsocket As System.Net.Sockets.Socket)
            While (True)
                Try
                    clientSocket = tcpListener.AcceptSocket()

                    ' Socket Information
                    Dim clientInfo As IPEndPoint = CType(clientSocket.RemoteEndPoint, IPEndPoint)



                    ' Set Thread for each Web Browser Connection
                    Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf ProcessRequest))

                    clientThread.Start()

                Catch ex As Exception
                    Console.WriteLine(ex.StackTrace.ToString())
                    If clientSocket.Connected Then
                        clientSocket.Close()
                    End If

                End Try
            End While

        End Sub
        Protected Sub ProcessRequest(ByVal clientSocket As System.Net.Sockets.Socket)
            Dim recvBytes(1024) As Byte
            Dim htmlReq As String = Nothing
            Dim bytes As Int32
            Try
                ' Receive HTTP Request from Web Browser
                bytes = clientSocket.Receive(recvBytes, 0, clientSocket.Available, SocketFlags.None)
                htmlReq = Encoding.ASCII.GetString(recvBytes, 0, bytes)



                ' Set WWW Root Path
                Dim rootPath As String = Directory.GetCurrentDirectory() & "/Monitor/" & "/" & grpInfo.Text & "/"

                ' Set default page
                Dim defaultPage As String = grpInfo.Text & ".html"

                Dim strArray() As String
                Dim strRequest As String

                strArray = htmlReq.Trim.Split(" ")

                ' Determine the HTTP method (GET only)
                If strArray(0).Trim().ToUpper.Equals("GET") Then
                    strRequest = strArray(1).Trim

                    If (strRequest.StartsWith("/")) Then
                        strRequest = strRequest.Substring(1)
                    End If

                    If (strRequest.EndsWith("/") Or strRequest.Equals("")) Then
                        strRequest = strRequest & defaultPage
                    End If

                    strRequest = rootPath & strRequest

                    sendHTMLResponse(strRequest, clientSocket)

                Else ' Not HTTP GET method
                    strRequest = rootPath & "Error\" & "400.html"

                    sendHTMLResponse(strRequest, clientSocket)
                End If

            Catch ex As Exception


                If clientSocket.Connected Then
                    clientSocket.Close()
                End If
            End Try
        End Sub
        Private Sub sendHTMLResponse(ByVal httpRequest As String, ByVal clientSocket As System.Net.Sockets.Socket)
            Try
                ' Get the file content of HTTP Request 
                Dim streamReader As StreamReader = New StreamReader(httpRequest)
                Dim strBuff As String = streamReader.ReadToEnd()
                streamReader.Close()
                streamReader = Nothing

                ' The content Length of HTTP Request
                Dim info As New IO.FileInfo(httpRequest)
                Dim respByte() As Byte = My.Computer.FileSystem.ReadAllBytes(httpRequest)

                ' Set HTML Header
                Dim htmlHeader As String = _
                    "HTTP/1.0 200 OK" & ControlChars.CrLf & _
                    "Server: WebServer 1.0" & ControlChars.CrLf & _
                    "Content-Length: " & info.Length & _
                    "Content-Type: " & getContentType(httpRequest) & _
                    ControlChars.CrLf & ControlChars.CrLf

                ' The content Length of HTML Header
                Dim headerByte() As Byte = Encoding.ASCII.GetBytes(htmlHeader)



                ' Send HTML Header back to Web Browser
                clientSocket.Send(headerByte, 0, headerByte.Length, SocketFlags.None)

                ' Send HTML Content back to Web Browser
                Dim stream As IO.FileStream = info.OpenRead
                Dim buffer(200000) As Byte
                Dim read As Integer = -1
                Do Until read = 0
                    read = stream.Read(buffer, 0, buffer.Length)
                    clientSocket.Send(buffer, 0, read, SocketFlags.None)
                Loop
                stream.Close()

                ' Close HTTP Socket connection
                clientSocket.Shutdown(SocketShutdown.Both)
                clientSocket.Close()

            Catch ex As Exception

                If clientSocket.Connected Then
                    clientSocket.Close()
                End If
            End Try

        End Sub
 
That's good apart from two things. No need for a Socket parameter for ProcessThread method, you're not passing a socket to that method, nor any other parameters. It is in the ProcessThread method the socket reference first occur from the AcceptSocket call, can you see that? Problem number two is that you never pass the socket on, have a look in help ParameterizedThreadStart Delegate (System.Threading) - can you see in the code example how a parameter value is passed to the thread delegate?

Another thing I noticed in the code you just posted, you're using StreamReader in sendHTMLResponse method to read the requested file, why? I seem to recall you asked before about a problem with that code, and I replied suggesting you to REPLACE that code with one of two alternatives that would work. Since you have added both these alternatives (why??), I will suggest that you quickly remove the bad code. Then you choose to use only one of the two alternatives I provided. Remove the other from your code.
 
I fixed my code to only use one of your prior solutions, i'm not sure why the rest of the code was still there apart from I just forgot to remove it.. :/

I'm trying to follow instructions on that page but it's not working for me yet, I know i'm close. Do you know of anything else I can read that would give me a better understanding?

Thank you for being so patient..
 
I'm not trying to confuse you here, the level of expertise needed to complete this task is beginner. Now, the code I was referring to in previous post was this:
VB.NET:
Dim newThread As New Thread(AddressOf Work.DoWork)
newThread.Start(42)

'Sub DoWork(ByVal data As Object)
Can you see that the value 42 here is passed to the thread method? That is the same the ProcessThread method need to do to pass the Socket to ProcessRequest method.
 
Back
Top