Page 1 of 3 123 LastLast
Results 1 to 40 of 109

Thread: Trying to connect to second Laptop.

  1. #1

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Trying to connect to second Laptop.

    Hi,

    I'm trying to connect two Laptops via a simple TCP connection.
    As far as I can tell everything's there, the two local WiFi addresses are correct and swapped in each lappy, I've been using the same Port on both lappys but am now using a different one on each.

    The code compiles without error and runs. Start the app. on both computers, when they're both sat waiting, I click the Start on both (in turn), I get the message 'Waiting for connection' as I'd expect, on both but that's as far as it gets... Both computers 'lock up' until I turn them off externally. (Little brown 'Stop Debugging' button.)

    You'll see that I've 'Pre-loaded' the two LAN addresses into the two TextBoxes to save a little time and to avoid errors when I'm testing, if I delete or invalidate either of them I get the error message so I'm assuming they're being Parsed correctly otherwise.


    Code:
    Imports System
    Imports System.IO
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Text
    Imports Microsoft.VisualBasic
    
    Public Class Form1
        Public Fail As Boolean = True
        Public Host As String
        Public Other As IPAddress
    
    
        '       192.168.0.4     iKi
        '       192.168.0.2     MSI
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Button1.Text = "Send"
            Button2.Text = "EXIT"
            Label1.Text = "Sender: "
            Label2.Text = "Friend: "
            TextBox1.Text = "192.168.0.4"   '   iKi Lappy.
            TextBox2.Text = "192.168.0.2"   '   This lappy. (Host)
            TextBox3.Text = ""
        End Sub
    
        Private Sub Button1_Click() Handles Button1.Click
    
            Host = TextBox1.Text
            Try
                Dim this = IPAddress.Parse(TextBox1.Text) 'Test for IP Address
            Catch ex As Exception
                Errors()
                Exit Sub
            End Try
    
            Try
                Other = IPAddress.Parse(TextBox2.Text)
            Catch ex As Exception
                Errors()
                Exit Sub
            End Try
            Fail = False
            MyTcpListener.Main()
            Connect(Host, "Hello you...")
        End Sub
    
        Private Sub Button2_Click() Handles Button2.Click
            Me.Close()
        End Sub
    
        Shared Sub Connect(server As String, message As String)
            If Form1.Fail Then Exit Sub
            Try
                Dim port As Int32 = 1301
                Dim client As New TcpClient(server, port)
                Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(message)
                Dim stream As NetworkStream = client.GetStream()
    
                stream.Write(data, 0, data.Length)
                Form1.TextBox3.Text = String.Format("Sent: {0}", message)
                Form1.TextBox3.Refresh()
                data = New [Byte](256) {}
    
                Dim responseData As [String] = [String].Empty
                Dim bytes As Int32 = stream.Read(data, 0, data.Length)
    
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
                Form1.TextBox3.Text = String.Format("Received: {0}", responseData)
                Form1.TextBox3.Refresh()
                client.Close()
            Catch e As ArgumentNullException
                Form1.TextBox3.Text = String.Format("ArgumentNullException: {0}", e)
                Form1.TextBox3.Refresh()
            Catch e As SocketException
                Form1.TextBox3.Text = String.Format("SocketException: {0}", e)
                Form1.TextBox3.Refresh()
            End Try
            Form1.TextBox3.Text += vbCrLf & vbCrLf & "Sorry...  Something's wrong with Connect."
            Form1.TextBox3.Refresh()
            Console.Read()
        End Sub 'Connect
    
        Private Sub Errors()
            TextBox3.Text += vbCrLf & "Please enter IP address for Host and Friend"
            TextBox3.Text += vbCrLf & Space(28) & "then try again."
            TextBox3.Refresh()
        End Sub
    
    
    
        Class MyTcpListener
    
            Public Shared Sub Main()
    
                If Form1.Fail Then Exit Sub
                Dim server As TcpListener
                server = Nothing
                Try
                    Dim port As Int32 = 1300
                    Dim localAddr As IPAddress = Form1.Other
    
                    server = New TcpListener(localAddr, port)
                    server.Start()
    
                    Dim bytes(1024) As Byte
                    Dim data As String = Nothing
    
                    Form1.TextBox3.Text = "Waiting for a connection... "
                    Form1.TextBox3.Refresh()
    
                    While True
                        Dim client As TcpClient = server.AcceptTcpClient()
    
                        Form1.TextBox3.Text = "Connected !"
                        Form1.TextBox3.Refresh()
                        data = Nothing
    
                        Dim stream As NetworkStream = client.GetStream()
                        Dim i As Int32
    
                        i = stream.Read(bytes, 0, bytes.Length)
                        While (i <> 0)
                            data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
                            Form1.TextBox3.Text = String.Format("Received: {0}", data)
                            Form1.TextBox3.Text = String.Format("SocketException: {0}", data)
                            Form1.TextBox3.Refresh()
                            data = data.ToUpper()
    
                            Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
    
                            stream.Write(msg, 0, msg.Length)
                            Form1.TextBox3.Text = String.Format("Sent: {0}", data)
                            Form1.TextBox3.Refresh()
                            i = stream.Read(bytes, 0, bytes.Length)
    
                        End While
                        client.Close()
                    End While
                Catch e As SocketException
                    Form1.TextBox3.Text = String.Format("SocketException: {0}", e)
                    Form1.TextBox3.Refresh()
                Finally
                    server.Stop()
                End Try
                Form1.TextBox3.Text += vbCrLf & vbCrLf & "Sorry...  Something's wrong with Sender."
                Form1.TextBox3.Refresh()
    
                Console.Read()
            End Sub 'Main
    
        End Class 'MyTcpListener 
    
    
    End Class
    I can't see where I'm going wrong.



    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,988

    Re: Trying to connect to second Laptop.

    Well, if system A is listening on port X, when system B sends something to port Y....do you expect system A to see that? For that to work, system A would have to be waiting at port X....but also paying attention to EVERY other port on the system.
    My usual boring signature: Nothing

  3. #3
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Trying to connect to second Laptop.

    If you have both computers waiting for a connection, who is going to connect to them?
    You would normally have one waiting for a connection (i.e. the server) and another connecting to it (the client).
    If you want both computers to be both a server and a client then you will need two connections, so would normally run the listener on a background thread so it can wait for a connection while you can use the GUI thread to act as a client and make a connection to the server on the other machine.

    That way, you can start both listeners in background threads and they wait for a connection. Then you would start a connection on one of the machines, or both if you want, to the other. You don't usually use two TCP connections to connect two machines though.

  4. #4

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Thanks guys,

    I don't want to dump this project, but I'm totally lost...

    I've tried to get a system to run from what I can find on the web but obviously I've no idea what's going on...
    I've been trying different 'Solutions' for close on for a year now and I'm no wiser. Onetime I did get a response from a trial i.e. messages are sent and received but then I couldn't harness it to what I want to do, also it was UDP (whatever that means) which I understand isn't guaranteed to receive every message. (Package ?) In fact I made a little application to test how often a message was actually received, a message plus an incremented number, and was very displeased with how many messages were lost, absolutely useless for what I want to do.

    So... It's back to the drawing board and try again, I'll just keep looking for a solution till I stumble on something I can understand.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,988

    Re: Trying to connect to second Laptop.

    UDP is connectionless. It's like posting a letter: You can send it, but it may get lost along the way.

    I'm curious about your loss rate, though. I've used UDP for a few things, and have yet to see a lost packet. There are ways to get around lost packets, but they all come with a bit of pain. TCP would be the way to go if you want a guarantee. I don't have a good example of it, though.
    My usual boring signature: Nothing

  6. #6

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Thanks Shaggy Hiker, I can find lots of good examples... Sadly none of them seem to work !

    Here's an example:

    This is for VB.NET, how to make a TCP data sender, P2P, (like a chat program)

    First, you want a basic GUI for your program, for the purpose of this tutorial, it will be a basic chatting program, because it is the easiest way to show one of these.

    http://icap.me/i/MZR6pbXXU6.png
    '* The list view will be where the data comes into from the other client
    '* The message box will be the text/data you want to send
    '* The IP box will be the IP you are sending the message/data to

    Now onto the code
    You want to make a few imports, as follows:


    Imports System.Net
    Imports System.Net.Sockets
    Imports system.Threading

    Now you will want to make some things, in your class file but not under any subs


    Public ListeningPort As Int32 = 8912 'Main listening port, will listen to this port
    Public SendingPort As Int32 = 8913 'Main sending port, will send data on this port
    Public LocalAddress As IPAddress = IPAddress.Parse("127.0.0.1") 'Local host address
    Public client As TcpClient 'Will send & receive information
    Public _Listen As Thread 'Thread for listening loop (multithreading)
    Public Receiver As New TcpListener(LocalAddress, MainPort) 'Listens for data
    Public IncomingIP As String 'IP of the sender



    Now, under the Form1_Load function, put the following code:


    _Listen = New Thread(AddressOf ReadData) 'Declaring the new thread
    _Listen.IsBackground = True 'Frees program of thread errors
    _Listen.Start() 'Starts the thread


    Now, make a new sub, call it ReadData this sub will loop listen for any data that comes in on port 8912; as declared above. Here is the code to go into this sub.


    Dim Bytes(1024) As Byte 'Bytes of data
    Dim Data As String = Nothing 'Message from bytes of data

    'Starting the listening loop, to read any data that comes in.
    While True
    Client = Receiver.AcceptTcpClient() 'Will accept the connection
    Data = Nothing 'Just resetting data if it equals something

    Dim stream As NetworkStream = client.GetStream 'Stream of info, like File.IO stuff
    IncomingIP = client.Client.RemoteEndPoint.ToString 'Gets IP of sender

    Dim i As Int32 'Just an int to loop through things

    'Loop to receive the data
    i = stream.Read(Bytes, 0, Bytes.Length)
    While (i <> 0)
    'Converting from bytes into ASCII string
    Data = System.Text.Encoding.ASCII.GetString(Bytes, 0, i)
    i = stream.Read(Bytes, 0, Bytes.Length)
    Listview1.items.add(Data) 'adds the message received
    End While
    Client.Close()
    End While


    Your program will now be listening on port 8912 for data.

    Now, to send data.

    Sending is very easy, just a couple lines of code. This will obviously needed to be called by the "Send Button"


    client = New TcpClient(IPBox.Text, 8913)
    Dim Data As Byte() = System.Text.Encoding.ASCII.GetBytes(TextBox.Text)
    Dim Stream As NetworkStream = client.GetStream
    Stream.Write(Data, 0, Data.Length) 'Writing back to the stream
    client.Close()

    '* In the following code above
    '* IPBox.Text being the TextBox you have typed an IP into
    '* TextBox.Text being the TextBox that has the message you want to send



    You can obviously do a lot more than this, make small games, RPGs & such.
    * Note: You may need to port forward the sending & receiving ports, and the other person might have to as well. If you need help, don't understand, or are getting an error, just message me on TTG or skype @ XBLToothPik, I'll be happy to help.

    Examples of things this could be used for:
    Chat Program
    Small Game (RPG, or something else)
    A ton of other things
    (Now I can't find the original Google entry)

    This one seems to have a name change ( 'MainPort' isn't declared... I used 'ListeningPort' which is)
    I changed the IP address to my router's address.

    When I run it, it fails at
    Code:
    Dim Bytes(1024) As Byte 'Bytes of data 
    Dim Data As String = Nothing 'Message from bytes of data 
    
    'Starting the listening loop, to read any data that comes in. 
    While True 
    Client = Receiver.AcceptTcpClient() 'Will accept the connection
    It fails at this last line, with: -


    System.InvalidOperationException occurred
    HResult=0x80131509
    Message=Not listening. You must call the Start() method before calling this method.
    Source=System
    StackTrace:
    at System.Net.Sockets.TcpListener.AcceptTcpClient()
    at New_TCP_Trial.Form1.ReadData() in C:\Users\georg\Documents\Visual Studio 2017\Projects\New TCP Trial\New TCP Trial\Form1.vb:line 36
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    Getting too late now to try to sort it out...

    Here's what I made of the instructions:
    Code:
    
    
    
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Threading
    
    Public Class Form1
    
        Public ListeningPort As Int32 = 8912 'Main listening port, will listen to this port 
        Public SendingPort As Int32 = 8913 'Main sending port, will send data on this port 
        Public LocalAddress As IPAddress = IPAddress.Parse("192.168.0.2") 'Local host address 
        Public client As TcpClient 'Will send & receive information 
        Public _Listen As Thread 'Thread for listening loop (multithreading) 
        Public Receiver As New TcpListener(LocalAddress, ListeningPort) 'Listens for data 
        'Public Receiver As New TcpListener(LocalAddress, MainPort) 'Listens for data (original line)
        Public IncomingIP As String 'IP of the sender 
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Button1.Text = "Exit"
            Button2.Text = "Send"
            Label1.Text = "IP"
            _Listen = New Thread(AddressOf ReadData) 'Declaring the new thread 
            _Listen.IsBackground = True 'Frees program of thread errors 
            _Listen.Start() 'Starts the thread 
        End Sub
    
        Private Sub ReadData()
    
            Dim Bytes(1024) As Byte 'Bytes of data 
            Dim Data As String = Nothing 'Message from bytes of data 
    
            'Starting the listening loop, to read any data that comes in. 
            While True
                client = Receiver.AcceptTcpClient() 'Will accept the connection 
                Data = Nothing 'Just resetting data if it equals something 
    
                Dim stream As NetworkStream = client.GetStream 'Stream of info, like File.IO stuff 
                IncomingIP = client.Client.RemoteEndPoint.ToString 'Gets IP of sender 
    
                Dim i As Int32 'Just an int to loop through things 
    
                'Loop to receive the data 
                i = stream.Read(Bytes, 0, Bytes.Length)
                While (i <> 0)
                    'Converting from bytes into ASCII string 
                    Data = System.Text.Encoding.ASCII.GetString(Bytes, 0, i)
                    i = stream.Read(Bytes, 0, Bytes.Length)
                    ListView1.Items.Add(Data) 'adds the message received 
                End While
                client.Close()
            End While
    
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Me.Close()
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            client = New TcpClient(TextBox1.Text, 8913)
            Dim Data As Byte() = System.Text.Encoding.ASCII.GetBytes(TextBox2.Text)
            Dim Stream As NetworkStream = client.GetStream
            Stream.Write(Data, 0, Data.Length) 'Writing back to the stream 
            client.Close()
        End Sub
    End Class
    It seems that Sub Form1_Load 'Starts the thread... Doesn't !


    Poppa.

    (02.27)
    Along with the sunshine there has to be a little rain sometime.

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Trying to connect to second Laptop.

    You might like to follow the CodeBank link in my signature below and check out my Asynchronous TCP thread. It uses the asynchronous support built into the appropriate classes (TcpListener, NetworkStream) rather than using synchronous methods on dedicated threads. It will work as is and then you can modify it as needed.

  8. #8

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by jmcilhinney View Post
    You might like to follow the CodeBank link in my signature below and check out my Asynchronous TCP thread. It uses the asynchronous support built into the appropriate classes (TcpListener, NetworkStream) rather than using synchronous methods on dedicated threads. It will work as is and then you can modify it as needed.
    Thanks for the pointer Jmcilhinney, I thought I'd looked in there, not well enough obviously.

    The Asynchronous TCP thread is exactly what I've been looking for, I shall try to understand it and I will try to modify it for my own purpose.

    Your thread asks for feedback:
    Ok, so your last update to that thread was Oct 10th, 2010 and I'm using it in VS2017 so the first thing that happens is a 'One-way upgrade', which completes with a warning that there may be errors due to files being Read Only.

    So, Delete the whole project, remove the read only attributes from the unzipped files and try again. This time there are only 2 warnings, I've added a '!' at the start of the two relevant lines in the Migration Report below. I think they're only a repeat of the need for an update.

    Next, I'm curious to see how the program works so
    To test out the features you can simply open the project in VS and run it. The test projects for the client and server will both run and present you with two windows: one for the server and one for the client.
    in the SV I click debug 'Start':

    Before any form appears I get an error:
    A project with an Output Type of Class Library cannot be started directly.

    In order to debug this project, add an executable project to this solution which references the library project. Set the executable project as the startup project.
    In Solution Explorer I double click 'Wunnell.MessageClientTest' 'My Project' > Application.
    It says:
    Application Type: Windows Form Application
    Assembly Name: Wunnell.MessageClientTest
    Startup From: MainWindow. With an option for ClientWindow.
    In Solution Explorer I double click 'Wunnell.MessageServerTest' 'My Project' > Application.
    It says:
    Application Type: Windows Form Application
    Assembly Name: Wunnell.MessageServerTest
    Startup From: MainWindow. With no options.
    In Solution Explorer I double click 'Wunnell.Net.MessageClientServer' 'My Project' > Application.
    It says:
    Application Type: Class Library
    Assembly Name: Wunnell.Net.MessageClientServer
    Root namespace: Wunnell.Net
    Startup From: (None). With no options.
    I've failed to find where the problem may be so I'm back with the begging bowl, looking for help.


    Poppa.


    Migration Report - Message Client-Server
    Overview
    Project Path Errors Warnings Messages
    ! Solution Message Client-Server.sln 0 1 2
    Wunnell.MessageClientTest Wunnell.MessageClientTest\Wunnell.MessageClientTest.vbproj 0 0 16
    Wunnell.MessageServerTest Wunnell.MessageServerTest\Wunnell.MessageServerTest.vbproj 0 0 13
    Wunnell.Net.MessageClientServer Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj 0 0 18
    Solution and projects

    Solution
    Message
    ! Message Client-Server.sln: Visual Studio needs to make non-functional changes to this project in order to enable the project to open in released versions of Visual Studio newer than Visual Studio 2010 SP1 without impacting project behavior.
    Message Client-Server.sln: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Message Client-Server.sln
    Message Client-Server.sln: Solution migrated successfully
    Hide 2 additional messages

    Wunnell.MessageClientTest
    Message
    Wunnell.MessageClientTest\Wunnell.MessageClientTest.vbproj: Project file successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\Wunnell.MessageClientTest.vbproj
    Wunnell.MessageClientTest\ClientWindow.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\ClientWindow.Designer.vb
    Wunnell.MessageClientTest\ClientWindow.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\ClientWindow.vb
    Wunnell.MessageClientTest\MainWindow.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\MainWindow.vb
    Wunnell.MessageClientTest\MainWindow.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\MainWindow.Designer.vb
    Wunnell.MessageClientTest\My Project\AssemblyInfo.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\AssemblyInfo.vb
    Wunnell.MessageClientTest\My Project\Application.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Application.Designer.vb
    Wunnell.MessageClientTest\My Project\Resources.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Resources.Designer.vb
    Wunnell.MessageClientTest\My Project\Settings.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Settings.Designer.vb
    Wunnell.MessageClientTest\My Project\Application.myapp: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Application.myapp
    Wunnell.MessageClientTest\My Project\Settings.settings: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Settings.settings
    Wunnell.MessageClientTest\ClientWindow.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\ClientWindow.resx
    Wunnell.MessageClientTest\MainWindow.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\MainWindow.resx
    Wunnell.MessageClientTest\My Project\Resources.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageClientTest\My Project\Resources.resx
    Wunnell.MessageClientTest\Wunnell.MessageClientTest.vbproj: Project migrated successfully
    Wunnell.MessageClientTest\Wunnell.MessageClientTest.vbproj: Scan complete: Migration not required for project files.
    Hide 16 additional messages

    Wunnell.MessageServerTest
    Message
    Wunnell.MessageServerTest\Wunnell.MessageServerTest.vbproj: Project file successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\Wunnell.MessageServerTest.vbproj
    Wunnell.MessageServerTest\MainWindow.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\MainWindow.vb
    Wunnell.MessageServerTest\MainWindow.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\MainWindow.Designer.vb
    Wunnell.MessageServerTest\My Project\AssemblyInfo.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\AssemblyInfo.vb
    Wunnell.MessageServerTest\My Project\Application.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Application.Designer.vb
    Wunnell.MessageServerTest\My Project\Resources.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Resources.Designer.vb
    Wunnell.MessageServerTest\My Project\Settings.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Settings.Designer.vb
    Wunnell.MessageServerTest\My Project\Application.myapp: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Application.myapp
    Wunnell.MessageServerTest\My Project\Settings.settings: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Settings.settings
    Wunnell.MessageServerTest\MainWindow.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\MainWindow.resx
    Wunnell.MessageServerTest\My Project\Resources.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.MessageServerTest\My Project\Resources.resx
    Wunnell.MessageServerTest\Wunnell.MessageServerTest.vbproj: Project migrated successfully
    Wunnell.MessageServerTest\Wunnell.MessageServerTest.vbproj: Scan complete: Migration not required for project files.
    Hide 13 additional messages

    Wunnell.Net.MessageClientServer
    Message
    Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj: Project file successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj
    Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj.user: Project user file successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj.user
    Wunnell.Net.MessageClientServer\ConnectionEventArgs.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\ConnectionEventArgs.vb
    Wunnell.Net.MessageClientServer\Delegates.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\Delegates.vb
    Wunnell.Net.MessageClientServer\HostInfo.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\HostInfo.vb
    Wunnell.Net.MessageClientServer\MessageClient.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\MessageClient.vb
    Wunnell.Net.MessageClientServer\MessageClientServerBase.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\MessageClientServerBase.vb
    Wunnell.Net.MessageClientServer\MessageReceivedEventArgs.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\MessageReceivedEventArgs.vb
    Wunnell.Net.MessageClientServer\MessageServer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\MessageServer.vb
    Wunnell.Net.MessageClientServer\My Project\AssemblyInfo.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\AssemblyInfo.vb
    Wunnell.Net.MessageClientServer\My Project\Application.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Application.Designer.vb
    Wunnell.Net.MessageClientServer\My Project\Resources.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Resources.Designer.vb
    Wunnell.Net.MessageClientServer\My Project\Settings.Designer.vb: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Settings.Designer.vb
    Wunnell.Net.MessageClientServer\My Project\Application.myapp: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Application.myapp
    Wunnell.Net.MessageClientServer\My Project\Settings.settings: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Settings.settings
    Wunnell.Net.MessageClientServer\My Project\Resources.resx: File successfully backed up as C:\Users\georg\Documents\Visual Studio 2017\Projects\Message Client-Server\Backup\Wunnell.Net.MessageClientServer\My Project\Resources.resx
    Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj: Project migrated successfully
    Wunnell.Net.MessageClientServer\Wunnell.Net.MessageClientServer.vbproj: Scan complete: Migration not required for project files.
    Hide 18 additional messages
    Along with the sunshine there has to be a little rain sometime.

  9. #9
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Trying to connect to second Laptop.

    I'll look at uploading a new solution that's tested in VS 2017. As for running the projects, I would think that it would have been the case that I had specified multiple startup projects for the solution. Maybe that setting didn't survive your upgrade or maybe I stuffed up. Either way, it is probably selecting the current project as the startup project for the solution. If you right-click the solution in the Solution Explorer and select Set Startup Projects or the like, you can then specify each of the application projects to be run. Hit the Start button on the toolbar or press F5 again and you should be in business.

  10. #10
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    I think JMC's advice and tutorial are good, I wish I'd peeked at them before writing all of this. But I do think I have some reasonable things to say about the nuts and bolts behind it, so I'm posting anyway.

    There's an up-front complexity, and at the time I started writing this only one person had brought it up: If you're using networking, you need at least one background thread. In the initial code you posted, you're running a While True loop on your UI thread. It's possible it was working, but since you're stuck in that loop the UI thread can't update so there'd be no indication it's working. So if you aren't comfortable with working with one of .NET's four main asynchronous patterns, you won't get very far.

    Even so, there's always the chance that Windows Firewall or some other security software you have is getting in the way. For tutorial purposes, I usually start my troubleshooting by completely disabling Windows Firewall. I don't run other firewalls because 1) Microsoft's is good and 2) every third-party firewall I've used has at some point refused to allow a program I needed through. There are ways to tell Windows Firewall "this program should be allowed through", but this can be wonky when you're in the process of developing a program since it changes a little every time you build.

    Here's a rough crash course that won't be copy/paste friendly.

    For TCP, you are using a connection-based protocol. One of your computers will be "listening" ('the host'), the other will actually make the connection ("the client"). You can write programs that are both Hosts and Clients, but it's easier to think about them if you treat Host and Client like two different programs with similar code.

    The Host

    The Host has to choose an IP address and port on which to listen. This is more complex than just saying "localhost and a random number" on modern machines. I have an ethernet card, wifi, and VirtualBox installed on my machine. Thus, I have 6 network adapters and 6 different IP addresses. If I listen on "localhost", I've got to figure out which adapter that corresponds to and remember it for later. When you CAN, it's best to reach out and find the adapter you want and use its IP explicitly. But that's complex enough it never appears in tutorial code. I'm only discussing it as a thing to remember that can be a problem.

    So you create some class (typically TcpListener), tell it which IP and port it's going to listen to, then wait for a connection. I recommend using one of the Async methods that returns a task. My example code will use that. This lets you do the "listening" on a background thread and only come back to the UI thread when a connection has been made, if at all. If you use this method, when the task completes it will either throw an exception or give you a TcpClient that represents a connection to the Client computer. You'll typically call that TcpClient's GetStream() method to get the stream representing the data, and from there interacting with the network is like reading a file. What you do after that depends on your program.

    If it's something that does short data exchanges like an HTTP server, then you'll close the stream and Dispose the TcpClient, that's the end of your transaction with the remote Client. If it's something that maintains a connection like some chat clients, you'll leave the Stream open and do something to listen, probably calling a method like ReadAsync() so you don't tie a thread up waiting. "Be like an HTTP server" is easier, so most tutorials follow that logic.

    DO NOT make connections yourself on the same port you're listening. That's the listen port. When a Client machine connects to you, the TcpClient you get will be assigned a random port of its own. You can figure out which port that is, but in general you don't give a flip. What matters is remembering the port on which you listen.

    So the Host code in an imaginary GUI application might look like:

    Code:
    Dim listenEndpoint As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000)
    _listener = New TcpListener(listenEndpoint)
    _listener.Start() 
    
    Using clientConnection As TcpClient = Await _listener.AcceptTcpClientAsync()
        Using reader As New StreamReader(clientConnection.GetStream())
            Dim data As String = Await reader.ReadToEndAsync()
            txtMessages.Text = data
        End Using
    End Using
    The listener is configured and started. AcceptTcpClientAsync() is awaited, this lets the UI thread go do something else until a connection is made. When it does, the UI thread comes back here and clientConnection is a TcpClient. Its stream is read by a StreamReader (using Await and asynchronous calls again, just in case), then the text is placed in the window.

    The use of Await is important here, you need to be familiar with Task-Based Asynchronous Programming to use it. There are other async patterns, but TcpListener only supports this one. The important part: this code always comes back to the UI thread when its asynchronous calls finish.

    The Client
    The client doesn't listen. It has to know the IP of the Host machine and the port that it should connect to. Instead of TcpListener, you tend to make your own TcpClient for this job. You tell it which IP/port it should connect to, then call Connect().

    Once the connection succeeds, you also call GetStream(), only in this case you're writing. This is pretty boring, because it's just like file I/O. What you do after writing data depends, again, on what your program does. If you expect a response, you start reading, probably using an asynchronous method. If you don't expect a response, you close the connection.

    The client code usually looks like:

    Code:
    Dim serverEndpoint As New IPEndPoint(IPAddress.Parse("192.168.1.80"), 3000)
    
    Using client As New TcpClient(serverEndpoint)
        Await client.ConnectAsync()
        Using writer As New StreamWriter(client.GetStream())
            writer.WriteLine("Hello!")
        End Using
    End Using
    The code examples in this post represent one-way communication: the Host listens and reads, the Client connects and writes. It's a good bit messier to do two-way communication, because you have to be more careful about when the stream is closed. So I did the simplest thing. If the client expected a response, you might write it more like this:
    Code:
    Dim serverEndpoint As New IPEndPoint(IPAddress.Parse("192.168.1.80"), 3000)
    
    Using client As New TcpClient(serverEndpoint)
        Await client.ConnectAsync()
            Using clientStream As Stream = client.GetStream()
                Dim writer As New StreamWriter(clientStream)
                Await writer.WriteLineAsync("Hello!")
    
                Dim reader As New StreamReader(clientStream)
                Dim response As String = Await reader.ReadToEnd(clientStream)
                txtResponse.Text = response    
            End Using
        End Using
    End Using
    If alarm bells are ringing and you are saying I should close the reader and writer, good! You're paying attention. However, in this case, they're both wrapping the same stream. So it is sufficient for our purposes to close the Stream, and it has its own Using statement to guarantee that happens.

    If you didn't think about that, then get in the habit of thinking about it. Closing the Stream or the Client or the Listener tells Windows when you're done with a connection. If you fail to do so, you can end up leaving a socket open until Windows decides you aren't using it. Sometimes that takes more than 10 minutes. It's often easier to reboot than to wait. So every time you start reading or writing, ask yourself, "Should I Dispose these types when finished, and if not, why?"

    Any time you write networking code, you have to do a little bit of thinking about what role your code is playing and how it interacts with the other machine. There's a lot of trial and error involved, and any number of network problems can make it look like your code's not working when it's perfectly fine. It helps if, before you start on something complicated, you practice with a ton of very small-scale scenarios. If you can't implement the simple scenario from memory, you generally don't have a chance of getting the harder scenarios right.

    So get some tiny program working, then throw it away and write it again. Add a feature each time you have it working, but make sure you have a way to get back to "working" if you break it. If you spend a couple of weeks hammering at it, you'll probably have seen the bulk of the error cases worth handling.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  11. #11

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    I think JMC's advice and tutorial are good, I wish I'd peeked at them before writing all of this. But I do think I have some reasonable things to say about the nuts and bolts behind it, so I'm posting anyway.
    Thank you Sitten Spynne,

    I'm thankful you spent the time to explain all this, at last I have an insight into what's going on.
    I have made a copy of your explanation and it's sitting in my Snippets folder so that I can refer to it as and when I need it. (Not if, you might notice)


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  12. #12

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by jmcilhinney View Post
    It is probably selecting the current project as the startup project for the solution. If you right-click the solution in the Solution Explorer and select Set Startup Projects or the like, you can then specify each of the application projects to be run. Hit the Start button on the toolbar or press F5 again and you should be in business.
    Thanks,

    That's sorted that out, the app.s open in both laptops now, I've tried opening the client in both lappys and I've tried opening the client on one and the server on the other, I've tried opening the server on both... Can't get a connection on either machine.
    I've spent a lot of time trying to find where you obtain an IP address but haven't found it yet... It gets both computer names, and the port you specify... But no addresses.

    I click the 'Connect' button on the server, the computer waits for a short while then tells me
    The specified server could not be found. Would you like to try again?


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Trying to connect to second Laptop.

    I've been debating about writing a new simple example, but I can't really allocate the time so I'll provide a couple of projects that I use to capture a portion of a desktop on one machine and send the image to another machine using TCP.

    My first iteration of this was a quick VB6 program to capture a portion of the desktop periodically from the cockpit of a simulator and send it to a java program that a co-worker wrote that would show the "video" as part of a page for some live presentation that he was doing.
    In this case, my vb6 program was the client and would connect to the java program and send the data. It was written really quickly and after it was tested to show that it was working I decided to redo the capturing side in VB.net (VS 2005 version) as this was back when I was first transitioning to the .net environment and would be a simple but useful learning exercise (so there are some things like using the Val function that purist may not care for).

    I expanded the original program to allowing defining five different areas of the screen that can be captured. You select which area you want to transmit with radio buttons. Later, since this was originally written to talk to a server that someone wrote in Java, I decided to write my own receiver side in vb.net so that I would have an example of both sides of the TCP connection for myself.

    Looking at this version, it is obviously a recent test version (i.e. modfied within the last two years). There is a large label that displays a count incrementing based on the AutoCapture interval. I believe I added that when I was testing to see what would happen if you tried to capture faster than you could transmit, i.e. would the receiving side display of the count (assuming you were capturing a part of the screen that included the label) show a lag with the number it displayed falling behind the number displayed on the transmitting side. I made it large so that I could see it across the room and observe the number on both machines at the same time.
    That label and the code related to that counter is not needed and can be removed.

    Also, on the receiving side radio buttons were added to test sending a message the other direction over the TCP connection so that the area being captured and transmitted could be chosen from the receiving side. This was just an early test so the radio controls were not even renamed.

    The code has been reliable for me and has been running 24/7 for months in a lab where a user would like to see what is happening on a simulation machine from where he works on the far side of the space.

    The BlockCapture side is the client, and the BlockDisplay side is the server.
    If you want to test it quickly, you can run both projects on the same machine.
    On the BlockCapture form change the IP address to 127.0.0.1 (i.e. loopback address) and then press the Connect button. The label next to the Connect button should change to say "Connected" if the BlockDisplay program is running.
    If you press the "Snap Shot" button a screen capture of a portion of the screen should be transmitted using TCP and displayed on the BlockDisplay form.
    If you press the "Show Capture Area" button, the area of the screen being captured should be shown using a translucent rectangle. You can click and drag with the left mouse button on the rectangle to move the area being captured. If you click and drag on the rectangle with the right mouse button you change the size of the area being captured.
    If you click the "Auto Capture" checkbox, the captures and transmit will occur automatically at the interval specified in the textbox below (depended on the accuracy of the simple timer component).

    If it works fine on a single machine, then you should try running the BlockDisplay code on another machine. Change the IP address in the textbox on the BlockCapture form to the IP address of that machine and press connect and hopefully it should connect if there isn't a firewall or some other network issue preventing it.

    Note that these are 2010 projects and the code was pre-2010 (probably 2005). I didn't check to see which framework it targeting, hopefully it is 4.0.
    Attached Files Attached Files
    Last edited by passel; Aug 9th, 2017 at 04:41 PM.

  14. #14

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by passel View Post
    The BlockCapture side is the client, and the BlockDisplay side is the server.
    If you want to test it quickly, you can run both projects on the same machine.

    On the BlockCapture form change the IP address to 127.0.0.1 (i.e. loopback address) and then press the Connect button. The label next to the Connect button should change to say "Connected" if the BlockDisplay program is running.

    If it works fine on a single machine, then you should try running the BlockDisplay code on another machine. Change the IP address in the textbox on the BlockCapture form to the IP address of that machine and press connect and hopefully it should connect if there isn't a firewall or some other network issue preventing it.
    Thanks Passel,

    Very interesting...

    Some feedback:

    I loaded the code into SV2017, opened BlockCapture first, I expected a 'One-Way upgrade' but it didn't happen.
    I just tried running it and it all seemed ok, So...

    I closed that and opened BlockDisplay, again no 'upgrade', and again it seemed ok. So...

    I closed that, opened File explorer, navigated to BlockCapture.exe made a desktop shortcut, then did the same for BlockDisplay.exe. Opened them both, set the IP address to 192.168.0.2 (I saw your recommended address later on a re-read), clicked connect and connected immediately...

    Played with it for a while, then copied the lot to a second laptop, did the same again(except IP address 192.168.0.4) ... Everything's lovely.
    Then I opened the two app.s on the first computer, changed the IP addresses to the other machine on both and tried again...
    Brilliant ! Goes from the second laptop to the first, no problem. Tried from the first (Windows 10) to the second (Windows 7), no joy.

    Figured maybe this has been the problem all the time. So, I removed the AV from the Win.7 machine and tried again exactly as before, and it all worked properly.

    I have to say I'm very impressed with your programmes. I shall be taking a deeper look tomorrow (Well... later today, it's already 02.15) right now I'm off to bed !


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  15. #15
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    Thanks,

    That's sorted that out, the app.s open in both laptops now, I've tried opening the client in both lappys and I've tried opening the client on one and the server on the other, I've tried opening the server on both... Can't get a connection on either machine.
    I've spent a lot of time trying to find where you obtain an IP address but haven't found it yet... It gets both computer names, and the port you specify... But no addresses.

    I click the 'Connect' button on the server, the computer waits for a short while then tells me



    Poppa.
    After submitting post #9, I downloaded the solution from the CodeBank and opened it myself. It converted without issue and, once I set the startup projects, it ran without issue. I only ran it with both the server and clients on the same machine but I had no issue with connections or sending messages.

    The MainWindow in the MessageServerTest project has this declaration:
    vb.net Code:
    1. Private WithEvents server As New MessageServer(12345)
    That MessageServer constructor looks like this:
    vb.net Code:
    1. Public Sub New(ByVal port As Integer)
    2.     Me.Initialise(IPAddress.Any, port)
    3. End Sub
    and that Initialise method looks like this:
    vb.net Code:
    1. Private Sub Initialise(ByVal ipAddress As IPAddress, ByVal port As Integer)
    2.     'Listen on the first IPv4 address assigned to the local machine.
    3.     Me.server = New TcpListener(ipAddress, port)
    4.     Me.server.Start()
    5.  
    6.     'Get the port number from the server in case a random port was used.
    7.     Me._port = DirectCast(Me.server.LocalEndpoint, IPEndPoint).Port
    8.  
    9.     'Start listen asynchronously.
    10.     Me.server.BeginAcceptTcpClient(AddressOf AcceptTcpClient, Nothing)
    11. End Sub
    The ClientWindow in the MessageClientTest project has these declarations:
    vb.net Code:
    1. ''' <summary>
    2. ''' The name of the server to connect to.
    3. ''' </summary>
    4. ''' <remarks>
    5. ''' In this case use the local machine.
    6. ''' </remarks>
    7. Private ReadOnly host As String = Environment.MachineName
    8. ''' <summary>
    9. ''' The port number on the server to connect to.
    10. ''' </summary>
    11. Private ReadOnly port As Integer = 12345
    12. ''' <summary>
    13. ''' The client object that will send the messages to the server.
    14. ''' </summary>
    15. Private WithEvents client As New MessageClient(host, port)
    That MessageClient constructor looks like this:
    vb.net Code:
    1. Public Sub New(ByVal hostName As String, ByVal remotePort As Integer)
    2.     Me.Initialise(hostName, remotePort)
    3. End Sub
    and the Initialise method looks like this:
    vb.net Code:
    1. Private Sub Initialise(ByVal hostName As String, ByVal remotePort As Integer)
    2.     Me.server = New HostInfo(hostName, remotePort)
    3. End Sub
    The port numbers need to match in both cases and the client needs to specify the name or IP address of the machine the server is running on.

  16. #16
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Trying to connect to second Laptop.

    I think that this comment may be wrong:
    vb.net Code:
    1. 'Listen on the first IPv4 address assigned to the local machine.
    2. Me.server = New TcpListener(ipAddress, port)
    I think that I originally had code in there to find the first IPv4 address on the local machine and then specified that when creating the TcpListener but I changed it to listen on any address. That was probably so that it would work on different machines because the original would only have worked on the same machine. Of course, you can specify an IP address there to accept connections from a specific machine.

  17. #17

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by jmcilhinney View Post
    I think that this comment may be wrong:
    vb.net Code:
    1. 'Listen on the first IPv4 address assigned to the local machine.
    2. Me.server = New TcpListener(ipAddress, port)
    I think that I originally had code in there to find the first IPv4 address on the local machine and then specified that when creating the TcpListener but I changed it to listen on any address. That was probably so that it would work on different machines because the original would only have worked on the same machine. Of course, you can specify an IP address there to accept connections from a specific machine.
    I'm sure you're right. I never tried server and client on the one machine... I just did and it does work correctly.

    I'll try to add a TextBox to the MessageClients Form in which to type a remote (or otherwise) IP address.
    I'll post how I get on as soon as SWMBO gives me permission to 'Play'.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  18. #18

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    I'll try to add a TextBox to the MessageClients Form in which to type a remote (or otherwise) IP address.
    Poppa.
    Adding the TextBox seemed easy enough, checking it's content seemed easy enough, once I'd added
    Code:
    Imports System.Net
    to ClientWindow.vb:

    Add
    Code:
    Public remoteAddress As IPAddress
    to 'Fields'. Then add this code...
    Code:
    Private Sub connectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles connectButton.Click
    
            Try
                remoteAddress = IPAddress.Parse(IP_Address_Box.Text)
            Catch ex As Exception
                'Address not accepted.
                IP_Address_Box.Text = "Enter IP address"
                Exit Sub
            End Try
    
            'Connecting can be done only once.
            Me.connectButton.Enabled = False
            'Connect to the server.
            Me.client.Connect()
        End Sub
    ...to this Subroutine.

    And add this Subroutine to make it simpler to enter the IP address if an error has been made.
    Code:
        Private Sub IP_Address_Box_MouseEnter(sender As Object, e As EventArgs) Handles IP_Address_Box.MouseEnter
            IP_Address_Box.Text = ""
        End Sub
    So far, so good. I've been trying for a few hours, and failing miserably, to find where exactly to insert 'remoteAddress'.




    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  19. #19
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    When you get stuck for hours, it's probably worth having a look at the documentation. See if you can't find a place to insert an IPAddress on that page.

    If programming is magic, MSDN is your tome. You have to read it to cast spells!
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  20. #20

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    When you get stuck for hours, it's probably worth having a look at the documentation. See if you can't find a place to insert an IPAddress on that page.

    If programming is magic, MSDN is your tome. You have to read it to cast spells!
    I've been trying to understand what 'the documentation' is telling me, and I'm trying to cobble together some code to just send a message to the same computer for now.

    I've got some way into it now, but can't see why it goes into, what must be, an endless loop at line No.40:
    vb.NET Code:
    1. Public Shared IpAddy As IPAddress  ' ( = 192.168.0.2)
    2.     Public Shared MyAddy As String        ' ( = 192.168.0.2)
    3.  
    4.     Private Sub Button2_Click() Handles Button2.Click
    5.         Me.BackgroundWorker1.RunWorkerAsync()
    6.         Connect(MyAddy, TextBox3.Text)
    7.     End Sub
    8.  
    9.     Shared Sub Connect(MyAddy As [String], message As [String])
    10.  
    11.         ' Create a TcpClient.
    12.         ' For this client to work I need a TCP IPAddress
    13.         ' connected to the same address as specified by the TCP IPAddress & port number
    14.         Try
    15.             Dim port As Int32 = 800
    16.             Dim client As New TcpClient(MyAddy, port)
    17.  
    18.             ' Translate the passed message into ASCII and store it as a Byte Array.
    19.             Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(message)
    20.  
    21.             ' Get a client stream for reading and writing.
    22.             '  Stream stream = client.GetStream();
    23.             Dim stream As NetworkStream = client.GetStream()
    24.  
    25.             ' Send the message to the connected TCPclient.
    26.             stream.Write(data, 0, data.Length)
    27.  
    28.             Console.WriteLine("Sent: {0}", message)
    29.  
    30.             ' Receive the TCPclient.response.
    31.             ' Buffer to store the response bytes.
    32.             data = New [Byte](256) {}
    33.  
    34.             ' String to store the response ASCII representation.
    35.             Dim responseData As [String] = [String].Empty
    36.  
    37.             Try
    38.                 ' Read the first batch of the response bytes.
    39.                 Dim bytes As Int32 = stream.Read(data, 0, data.Length)
    40.                 responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
    41.                 Console.WriteLine("Received: {0}", responseData)
    42.             Catch e1 As ArgumentNullException
    43.                 Console.WriteLine("ArgumentNullException: {0}", e1)
    44.             Catch e2 As SocketException
    45.                 Console.WriteLine("SocketException: {0}", e2)
    46.             End Try
    47.             ' Close everything.
    48.             stream.Close()
    49.             client.Close()
    50.         Catch e3 As ArgumentNullException
    51.             Console.WriteLine("ArgumentNullException: {0}", e3)
    52.         Catch e4 As SocketException
    53.             Console.WriteLine("SocketException: {0}", e4)
    54.         End Try
    55.  
    56.         Console.WriteLine(ControlChars.Cr + " Press Enter to continue...")
    57.         Console.Read()
    58.     End Sub 'Connect
    59.  
    60.     Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object,
    61.                      ByVal e As System.ComponentModel.DoWorkEventArgs) _
    62.                      Handles BackgroundWorker1.DoWork
    63.  
    64.         Connect(MyAddy, TextBox3.Text)
    65.     End Sub
    66.  
    67.     Private Sub Back_Worker1_Done(ByVal sender As System.Object,
    68.                              ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
    69.                              Handles BackgroundWorker1.RunWorkerCompleted
    70.  
    71.         TextBox3.Text = "Done"
    72.     End Sub
    Everything's ok up to line 39 of the above code, but as soon as I step into line 40 the whole thing stops responding to anything but the Debug stop button.

    Most of this stuff is more or less copied straight from MSDN and it's the bit where it goes wrong that has me confused as I'm not at all sure I understand what's going on.

    I've been trying to find what the square brackets mean in (for example) lines 9 & 35, when I search for it in MSDN I just get code examples with it in, but can't find what they actually do anywhere.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  21. #21

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Ah! Reading through post 20, I spotted that I've managed to remove the Comment-out from line 6.
    Putting that back (i.e. Commenting-out line 6) stops the loop.
    Sadly though the message still doesn't get through.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  22. #22
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    OK, let's talk about WHY it seemed to go into an infinite loop. If it's still not working properly even without freezing, this might help you figure out why.

    Read() is a synchronous call. Sometimes we also say it "blocks". Those are both ways of saying it does what most code does: you don't move to the next line until Read() finishes. That's real dangerous with I/O in general. Especially network I/O.

    With a file, you usually finish a Read() pretty fast unless you ask for waaaaay too much data at once. You ask for 1KB, you get 1KB in milliseconds. So with a lot of file I/O it doesn't really matter if you do things on the UI thread because while slow, it's still an imperceptible delay. And if the file's total size is smaller than what you ask for, well, you don't get all of it and it returns quickly.

    Network I/O is messier. The only "end of file" in TCP comes when the other side closes the connection. If, for whatever reason, the other side doesn't close it, you're going to sit at that Read() call for a looooong time. .NET has ridiculous default timeouts for these things, something near 10 minutes, I think! But it may not even be that the other side doesn't close.

    Since this is a blocking Read(), it can wait until it reads as much data as you asked for. In this case, you're asking for 257 bytes. What if the other side doesn't send 257 bytes? Well, if it doesn't close the connection, Read() is going to wait until it gets 257 bytes. That might be "forever" based on the way the program's set up!

    And it might not even be "bad code". It could just be that the network's slow and getting your 257 bytes takes a long time.

    So.

    This is why if I didn't say earlier, I meant to say you just can't do network I/O without involving helper threads. If you are on the UI thread, and Read() takes a few seconds, that's a few seconds your app will appear to freeze. There are hundreds of reasons why a Read() for even a small amount of data might take a few seconds to finish. There are also plenty of reasons it might take FOREVER to finish.

    Line 5 tells a BackgroundWorker to do the same thing as line 6. But since Line 5 is telling a BackgroundWorker to do it, it happens on a worker thread. So when you comment out line 6, the UI thread is free to do its thing while waiting on the BackgroundWorker. But it's likely that's still taking forever to finish.

    Why's it taking forever? That's worth investigating. The easiest answer is "maybe it's not getting all 257 bytes back, and the other side doesn't disconnect so it doesn't know it should stop reading".

    There's another way for networking APIs to work, called "non-blocking mode". In that mode, Read() always returns instantly. If it had some data, it fills the buffer with as much as it could read, and it returns a value that tells you how many bytes are there. If there was no data, it returns 0, and you can decide if you want to try again or if you want to assume you have everything. In non-blocking mode, you can write code like this:
    Code:
    DO NOT COPY AND PASTE THIS
    I DON'T THINK READ WORKS THIS WAY
    
    Dim allData As New List(Of Byte)()
    Dim buffer(254) As Byte
    Dim bytesRead As Integer = 0
    Do
        bytesRead = stream.Read(buffer, 0, buffer.Length)
        allData.AddRange(buffer.Take(bytesRead))
    Loop Until bytesRead = 0
    In this case, if only 64 bytes are sent, bytesRead will be 64 on the first loop. We'll add 64 bytes to allData. Then we try again. We get 0 bytes on the next Read() call, so bytesRead will be 0. So we add nothing to allData, and we exit the loop and assume we have all the data.

    Unfortunately, that's naive. We might NEED 255 bytes, but a slow network means we've only received 64 so far. This is where protocols become useful, as they can send data to help us figure out what length we're supposed to expect.

    So the trick here is you're asking for 257 bytes out of Read(). But are you SENDING 257 bytes? Probably the easiest way to find out is to make one small change. Make Line 32:
    Code:
    data = New [Byte](0) {}
    That looks stupid, but it means Read() will ask for 1 byte. If you aren't getting 1 byte, you know the "client" end of the equation isn't working at all. But if you get 1 byte, then you know the "client" is sending successfully, but you get stuck because Read() wants 257 bytes.

    I want to say so much more, but I'm in the weeds now. I had a pretty cool client/server example at work the other day, but I didn't have time to post it because company Vice Presidents are in town so I can't exactly be spending my day on forum posts I'm going to tinker again tomorrow if I have time. My wife's out of town so it's not like I have anything better to do.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  23. #23

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Thanks again Sitten Spynne, that's brilliant.

    I'll try your read one byte idea, whilst reading your post I was expecting you to say measure the length of the message and send that... Thinking about that it's the wrong way round... Damn ! Read() would need to be clairvoyant ! I could maybe try asking for a fixed number of bytes, then before sending a message I could send the number of message bytes, padded with (say) zeros to exactly that fixed number.

    I have a question:
    With a file, you usually finish a Read() pretty fast unless you ask for waaaaay too much data at once. You ask for 1KB, you get 1KB in milliseconds. So with a lot of file I/O it doesn't really matter if you do things on the UI thread because while slow, it's still an imperceptible delay. And if the file's total size is smaller than what you ask for, well, you don't get all of it and it returns quickly.
    I'm not quite sure what you mean by "you don't get all of it and it returns quickly." ?



    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  24. #24

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    Thanks again Sitten Spynne, that's brilliant.

    I'll try your read one byte idea
    Ok, I tried that (I forgot you said 0, I set 1) ran the code and expanded 'data' and found it has two bytes, both 0.
    I restored the line back to where it was at 256. It's only at 256 because that's what was there in the MSDN example. I ran the code again, expanded 'data' and found it had 257 'Items' (?) again, they were all 0.

    I've not had a chance to try your other suggestion as yet (SWMBO had other plans !) but I'll get onto that as soon as I can, 01.40 ATM so I'm calling it a day for now.


    Poppa.
    Last edited by Poppa Mintin; Aug 13th, 2017 at 07:40 PM. Reason: Added 2nd test. (Updated time)
    Along with the sunshine there has to be a little rain sometime.

  25. #25
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    I have a question:
    I'm not quite sure what you mean by "you don't get all of it and it returns quickly." ?
    Blocking and non-blocking reads ask two different questions.

    A blocking read has a conversation like this:
    I would like to get 256 bytes. Please wait until you get 256 bytes or the other side disconnects, then give them to me.
    A non-blocking read has a conversation like this:
    I would like to get 256 bytes. Please give me as many bytes as you can, and let me know how any there are. If I get less than 256, I'm going to ask for more later.
    So with blocking reads, if the client sends 150 bytes then stops sending, Read() is going to wait until either it gets 106 more bytes or the connection closes. With non-blocking reads, if the client sends 150 bytes, you get your array back with 0-149 populated, and Read() returns 150 to let you know where the data stops in the array. You can call Read() again later, and if the remaining bytes aren't there yet, Read() returns 0 to let you know no data was received. Eventually, you might decide "it's never coming" and close the connection yourself. Or, you might get the bytes.

    Your struggles with "How do I know how much to ask for?" are why I mentioned protocols. Many network protocols include information for determining length ahead of time. For example, in HTTP:

    The first block of data will be the headers. The headers are textual data that always ends with the string \r\n\r\n, or CRLF, twice. So any HTTP server knows when it gets a connection, it first needs to keep reading until it sees the end of the headers.

    The headers might contain a line that starts with "Content-Length:". If that header is present, it indicates the size of the message body. That tells the program how many bytes to read.

    If they don't contain that line, sometimes the "Transfer-Encoding" header indicates a different protocol will be used. For example, in Chunked encoding every message begins with a string representing the number of bytes in the "chunk", terminated with CRLF. So the program reads until it finds CRLF, parses the number, then reads that many bytes. The end of the message is signified by "0\r\n\r\n", or "a chunk with zero bytes and a terminating CRLF".

    So in general, when sending large amounts of data, some mechanism will exist within that data stream to help indicate how much data is arriving.

    I'm going to try to make a less complicated example at work today. It sounds like you got something wrong on the client end when tinkering with the MSDN examples. It'd be nice to start with something that works, then build on top of it.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  26. #26
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    Let's take a biiiiiiig step back.

    Involving Windows Forms is complexity. Sending Strings, believe it or not, is complexity. Networking code is complexity. If we try to mash all of these things together, we have to talk about lots of different concerns and learn lots of things all at once. It makes me think of a song:

    Too broke to pay attention, better get you some
    When trouble's up I double up on bubblegum
    I like to strut my stuffing down on Easy Street
    It's so easy
    Without complexity
    So. Let's forget all the complexity and start with something very basic. Console applications. We are going to write a client that sends one byte, then disconnects. We are going to write a server that expects to receive one byte and displays it. We will slowly add features, but if we can't get a one-byte-then-disconnect transaction working we can be 100% certain anything more advanced would be confusing.

    Sometimes you'll write one program that is both a client and a server, but I am keeping them separate right now.

    Here is the client. Let's talk about it.

    Code:
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Threading.Tasks
    Imports System.IO
    
    Module Client
    
        Private ReadOnly _rng As New Random()
    
        Sub Main()
            Console.WriteLine("I'm the client. I know I need port 3000, but I need you to tell me the connection IP.")
            Dim connectionEndpoint As IPEndPoint = Nothing
    
            ' You have to input the right IP for the client.
            While True
                Console.Write("IP?> ")
                Dim ipInput As String = Console.ReadLine()
                Dim ip As IPAddress
                If Not IPAddress.TryParse(ipInput, ip) Then
                    Console.WriteLine("I don't understand that. Try again.")
                    Continue While
                End If
    
                connectionEndpoint = New IPEndPoint(ip, 3000)
                Exit While
            End While
    
            Console.WriteLine("OK, now I'm going to send a message.")
            Using client As New TcpClient()
                client.Connect(connectionEndpoint)
                Console.WriteLine("I connected!")
    
                Using stream = client.GetStream()
                    Dim data(0) As Byte
                    _rng.NextBytes(data)
    
                    Console.WriteLine("I am going to send the byte '{0}'.", data(0))
    
                    stream.Write(data, 0, 1)
    
                    Console.WriteLine("Message sent! Disconnecting.")
                End Using
            End Using
    
            Console.WriteLine("That's all, folks!")
        End Sub
    
    End Module
    It is very straightforward, but sadly we have to spend a lot of lines of code getting the IP address the client will connect to. Since I tested with the client and server on the same machine, I could use 127.0.0.1.

    The client creates a TcpClient, connects, then opens the stream. A single, random byte is generated and written. The Write() function always takes a starting offset and length in case you're using an array as a buffer for larger data, a neat trick that's better explained in the context of more complex problems.

    After the byte is written, the stream is closed, as is the connection, and the client is done.

    Let's look at the server. It unavoidably has to use some asynchronous code, it felt silly to write a single-connection server.
    Code:
    Imports System.IO
    Imports System.Net
    Imports System.Net.Sockets
    
    Module Server
    
        Private _listener As TcpListener
    
        Sub Main()
            Dim listenEndPoint As New IPEndPoint(IPAddress.Any, 3000)
            _listener = New TcpListener(listenEndPoint)
    
            _listener.Start()
            _listener.AcceptTcpClientAsync().ContinueWith(AddressOf WhenAConnectionHappens)
            Console.WriteLine("I am listening for traffic on port 3000.")
    
            ' A tricky part of console applications is they end if we reach the end of Sub Main.
            ' So loop until we decide to quit.
            While True
                Console.WriteLine("I am in the loop! Pressing Enter will make me stop.")
    
                If Console.KeyAvailable Then
                    Dim theKey = Console.ReadKey()
                    If theKey.Key = ConsoleKey.Enter Then
                        Console.WriteLine("You pushed enter, I'm shutting down!")
                        Exit While
                    End If
                End If
    
                Task.Delay(1000).Wait()
            End While
    
            _listener.Stop()
        End Sub
    
        Private Sub WhenAConnectionHappens(ByVal parentTask As Task(Of TcpClient))
            Console.WriteLine()
            Console.WriteLine("I got a connection!")
            If parentTask.Exception IsNot Nothing Then
                Console.WriteLine("But there was a problem:")
                Console.WriteLine(parentTask.Exception)
                Console.WriteLine("(This may be expected if you are closing the application!)")
            Else
                Using remoteClient = parentTask.Result
                    Console.WriteLine("It came from IP: {0}", remoteClient.Client.LocalEndPoint)
                    Console.WriteLine("I'm going to try to read data from it.")
    
                    Using remoteStream = remoteClient.GetStream()
                        Dim data(1024) As Byte
                        Dim bytesRead As Integer = 0
                        bytesRead = remoteStream.Read(data, 0, 1)
    
                        Console.WriteLine("I expected 1 byte, and {0} were read.", bytesRead)
                        If bytesRead > 0 Then
                            Console.WriteLine("I got '{0}'.", data(0))
                        Else
                            Console.WriteLine("Strange. I did not expect 0 bytes.")
                        End If
                    End Using
                End Using
            End If
    
            Console.WriteLine("I am finished with that connection, I am going to wait for another.")
            _listener.AcceptTcpClientAsync().ContinueWith(AddressOf WhenAConnectionHappens)
        End Sub
    
    End Module
    Setting up a TcpListener isn't much harder than creating a client. It needs an IP it will listen on, and listening on IPAddress.Any is a good trick for simple purposes. You must call Start() for the server to be listening.

    The AcceptTcpClientAsync() method will return a task that completes if an error occurs or if a client connects. I added a continuation (ContinueWith()) that will be called when that happens. This is sort of like the RunWorkerCompleted event for a BackgroundWorker, but talking more about how this works is more appropriate when we are talking about Windows Forms. Console applications have a different kind of ugly.

    The While True loop is irrelevant to networking. Once we call AcceptTcpClientAsync() and schedule the continuation, the server is running. But console applications end when Main() completes, so I had to write a loop to wait for the user to ask the application to quit. It waits 1 second, checks if Enter was pushed, and terminates the loop if that happens. When all is done, the TcpListener is told to stop listening: this is polite and ensures it has a chance to let go of the socket it was using.

    WhenAConnectionHappens() is called when the Task completes, which you should remember happens when an error occurs or a connection happens. (So maybe it's a bad name.) It receives the Task that was created when AcceptClientAsync() was called, and that Task's Result property is of type TcpClient. That represents the client connection.

    But first we have to check the Exception property to see if there was an error. If there was, this property will hold that error, or at least the frustrating AggregateException that ultimately contains the error. There will definitely be one of these, because when you call TcpListener.Stop() while an asynchronous method like AcceptTcpClientAsync() is running, it forces that task to finish and a particular exception indicates "I was told to stop listening."

    If there was no error, we know the Result property is a TcpClient that represents the connection. I wrote, and like to write, very paranoid Read() code. I only EXPECT one byte, so I could make an array that holds one byte, ask for one byte, and be done. But people who write network programs tend to make stupid mistakes, and it's very helpful when a server anticipates those mistakes and handles them gracefully.

    So I allocate a 1024-byte array for the data, even though it'd be a bug for Read() to return more than one byte based on how I called it. Pay attention to how it was called: I told it to read up to 1 byte, and place that in data starting at index 0. Later, we'll see why this seemingly-goofy calling convention exists. But we're shedding complexity now. Let's move on.

    If I got 0 bytes (which theoretically can happen), I print how odd that is and move on. In a more robust application, we might try to Read() again. But for now, we'll treat it as an interesting anomaly and just note that it happened. (I'm almost positive the implementation of Read() won't let that happen.)

    If I got at least 1 byte, I print the decimal value of the byte I got, then finish with the client connection. The last thing I do is call AcceptTcpClientAsync() again, with the same continuation, so the server can handle other requests.

    Try this application out. If it works, then we know we aren't dealing with hardware/networking issues. Make sure the byte that the server receives is the same one sent by the client. If it's not, something is wrong. It should be trival to expand this to send "multiple bytes", but don't get excited and try to work towards that goal until this one works.

    That's how programming should work: we write small, simple things that work, then slowly add working features until we have something complicated. If we try to start by writing something complicated, we almost always fail.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  27. #27

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    I have to thank you again Sitten Spynne, this is a great deal of time you're spending on my behalf, I really do appreciate it. SWMBO has had me doing other things, and another application that I've not used for ages started playing up, probably due to Windows 10. I've spent nearly two days trying to sort out what's wrong, but it only took a few hours today to write a completely new equivalent application, then a few more hours dealing with the output from that. All done now (I hope) I can get back on with this TCP job.

    Just coming up to midnight, I'll see how far I can get in an hour.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  28. #28

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Situation report @ 01.55

    Hi,

    Well it's not actually working. I expect it ought to be obvious, but not to me. I can't tell if this is supposed to be all one project or two separate ones.
    I tried it first as one. First with both modules in the same Form, and called the sub Main thus:
    Code:
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Threading.Tasks
    Imports System.IO
    
    Public Class Form1
    
        Private Sub Form1_Load() Handles MyBase.Load
            Server.Main()
            Client.Main()
        End Sub
    End Class
    
    Module Client
    'etc...
    but had a runtime error. Then I tried it, still in the same application, but with two different Forms. I put the Server in Form1 and the Listener in Form2 but still had the same runtime error. I added a Button to the form and moved the calls to the Sub Main()s into it's Click event. still had the same runtime error but it was delayed until the 'Click'.
    I swapped the order of calling the two subs, same problem. The Server seems to be ok, just sits there churning out
    IP?> I don't understand that. Try again.
    IP?> I don't understand that. Try again.
    IP?> I don't understand that. Try again.
    hundreds of times in the output window, but it's the Listener that fails, it tellsme:
    'I am listening for traffic on port 3000. I am in the loop! Pressing Enter will make me stop.
    but then fails:
    Code:
            While True
                Console.WriteLine("I am in the loop! Pressing Enter will make me stop.")
    
                If Console.KeyAvailable Then 
                    Dim theKey = Console.ReadKey()
                    If theKey.Key = ConsoleKey.Enter Then
                        Console.WriteLine("You pushed enter, I'm shutting down!")
                        Exit While
                    End If
    it fails at "If Console.KeyAvailable Then" with:
    System.InvalidOperationException: 'Cannot see if a key has been pressed when either application does not have a console or when console input has been redirected from a file. Try Console.In.Peek.
    Then I scrapped all that and made two separate applications, one each for Server and Client. Put a shortcut for each on the desktop and ran them independently, this made no difference. Same problem.

    Maybe I'm using the wrong console ? I open the Debug 'Output' window to read console, I never use this myself, never have, I only recently discovered where to read console stuff... I've always put a temporary TextBox somewhere on the form, even if it means temporarily enlarging the form, and send messages to that. (Or those).




    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  29. #29
    PowerPoster PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Pontypool, Wales
    Posts
    2,458

    Re: Trying to connect to second Laptop.

    So. Let's forget all the complexity and start with something very basic. Console applications. We are going to write a client that sends one byte, then disconnects. We are going to write a server that expects to receive one byte and displays it. We will slowly add features, but if we can't get a one-byte-then-disconnect transaction working we can be 100% certain anything more advanced would be confusing.

    Sometimes you'll write one program that is both a client and a server, but I am keeping them separate right now.
    So I would say they are two separate console applications based on that bit of the post.

    The client is the one asking for an IP, not the server - you will need to type the server's IP address when the client displays IP>?

  30. #30

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by PlausiblyDamp View Post
    Sometimes you'll write one program that is both a client and a server, but I am keeping them separate right now.
    So I would say they are two separate console applications based on that bit of the post.

    The client is the one asking for an IP, not the server - you will need to type the server's IP address when the client displays IP>?
    Ah yes... I guess I missed that bit, too early in the post when I was trying to find an answer maybe

    And yes, you're right of course...
    The Server seems to be ok, just sits there churning out
    ought to say...
    The Client seems to be ok, just sits there churning out
    I put it down to the lateness of the hour! xxxxxxxHowever...
    "you will need to type the server's IP address"
    ... a chance would be a fine thing.



    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  31. #31

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    Situation report @ 01.55

    Hi,

    Maybe I'm using the wrong console ? I open the Debug 'Output' window to read console, I never use this myself, never have, I only recently discovered where to read console stuff... I've always put a temporary TextBox somewhere on the form, even if it means temporarily enlarging the form, and send messages to that. (Or those).

    Poppa.
    Ok guys... I just discovered 'Console Applications' !
    I want to post this before someone explains it to me.

    As I said before I knew nothing about console stuff.

    Now that I've found that, everything's working as I think it ought... Except, I start the Server, it tells me it's listening, and that 'Enter' will close it.
    That's fine all working, including 'Enter'.
    Start the client, enter the IP address, fine, it says it's going to send a message... Nothing else happens for about 20 seconds when the client stops with a 'time-out' error and stops.
    I'm trying to see if I can find what's happening... (not happening).


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  32. #32

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    It is very straightforward, but sadly we have to spend a lot of lines of code getting the IP address the client will connect to. Since I tested with the client and server on the same machine, I could use 127.0.0.1.
    OK, got it! I don't understand why my machine's IP address doesn't work, (192.168.0.2) whilst 127.0.0.1 does.
    I've been trying TCP for quite a while now so I've got used to entering my machine's IP address automatically. When I entered 192.168.0.2, I did get a connection.
    I reckon to've read through the code carefully looking for the actual use of 127.0.0.1 and believe it's not there.


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  33. #33

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    The AcceptTcpClientAsync() method will return a task that completes if an error occurs or if a client connects. I added a continuation (ContinueWith()) that will be called when that happens. This is sort of like the RunWorkerCompleted event for a BackgroundWorker, but talking more about how this works is more appropriate when we are talking about Windows Forms. Console applications have a different kind of ugly.
    Ah Ha !
    Now I understand this too.

    Pop.
    Along with the sunshine there has to be a little rain sometime.

  34. #34
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    OK, got it! I don't understand why my machine's IP address doesn't work, (192.168.0.2) whilst 127.0.0.1 does.
    I've been trying TCP for quite a while now so I've got used to entering my machine's IP address automatically. When I entered 192.168.0.2, I did get a connection.
    I reckon to've read through the code carefully looking for the actual use of 127.0.0.1 and believe it's not there.


    Poppa.
    You're supposed to type in 127.0.0.1. The client asks you to give it an IP address. You won't find that IP address in the code because the client expects you provide the IP address. That's why it says "I need you to tell me the connection IP".

    There are some reasons why 127.0.0.1 might work when 192.168.0.2 doesn't. The first thing I would try is turning off Windows Firewall to see if that magically makes the 192 address work. If you're running anything else that might have a firewall, that could be getting in the way, too. The "wait 20 seconds and time out" behavior is what happens when you try to open a connection to an IP that doesn't respond at all.

    Double-check and triple-check that you are indeed entering the correct IP. Double check you're factoring in that if the client is on machine A and the server is on machine B, the client needs the IP address of machine B to connect.

    We have to get this working consistently because there's not much point in trying more complicated tasks if the simplest possible thing isn't working.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  35. #35
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    OK, got it! I don't understand why my machine's IP address doesn't work, (192.168.0.2) whilst 127.0.0.1 does.
    I've been trying TCP for quite a while now so I've got used to entering my machine's IP address automatically. When I entered 192.168.0.2, I did get a connection.
    I reckon to've read through the code carefully looking for the actual use of 127.0.0.1 and believe it's not there.

    Poppa.
    Perhaps you meant "didn't" get a connection, not "did".

    127.0.0.1 is a "special" address. One of the names for it is the loopback address.

    127.0.0.1 will exist automatically on every computer and the traffic to that address will never actually go through the NIC (Network Interface Card). The packets are looped back within the machine at the Socket level so you can test two applications that connect over Ethernet on the same machine by using the 127.0.0.1 address.

    Of course, if you use the machine's actual IP addresses, that should work essentially the same as using the loopback as the application would be transmitting to itself, but I see Sitten Spynne has also replied now, and has pointed out the difference, in that using the local address will send to the NIC and is probably subject to Firewall protection.
    Last edited by passel; Aug 17th, 2017 at 08:43 AM.

  36. #36
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by passel View Post
    Perhaps you meant "didn't" get a connection, not "did".

    127.0.0.1 is a "special" address. One of the names for it is the loopback address.

    127.0.0.1 will exist automatically on every computer and the traffic to that address will never actually go through the NIC (Network Interface Card). The packets are looped back within the machine at the Socket level so you can test two applications that connect over Ethernet on the same machine by using the 127.0.0.1 address.

    Of course, if you use the machine's actual IP addresses, that should work essentially the same as using the loopback as the application would be transmitting to itself, but I see Sitten Spynne has also replied now, and has pointed out the difference, in that using the local address will send to the NIC and is probably subject to Firewall protection.
    Yes, it's very subtle and I think I referenced some vague problems I'd had with it in a previous thread.

    Where it really bit me was a difference between Windows and Linux, my app was a Mono app. At that time, I was naive and would set up my TcpListener to listen on 127.0.0.1. On Windows, this worked fine, apparently the network subsystem took that to mean "I want to listen for local traffic". On the Linux server I deployed to, it didn't work at all, because it meant "listen to traffic on the loopback device".

    So it sounds like there's a REALLY strong chance you need to open up your firewall, Poppa Mintin. Turning it off is a good solution for quick debugging. The next-best is to dig in your firewall settings and tell it to allow your program through. A bit less elegant, but no less effective, is to tell the firewall to let any program use a particular port (in this case, 3000).
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  37. #37

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    SitRep 20.08.2017.

    Hi guys...

    Still having fun with this...

    I'm trying to turn Sitten Spynne's Server Console App. into a Windows Forms App. and I think I'm getting somewhere.
    Not all plain sailing, and of course I've hit a snag.

    After...
    Code:
    Public Class Form1
        Public say As String    
        Private Sub Form1_Load()
        ' some code
        End Sub
    ...I've added:
    Code:
        Public Sub New()
            InitializeComponent()
            BackgroundWorker1.WorkerReportsProgress = True
            BackgroundWorker1.WorkerSupportsCancellation = True
        End Sub
    Which I believe enables me to use 'ProgressChanged' with BackgroundWorker1.

    I've taken all (most) of the code from the Server module and placed it inside:
    Code:
     Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object,
                        ByVal e As System.ComponentModel.DoWorkEventArgs) _
                        Handles BackgroundWorker1.DoWork
    
    ' To facilitate the use of 'ProgressChanged';  here I've added:
    
            Dim worker As System.ComponentModel.BackgroundWorker
            worker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
    
    ' Server Module code here
    
                             '  Plus for example:
            say = "I am listening for traffic on port 3000."
            worker.ReportProgress(1)
    
     End Sub
    Then added:
    Code:
        Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object,
                                     ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
                                     Handles BackgroundWorker1.ProgressChanged
    
            TextBox1.Text += say & vbCrLf        ' String from BackgroundWorker1
    
        End Sub
    The above sums up more or less what I've been trying and the above all works satisfactorily.

    My snag comes in Sitten Spynne's subroutine:
    Code:
      Private Sub WhenAConnectionHappens(ByVal parentTask As Task(Of TcpClient))
    This sub. doesn't allow direct access to Form1 controls either, so I'm trying to do something similar to the
    'ProgressChanged' in BackgroundWorker1 in this subroutine and failing.

    Obviously I tried:
    Code:
            Dim worker As System.ComponentModel.BackgroundWorker
            worker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
    But 'sender' isn't accepted, omitting it isn't accepted either, and I can't find an alternative, nor a replacement for the whole code.
    (Oh bother it !)


    Poppa.
    Along with the sunshine there has to be a little rain sometime.

  38. #38
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Trying to connect to second Laptop.

    I'm not going to be talking about Windows Forms for a while, because there is still a lot to learn about "making a program work".

    The Short Version

    You haven't confirmed my networking example works with console applications yet. So what good is a GUI? You're only making the code that doesn't work more complicated. It's not surprising that, after complicating the broken code, it doesn't work. You still say you can't get the two machines talking to each other. This is a big problem. We might have to try different software to see where the problem lies before continuing.

    The Long Version

    I don't want to talk about WinForms yet because there are things you need to learn about how asynchronous network I/O works in a WinForms application before we get there. If I showed you a functioning application right now (and at least two experts already have), you'd be lost as if in a maze, because the "networking" parts are mixed with the "thread synchronization" parts, and it's hard to know which is which. And if you tinker with either, it's hard to know which one you broke.

    I know I'm moving very slow, and that's frustrating. Let me explain what I want to do by analogy:

    If you want to build a LEGO set that looks like a computer, you can buy one. It will come with exactly the bricks you need and instructions. If you follow them, you'll get a thing that looks like a computer!

    Now suppose I ask you, "Can you build that, but at 1/3 scale?" That's an interesting question. You'd have to buy custom bricks, there's no kit for it. 1/3 scale is pretty precise, you might have to approximate some shapes or buy weird-sized blocks. Do they even exist?

    Examples are like that LEGO set that was bought. They do exactly one thing in exactly one program. They demonstrate concepts, and those concepts aren't always best practices. You're meant to read them, get how the API fits together, then integrate them properly into your application.

    Most programs are more like my request for the 1/3 scale LEGO computer. You can look at the instructions for the full-scale computer and get a rough idea of what you need, but you're also going to have to do some brainwork on your own to get it done. The more experienced with LEGO you are, the easier this gets.

    Most people on this forum, and the experts in this thread so far, like to take the "instructions" approach. It's valid: most people just want an answer today so they can move on to other issues. You've got a couple of these examples in this thread. They didn't work for you.

    So instead, I'm sitting down with a bucket of 10,000 bricks and trying to teach you "how to build". That takes much longer. But I feel like what you want isn't just "one working example", but "the ability to write this kind of code whenever I want". I can't give you enough sets of instructions to represent that. But I can show you every way bricks fit together, and hope that helps inspire you to be able to build things you haven't seen yet.

    In my head, it goes like this:
    1. Can we send 1 byte? (Confirmed!)
    2. Can we send more than 1 byte? (Dubious, does it work between two machines?)
    3. Let's talk about sending "arbitrary" numbers of bytes!
    4. Let's talk about sending Strings!
    5. Let's talk about asynchronous network I/O!
    6. Let's talk about how asynchronous code works in WinForms!
    7. Let's convert the console chat application to WinForms!


    We haven't made it past step 2 yet. If you want me to hurry along to step 6 and 7, you need to figure out why that's not working. I won't be offended if you find someone else's example that works, but I'm also not going to respond to questions about skipping steps unless I think you are SO close I want to congratulate you.

    Right now you're not close at all. I'd have to write tutorials 5 and/or 6 to explain why. But if we can't prove tutorial 2 is working, it's a waste to skip ahead.

    I like writing the tutorials, but it takes a lot of my time and I don't have a lot of time. 2-3 hours is a conservative estimate! The problem is I don't know exactly which topics between (1) and (7) you lack, so it's easier for me to address them ALL and let you figure that part out. I have (3) mostly written and ready to go, but I'm waiting to hear if (2) worked for you first. There's not much sense in building a staircase by starting a the top, or trying to install the middle steps before the bottom steps.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  39. #39

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    You haven't confirmed my networking example works with console applications yet.
    Please check out posts #31, #32, #33 and #34.

    (Especially #31)
    Ok guys... I just discovered 'Console Applications' !
    I want to post this before someone explains it to me.

    As I said before I knew nothing about console stuff.

    Now that I've found that, everything's working as I think it ought...
    Yeah, it didn't work quite correctly when I used the wrong IP Address... but I did say I'd got that fixed too.


    Poppa.

    PS.

    I've re-read my post #31 and I notice that I didn't specifically say that the two laptops were communicating...
    I only mentioned the address problem in relation to working both halves on just one computer.

    Pop.
    Last edited by Poppa Mintin; Aug 20th, 2017 at 06:22 PM. Reason: Added PS
    Along with the sunshine there has to be a little rain sometime.

  40. #40

    Thread Starter
    PowerPoster Poppa Mintin's Avatar
    Join Date
    Mar 2009
    Location
    Bottesford, North Lincolnshire, England.
    Posts
    2,423

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    We haven't made it past step 2 yet.

    I like writing the tutorials, but it takes a lot of my time and I don't have a lot of time. 2-3 hours is a conservative estimate!
    I've been trying to find step 2 but must've missed it.

    I too like writing tutorials when I know the subject I'm talking about, I get a lot of satisfaction from helping someone, and I'm very grateful to you for the time you're spending. In defense for leaping ahead and trying stuff on my own... I can't say to you... 'Hey! I've done that, can I have the next step?' now can I? I'm well aware of the time it takes. So while I wait I try to figure what I assume will be the next step ... I hope you're not offended by that.


    Poppa.

    (Reply #2 to post #38)
    Along with the sunshine there has to be a little rain sometime.

Page 1 of 3 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width