Page 3 of 3 FirstFirst 123
Results 81 to 109 of 109

Thread: Trying to connect to second Laptop.

  1. #81

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by PlausiblyDamp View Post
    You might need to either declare it as an IpEndPoint or if it is being returned from a method try casting it to an IpEndPoint, EndPoint is a base class which doesn't have an Address property.

    https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx
    Thanks PlausiblyDamp,

    That's pointed me in the right direction, it's a bit of a roundabout route but it gets there.
    Code:
        Private Sub SvrGot(ByVal token As IAsyncResult)
            Dim ipa As String
            Dim Ears As TcpListener = CType(token.AsyncState, TcpListener)
    
            palPC = Ears.EndAcceptTcpClient(S_Token)
            ipa = palPC.Client.RemoteEndPoint.ToString
            ipa = ipa.Substring(0, InStr(ipa, ":") - 1)
            Pal = IPAddress.Parse(ipa)
            palName = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
            UpDate_T(palName & " connected !")
            S_Token = Nothing
    
            ' Since we have a client connection, there's no good reason to keep listening!
            Ears.Stop()
    
            ' Start listening for messages from the client.
            ListenToClient(palPC)
        End Sub
    All that just to get the name of the 'remote' computer !
    Sadly it's not a vital part of my project, but it highlights one of my problems... I like to get all the bells and whistles working as I go along instead of getting the bare bones working first.


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

  2. #82

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

    Question to Sitten Spynne

    Hi Sitten Spynne, I've just found a problem, or a question at least with regard to your attached code for Async Chat in post #54 on the 1st September.
    Code:
        Private Sub WhenClientConnectsToServer(ByVal state As Object)
            ' Note that sometimes asynchronous things don't return a result. You still have to call the 'End' method!
            _remoteClient.EndConnect(_clientConnectToken)
            _clientConnectToken = Nothing
            SetStatus("Connected!")
    
            ListenToClient(_remoteClient)
        End Sub
    I don't understand the 'ByVal state As Object', yes I understand what it means, but what does it do?

    'state' doesn't seem to be used anywhere else in the subroutine. Maybe the 'Nothing' in the subroutine...
    Code:
        Private Sub ConnectToServer(ByVal ipInput As String)
            Dim remoteAddress = IPAddress.Parse(ipInput)
            Dim port = 3000
            _remoteClient = New TcpClient()
    
            _clientConnectToken = _remoteClient.BeginConnect(remoteAddress, port, AddressOf WhenClientConnectsToServer, Nothing)
            SetStatus("Connecting...")
        End Sub
    ... is what's being passed? And maybe the '(ByVal state As Object)' is a requirement of that form of call to a subroutine?

    I'm trying to use a version of this subroutine in a test project and have a problem in this area and wonder if this is where my problem lays.


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

  3. #83
    PowerPoster PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Pontypool, Wales
    Posts
    2,474

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Poppa Mintin View Post
    Thanks PlausiblyDamp,

    That's pointed me in the right direction, it's a bit of a roundabout route but it gets there.
    Code:
        Private Sub SvrGot(ByVal token As IAsyncResult)
            Dim ipa As String
            Dim Ears As TcpListener = CType(token.AsyncState, TcpListener)
    
            palPC = Ears.EndAcceptTcpClient(S_Token)
            ipa = palPC.Client.RemoteEndPoint.ToString
            ipa = ipa.Substring(0, InStr(ipa, ":") - 1)
            Pal = IPAddress.Parse(ipa)
            palName = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
            UpDate_T(palName & " connected !")
            S_Token = Nothing
    
            ' Since we have a client connection, there's no good reason to keep listening!
            Ears.Stop()
    
            ' Start listening for messages from the client.
            ListenToClient(palPC)
        End Sub
    All that just to get the name of the 'remote' computer !
    Sadly it's not a vital part of my project, but it highlights one of my problems... I like to get all the bells and whistles working as I go along instead of getting the bare bones working first.


    Poppa.
    Did you try casting the palPC to an IPEndPoint rather than going via string conversion / parsing?

  4. #84

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

    Re: Question to Sitten Spynne

    Quote Originally Posted by Poppa Mintin View Post
    Hi Sitten Spynne, I've just found a problem, or a question at least with regard to your attached code for Async Chat in post #54 on the 1st September.
    Ok, I've sorted that out... My surmise was correct it seems.

    My problem was that although the two computers were connecting, my code said they weren't.
    It also turns out that my Win.7 lappy isn't as fast as my i7 Win.10 lappy! So I have to build-in a short delay.


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

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

    Re: Trying to connect to second Laptop.

    Post #54 is one of your own posts. I'm not quite sure when that code was featured, but there's "no reason" and "a good reason" why that parameter was there. It's a bit of a mistake on my part, but not a very serious one.

    If you read the documentation for BeginConnect() (and most async methods using this pattern), you'll see that callback parameter is an AsyncCallback delegate type. That is a Sub that takes an IAsyncResult parameter.

    Remember that the pattern dictates after you call BeginSomething(), you must call EndSomething(). Usually, you pass along a "state" object which has a reference to "the thing I called BeginSomething() on". That object is part of the IAsyncResult, and that IAsyncResult is passed as a parameter to the callback so it can properly call EndSomething().

    But in this case, I already had a more convenient reference to "the thing that called BeginSomething()", so I used that and ignored the parameter. It was Object because this was a very early bit of code, and I couldn't remember that the parameter to the callback was IAsyncResult. Since IAsyncResult can be cast to Object, VB didn't complain that it didn't exactly match. Don't ask me to explain the delegate conversion rules, I've never understood them.

    But since that parameter is part of AsyncCallback's required signature, I have to provide it even if I don't use it.

    Similar things happen with the Thread class, it wants a delegate that is a Sub that takes 1 Object parameter for state. Even if you don't use it, you have to have that parameter.

    As usual: "I had to build in a short delay" means nothing to me. When you speak in paragraphs I can't understand you. When you show me code, I can comprehend.

    I say this because "when something is broken", we have to write "bad" code that won't work on other machines to make it work. That doesn't mean "the bad code is sometimes good". That means "I need to fix the problem with my network configuration so the code that works everywhere else can work on my machine." So I need to see what you did to "fix" it to maybe gain some insight into what went wrong.

    Otherwise every bit of code I write will be broken on your machine, and you'll have to solve the, 'How do I tweak it to make it work?' game. That is a tiring game of 20 questions where almost none of my experience helps me help you. I don't want to play that game and don't want to write more code examples until the code that works on 99% of computers also works on yours.
    Last edited by Sitten Spynne; Oct 16th, 2017 at 09:24 AM.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  6. #86

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    Post #54 is one of your own posts.
    Ah... Yeah, I just checked, I don't know how that happened... Ought to've been post# 57.


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

  7. #87

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    As usual: "I had to build in a short delay" means nothing to me. When you speak in paragraphs I can't understand you. When you show me code, I can comprehend.

    I say this because "when something is broken", we have to write "bad" code that won't work on other machines to make it work. That doesn't mean "the bad code is sometimes good". That means "I need to fix the problem with my network configuration so the code that works everywhere else can work on my machine." So I need to see what you did to "fix" it to maybe gain some insight into what went wrong.

    Otherwise every bit of code I write will be broken on your machine, and you'll have to solve the, 'How do I tweak it to make it work?' game. That is a tiring game of 20 questions where almost none of my experience helps me help you. I don't want to play that game and don't want to write more code examples until the code that works on 99% of computers also works on yours.
    I thought I'd fixed it, so code wasn't required. But you're right it's likely to be a 'Fix' rather than a solution, so first the code which didn't work, or rather the code which stopped working.

    I'm trying to avoid having to start with the decision 'Server or Client' so my project starts in Server mode but looks to see if any computers are active on the LAN (Same router). If one or more is found there's an option to choose which computer to try to connect to. Here there's only my missus and I so there's only ever one other computer, but doing it that way means that if we know the other has the game (to be) open either of us can start it.

    Currently Form1 contains just:
    1: ListBox. to display active computers. (excluding the host machine) thus '192.168.0.3. iKi_Lappy' (Address Space Name)
    1: TextBox. to display status.
    3: Buttons.
    'Exit'.
    'Start' (Look for other computers).
    'Test' Will be used to try communications.

    This is the previous code to connect to the other computer:
    Code:
        Private Sub Get_Clnt()
            palPC = New TcpClient()
            C_Token = palPC.BeginConnect(Pal, Port, AddressOf Got_Clnt, Nothing)
    
        End Sub 'Connect to Client.
        
        Private Sub Got_Clnt(ByVal state As Object)
            Try
                palPC.EndConnect(C_Token)
                C_Token = Nothing
                TextBox1.Text = vbCrLf & "Connected to " & palName
            Catch ex As Exception
                Dim txt As String = vbCrLf & "Sorry... Not connected !" & vbCrLf & vbCrLf
                UpDate_T(txt & "Listening for Friend")
                StartServer()
            End Try
    
        End Sub ' Connected to Client... Or not.
    This used to work almost immediately if the Win.7 machine tried to connect, but got to be that if the Win.10 machine tried to connect it didn't, although it did in fact connect some five or so seconds later. I'm pretty sure it worked at first before I started trying to actually use it.

    This is how the code is now, I've added other parts so that you can see (what I hope is all) the relevant bits.
    Code:
        Private Sub Lbx1() Handles ListBox1.SelectedValueChanged
            '       I am now the Client !
            Dim LbxS As String = CType(ListBox1.SelectedItem, String)
            Dim Splt() As String = Split(LbxS)
            Dim Adr As String = Splt(0).Substring(0, Splt(0).Length - 1)
            SvrStop()
            Pal = IPAddress.Parse(Adr)
            palName = Splt(3)
            TextBox1.Text = vbCrLf & "Trying to connect to " & palName
            TextBox1.Refresh()
            Get_Clnt()  '   Connect to Server
            GameStart()
    
        End Sub ' Make me the Client!
    
        Private Sub Get_Clnt()
            palPC = New TcpClient()
            C_Token = palPC.BeginConnect(Pal, Port, AddressOf Got_Clnt, Nothing)
    
        End Sub ' Client: Connect to Server.
    
        Private Sub Got_Clnt(ByVal state As Object)
            Try
                palPC.EndConnect(C_Token)
                C_Token = Nothing
            Catch ex As Exception
            End Try
    
        End Sub ' Client: Connected to Server... Or not.
    
        Private Sub SvrStop()
            Try
                S_Ears.Stop()
            Catch ex As Exception
            End Try
    
        End Sub ' Server: Stop listening.
    
        Private Sub GameStart()
            System.Threading.Thread.Sleep(6000) ' Allow time for 'Pal' to connect.
            If palPC.Connected Then
                TextBox1.Text = vbCrLf & "Connected to " & palName
                ListBox1.Dispose()
                Button2.Visible = False
                Button3.Visible = True
            Else
                Dim txt As String = vbCrLf & "Sorry... Not connected !" & vbCrLf & vbCrLf
                UpDate_T(txt & "Listening for Friend")
                StartServer()
                Exit Sub
            End If
    
        End Sub ' Both connected.
    Poppa.
    Along with the sunshine there has to be a little rain sometime.

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

    Re: Trying to connect to second Laptop.

    Yes. This is definitely a case of "doing the wrong thing and fixing it with wrong code".

    The word "asynchronous" means the idea of two things happening at the same time, in parallel. When you call code that is asynchronous, you are saying, "Start doing this, but let me keep going. Call me when you are finished." Let me try to express it with analogy, then tie it back to the code you wrote.

    Suppose you need to do two things today. You need to buy some groceries, and you need to watch a movie with your wife. The movie you want to watch is at the Redbox machine at the grocery store. She hands you a grocery list and says, "Please go to the store for me." That's BeginShopping(). Now one of two things can happen. Let's look at the code.


    That paragraph looks like this:
    Code:
    Sub DoThings()
        you.Items.Add(groceryList)
        you.BeginShopping(AddressOf EndShopping)
    
        wife.DoSomething()
    
        wife.TakeMovie() ' CRASH: you aren't even in the house anymore.
        wife.WatchMovie()
    End Sub
    
    Sub EndShopping()
        you.GiveMovieToWife()
        you.WatchMovie()
    End Sub
    Maybe the "DoSomething()" your wife does takes a long time. If it does, you might get back from shopping before she finishes. So by the time she does "TakeMovie()", you're back with the movie and it all works. This is what's happening on one of your PCs.

    But what if the "DoSomething()" is really quick, and she tries to TakeMovie() before you get back? You aren't there, so there's no movie, so the program crashes and the universe ends. Oops.

    So when you write asynchronous code, you have to make sure if something assumes the code is finished, it doesn't happen until AFTER the thing finishes:

    Code:
    Sub DoThings()
        you.Items.Add(groceryList)
        you.BeginShopping(AddressOf EndShopping)
    
        wife.DoSomething()
    End Sub
    
    Sub EndShopping()
        you.GiveMovie()
        wife.TakeMovie()
        you.WatchMovie()
        wife.WatchMovie()
    End Sub
    Back to your code.

    When you call BeginConnect(), you are telling the computer: "Go try to make a connection on another thread. Don't call me back until there is an error or it has finished." The method "Got_C1nt()" will be called from that other thread when it finishes.

    But your code barrels onwards and calls GameStart(), which assumes you've already finished making the connection. On one PC, the connection finishes fast enough that this is true by accident. On the other PC, it takes a little while longer, and GameStart() rightfully complains the connection isn't ready yet. When you add a Thread.Sleep(), you cause GameStart() to wait long enough for the connection to happen.

    But that defeats the purpose of using asynchronous code at all.. The whole point is "I don't want to freeze the UI thread", and nothing freezes the UI thread quite like Thread.Sleep().

    This is what your code should look like:
    Code:
    Private Sub ListBox1_SelectedValueChanged() Handles ...
        ' blah blah parsing code
        TextBox1.Text = vbCrLf & "Trying to connect to " & palName
        Get_C1nt()
    End Sub
    
    Private Sub Get_C1nt()
        palPC = New TcpClient()
        C_Token = palPC.BeginConnect(...)
    End Sub
    
    Private Sub Got_C1nt()
        Try
            palPC.EndConnect(C_Token)
            C_Token = Nothing
    
            Me.Invoke(AddressOf GameStart)
        Catch ex As Exception
            MessageBox.Show("Don't ever let me see an empty Catch again.")
        End Catch
    End Sub
    
    Private Sub GameStart()
        ...
    All I did was move the GameStart() call from the initial event handler to the thing that is called after the connection completes. I did add the call to Invoke(), because I know that will be on a worker thread and GameStart() wants to be on the UI thread.

    Remember: calling BeginConnect() is not "Make the connection and wait for it to finish." It is "Make the connection and call me back when you finish." IIRC the whole reason we started down this rabbit hole was, "Why does the UI freeze?" Any time you say, "Wait", it will freeze. Getting around UI freezes involves finding ways to say, "Do this and call me back when you finish." It's the difference between "going to the grocery store" and "getting the groceries delivered".
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  9. #89

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

    Re: Trying to connect to second Laptop.

    OK, I take that point, I thought Get_Clnt() would only complete after Got_Clnt() completed. (Obviously didn't think hard enough).

    I've added a new button and now only startServer with that button so that I could remove the 'StopServer' subroutine and just stop the server where you stop it in the original code, because that subroutine wasn't stopping the server... I hope this is a temporary measure.

    In both machines I have VS2017 fully up-to-date, what I do is:
    Modify the project, (usually on the Win.10 machine), run it to build the .exe file, then copy that file onto a 'USB memory stick'. Then, using the 'stick' I test the project between the two computers. If that fails to work correctly I copy the whole project folder onto the other machine, build it and run it in Debug from there... Oughtn't to make a difference but I do it 'just in case'. I don't recall a time when it did make a difference.

    So, I'm back to my original problem, back where I was quite a long time ago. Which, as has been suggested several times before, may be a function of a firewall or anti-virus application.

    I open the project on the Win.10 machine, leave it in Server mode... Listening. Then open the project on the Win.7 machine and try to connect and it connects seemingly instantly. Then exit applications on both machines, reopen both, this time I leave the Win.7 listening and try to connect with the Win.10 machine which fails. From what you say with regard to 'StartGame' barreling on it may well be that there never was a connection in that direction, I was just fooled into believing there was. I haven't got around to trying to actually send data between the two machines yet, that's next once I've got the connection working both ways.

    I've tried looking at the firewall (AVG Free) on the Win.7 machine (which I think is the logical machine to look at) I've tried to set my project as an exclusion, but I'm not at all sure I've done that correctly... The 'Help' isn't very helpful. It talks about webpage URLs, file paths, files and folders but I don't see how to enter another computer asking for a connection, so I've just entered the file name. I've also entered the five addresses '192.168.0.' plus 2 to 6. (Our computers are currently '192.168.0.2' and '192.168.0.3' ).


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

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

    Re: Trying to connect to second Laptop.

    Well, we've been in this spot before.

    Early in the thread, there were very simple programs, and part of their purpose was "run these to make sure network connectivity works". I vaguely remember telling the story that I keep them around because network code can be finicky, and it's useful to make sure there's not a real hardware issue before debugging. Go back and find one of those. That's more reliable than running some code that we're not sure works.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  11. #91

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    Well, we've been in this spot before.
    Early in the thread, there were very simple programs, and part of their purpose was "run these to make sure network connectivity works".

    Go back and find one of those. That's more reliable than running some code that we're not sure works.
    Hi,

    I did that two days ago, but I did it again this evening to be sure I remembered the test and the results correctly.
    I've been using the Form1.vb file from the zip file which you attached to post# 57, (correct number this time) Async Chat 2017.zip, as the basis for 'Just Connect' which, as the name suggests it was just supposed to check the connection...
    ...but it's grown a bit !

    The Async Chat 2017 project is still on both computers. I opened it on both, selected the Win.7 machine as the Server and clicked start. On the Win.10 machine I entered the address of the Win.7 machine (This is the direction which doesn't work with my code) selected Client, clicked Start and the Form1 heading on both said 'Chatting'. I sent a message both ways.

    Then I closed both app's and did the same again but swapped the Server and Client, again both worked properly. Which seems to suggest that the problem isn't either machine don't you think ?


    Poppa.
    Last edited by Poppa Mintin; Oct 17th, 2017 at 07:19 PM. Reason: Typo.
    Along with the sunshine there has to be a little rain sometime.

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

    Re: Trying to connect to second Laptop.

    Yep. It sounds like the problem is in the modified code. You keep describing it and saying what you did to it, but the only real way to describe code is to post it. The devil's in the details.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  13. #93

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    Yep. It sounds like the problem is in the modified code. You keep describing it and saying what you did to it, but the only real way to describe code is to post it. The devil's in the details.
    The Form1 is as previously described, Button3 starts invisible under ListBox1.

    Code:
    Imports System.IO
    Imports System.Net
    Imports System.Net.Sockets
    
    Public Class Form1
        Private C_Token As IAsyncResult
        Private S_Token As IAsyncResult
        Public check, MyIDnum As Int32
        Private Port As Int32 = 3000
        Public myID, Pal As IPAddress
        Public EarsEP As IPEndPoint
        Public HostName, MyName, palName As String
        Public palPC As TcpClient
        Public S_Ears As TcpListener
    
        Private Sub Form1_Load() Handles MyBase.Load
            TextBox1.Location = New Point(1, ListBox1.Height + 2)
            TextBox1.Height = Button1.Location.Y - TextBox1.Location.Y - 2
            Button1.Text = "Exit"
            Button2.Text = "Seek"
            Button3.Text = "Test"
            Button4.Text = "Wait"
            Me.Show()
            Me.TopMost = True
            WhoAmI()
            TextBox1.Text = "Seek:-    For Others" & vbCrLf & "Wait:-    For Friend"
            Me.Refresh()
        End Sub
    
    
    
        Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            '	Dont forget to dispose everything in here.
        End Sub
    
        Private Sub Button1_Click() Handles Button1.Click
            CloseMeDown()
        End Sub ' Exit.
    
        Private Sub Button2_Click() Handles Button2.Click
            TextBox1.Text = vbCrLf & "Please wait"
            TextBox1.Refresh()
            Dat = 0
            Button1.Focus()
            Button2.Visible = False
            Button4.Visible = False
            check = CInt(Val(TextBox1.Text))
            If check < 6 Then check = 6
            Seek()
        End Sub ' Start.   Temp !
    
        Private Sub Button3_Click() Handles Button3.Click 
            '	Test data swap in here.
            Me.Close()
        End Sub ' Message. 
    
        Private Sub Button4_Click() Handles Button4.Click
            Button2.Visible = False
            Button4.Visible = False
            TextBox1.Text = vbCrLf & "Listening for Friend"
            StartServer()
        End Sub
    
        Private Sub CloseMeDown()
            If Me.InvokeRequired Then
                Me.Invoke(Sub() CloseMeDown())
            Else
                UpDate_T("Closing !")
                Me.Close()
            End If
        End Sub
    
        Private Sub GameStart()
            TextBox1.Text = vbCrLf & "Connected to " & palName
            '   Won't need Listbox any further.
            ListBox1.Dispose()
            Button2.Visible = False
            Button3.Visible = True ' Enable comm's test
            Button4.Visible = False
        End Sub
    
        Private Sub Get_Clnt()
            palPC = New TcpClient()
            C_Token = palPC.BeginConnect(Pal, Port, AddressOf Got_Clnt, Nothing)
        End Sub ' Client: Connect to Server.
    
        Private Sub Got_Clnt(ByVal state As Object)
            Try
                palPC.EndConnect(C_Token)
                C_Token = Nothing
                If palPC.Connected Then GameStart()
            Catch ex As Exception
                Dim txt As String = vbCrLf & "Sorry... Not connected !" & vbCrLf & vbCrLf
                UpDate_T(txt & "Listening for Friend")
                StartServer()
            End Try
        End Sub ' Client: Connected to Server... Or not.
    
        Private Sub Lbx1() Handles ListBox1.SelectedValueChanged
            '       I am now the Client !
            Dim LbxS As String = CType(ListBox1.SelectedItem, String)
            Dim Splt() As String = Split(LbxS)
            Dim Adr As String = Splt(0).Substring(0, Splt(0).Length - 1)
            Pal = IPAddress.Parse(Adr)
            palName = Splt(3)
            TextBox1.Text = vbCrLf & "Trying to connect to " & palName
            TextBox1.Refresh()
            Get_Clnt()  '   Connect to Server
        End Sub ' Make me the Client!
    
        Private Sub Seek()
            Dim Echo, ipa, txt As String, pc As Int32, Yes As Boolean
            ListBox1.Items.Clear()
            For i = 2 To check
                pc = CInt(i * 100 / check)
                ipa = "192.168.0." & i.ToString
                Yes = My.Computer.Network.Ping(ipa)
                If i <> MyIDnum And Yes Then
                    Try
                        Echo = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
                        ListBox1.Items.Add(ipa & ".   " & Echo)
                    Catch ex As Exception
                        UpDate_T(ex.ToString)
                    End Try
                End If
                TextBox1.Text = vbCrLf & "Please wait" & vbCrLf & vbCrLf
                TextBox1.Text += "Seeking connections...  " & pc.ToString & "%"
                Me.Refresh()
            Next
            If ListBox1.Items.Count > 0 Then
                TextBox1.Text = "Please select"
            Else
                txt = "Sorry..." & vbCrLf & "No other computers found."
                txt += vbCrLf & vbCrLf & "Listen for a Player ?"
                TextBox1.Text = txt
                Button2.Visible = True
                Button4.Visible = True
            End If
        End Sub ' Find other computers.
    
        Private Sub StartServer()
            '       I am Server !
            Try
                EarsEP = New IPEndPoint(IPAddress.Any, 3000)
                Dim S_Ears As New TcpListener(EarsEP)
                S_Ears.Start()
                S_Token = S_Ears.BeginAcceptTcpClient(AddressOf SvrGot, S_Ears)
            Catch ex As Exception
                UpDate_T("StartServer" & vbCrLf & ex.ToString)
            End Try
        End Sub ' Start listening.
    
        Private Sub SvrGot(ByVal token As IAsyncResult)
            Dim ipa As String
            S_Ears = CType(token.AsyncState, TcpListener)
            palPC = S_Ears.EndAcceptTcpClient(S_Token)
            ipa = palPC.Client.RemoteEndPoint.ToString
            ipa = ipa.Substring(0, InStr(ipa, ":") - 1)
            Pal = IPAddress.Parse(ipa)
            palName = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
            UpDate_T(palName & " connected !")
            S_Token = Nothing
            ' Since we have a client connection, there's no good reason to keep listening!
            S_Ears.Stop()
            If Me.InvokeRequired Then
                Me.Invoke(Sub() GameStart())
            Else
                GameStart()
            End If
            '' Start listening for messages from the client.
            'ListenToClient(palPC)
        End Sub ' Connected to Server... Or not.
    
        Private Sub UpDate_T(ByVal txt As String)
            If Me.InvokeRequired Then
                Me.Invoke(Sub() UpDate_T(txt))
            Else
                TextBox1.Text = txt
                TextBox1.Refresh()
            End If
        End Sub
    
        Private Sub WhoAmI()
            Dim ad As New List(Of String)
            ad.Clear()
            HostName = Dns.GetHostName()
            Dim host As IPHostEntry = Dns.GetHostEntry(HostName)
            Dim ip As IPAddress() = host.AddressList
            Dim i As Int32
            For i = 0 To ip.Length - 1
                myID = ip(i)
            Next
            Dim ID As String = myID.ToString
            Dim spt() As String = Split(ID, ".")
            MyIDnum = CInt(Val(spt(3)))
        End Sub ' Get my name and address.
    
    End Class
    I don't like 'flooding' posts so usually I only post what I think is relevant.
    Note: Explaining 'check', temporarily set at 6 but can be set to the lowest number of addresses likely to be found on local LAN, can be adjusted without altering any code by typing in a new number before clicking 'Start'.

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

  14. #94

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

    Re: Trying to connect to second Laptop.

    Hmmm....

    I don't know what (or if) I've done.
    Code is working now !
    As far as it goes... Can start working on data transfer now.


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

  15. #95
    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
    Hmmm....

    I don't know what (or if) I've done.
    Code is working now !
    If you had posted the code here, we could tell you what you did. Now the opportunity to learn something has been lost.

    Post your code. It's not too much, and if I don't think I need to see it it's easier to skip the code blocks than it is to skim a paragraph.

    My psychic guess: your execute a ton of code per connection to, in a roundabout way, get a host entry for an IP. If anything goes wrong in that process, an exception is thrown, and GameStart() won't get called. (It's fairly likely, because there's not always a host entry for a given IP.) Because that exception is on a worker thread, the thread quits. Because that was a worker thread and not the main thread, the program doesn't crash. My advice:

    If the method is named SvrGot, it should Got the Svr, not "accept the client, try to get a hostname and fail completely if I can't, then start the game". I don't know what a Svr is or what it means to Got it, so this is how I'd write that snippet of code:
    Code:
        Private Sub WhenTcpClientConnects(ar As IAsyncResult)
            Dim listener = CType(ar.AsyncState, TcpListener)
            _remoteClient = listener.EndAcceptTcpClient(ar)
    
            ReportConnection()
    
            GameStart()
        End Sub
    
        Private Sub ReportConnection()
            Dim info = GetConnectionInfo()
            If info.WeirdInfo IsNot Nothing Then
                Debug.WriteLine("Got a weird connection: {0}", info.WeirdInfo)
            End If
    
            If info.Hostname IsNot Nothing Then
                Debug.WriteLine("Got a connection from {0} ({1})", info.Hostname, info.IPAddress)
            ElseIf info.IPAddress IsNot Nothing Then
                Debug.WriteLine("Got a connection from {0}.", info.IPAddress)
            End If
        End Sub
    
        Private Function GetConnectionInfo() As ConnectionInfo
            ' This means it was called at a time when there isn't a connection.
            If _remoteClient Is Nothing Then
                Return New ConnectionInfo()
            End If
    
            Dim result As New ConnectionInfo
            Dim remoteEndPoint = _remoteClient.Client.RemoteEndPoint
            Dim usefulEndPoint = TryCast(remoteEndPoint, IPEndPoint)
            If usefulEndPoint Is Nothing Then
                ' Not sure how you get a "not IP endpoint" but here we are.
                result.WeirdInfo = remoteEndPoint.ToString()
            End If
    
            result.IPAddress = result.IPAddress
    
            Try
                Dim hostEntry = Dns.GetHostEntry(result.IPAddress)
                result.Hostname = hostEntry.ToString()
            Catch ex As Exception
                ' Whoops, couldn't get the hostname.
                Debug.WriteLine("Failed to resolve a hostname.")
            End Try
    
            Return result
    
        End Function
    
        Private Class ConnectionInfo
            Public IPAddress As IPAddress
            Public Hostname As String
    
            Public WeirdInfo As String
        End Class
    Part of understanding what goes wrong in your code is adding exception handlers and debug output so it tells you when it fails. When you are working asynchronously, failures don't always crash the application. So it's even more important than it was before to be sure your program tells you when it's sick.

    That means writing more code. But compare the 5-10 minutes it took me to write that code to the amount of time you've spent debugging this program! Every line of code you write to catch errors and log or handle them is worth 15 minutes of debugging saved.
    Last edited by Sitten Spynne; Oct 18th, 2017 at 09:35 AM.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  16. #96

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

    Re: Trying to connect to second Laptop.

    Hi,

    Still trying to use what I've learned so far, Still struggling.

    I've started a new project, and putting up with the "OS problem" for now, since I can always connect in one direction.
    I'm trying to send just one Byte at a time, and although I don't actually need asynchronous, that's what I'm working with.
    Try as I might, I can't find anything on the web concerning TCP which doesn't either give examples of 'Chat' or give examples using the Console neither of which is what I'm after.

    Usually I code all my subroutines alphabetically by name followed by functions alphabetically, I find it easier to locate any particular code that way.
    For the purpose of this exercise, I've also separated the different sections. (I may continue to do that, I quite like it.)

    With reference to the code:

    The section headed 'Running' is where I'm having the problem, all the others are working to my satisfaction at the moment.
    As mentioned, I just want to send one byte so I've tried to modify the code to achieve that without all the checking and coding for message length... It's always just one byte.

    For the purpose of this test project I'm generating the one byte by using a TextBox in computer A, writing an integer to it, then I'm trying to send that number to the other computer, (B) with the intention of writing that number in the TextBox in that computer. Then in computer B, I was planning to take that number, increment it, and send it back to computer A, not exceeding 9 for this test.

    In computer A, watching Subroutine WrtStr...
    Code:
    clientStream.BeginWrite(out, 0, 1, AddressOf WrtDone, WrtStat)
    ...'out' has to be byte(), I believe I've achieved that, a bit of a wrangle I guess. (Sub B4_Click)
    Stepping through this sub' bit = "1", out(0) = 49. So far, so good.

    In computer B, watching Subroutine ReadData and with a BreakPoint set at...
    Code:
    Dim Data As AsyncReadState = CType(token.AsyncState, AsyncReadState)
    ...as (A) Sub' WrtDone completes,
    Control arrives at the BreakPoint, which I interpret as 'data has been received'.
    Stepping through, bytesRead = 0. Then, msg = "".

    I don't understand why that should be. I expect bytesRead = 1. and msg = "1".

    Full code:
    Code:
    Imports System.IO
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Drawing.Text
    
    Public Class Form1
        Private C_Token, S_Token As IAsyncResult
        Public MyIDnum, Port As Int32
        Public myID, Pal As IPAddress, EarsEP As IPEndPoint
        Public HostName, MyName, palName As String
        Public palPC As TcpClient, S_Ears As TcpListener
    
    
        Private Sub Form1_Load() Handles MyBase.Load
            Label1.Text = ""
            Button1.Text = "EXIT"
            Button2.Text = "Client"
            Button3.Text = "Server"
            Button4.Text = "Send"
            Button4.Visible = False
            Port = 3000
            WhoAmI()
        End Sub
    
    
        '               Close down.
    
        Private Sub B1_Click() Handles Button1.Click
            Me.Close()
        End Sub ' Exit Button.
    
        Private Sub CloseMeDown()
            If Me.InvokeRequired Then
                Me.Invoke(Sub() CloseMeDown())
            Else
                UpDate_L("Closing !")
                Me.Close()
            End If
        End Sub ' Exit game.
    
        Private Sub Gone()
            If Me.InvokeRequired Then
                Me.Invoke(Sub() Tell())
            Else
                Tell()
            End If
        End Sub ' Other computer has closed.
    
        Private Sub Tell()
            Dim txt As String = "The other player" & vbCrLf & "has gone !!"
            txt += vbCrLf & vbCrLf & "Closing Down."
            Label1.Visible = True
            Label1.Text = txt
            Label1.Refresh()
            Timer1.Start()
        End Sub ' Closing down message.
    
        Private Sub Timer1_Tick() Handles Timer1.Tick
            CloseMeDown()
        End Sub ' Auto Close.
    
        '               Start up.
    
        Private Sub B2_Click() Handles Button2.Click
            '   I will be Client.
            Label1.Text = "Please wait..."
            Label1.Refresh()
            Button2.Visible = False
            Button3.Visible = False
            Seek()
        End Sub ' Client Button.
    
        Private Sub B3_Click() Handles Button3.Click
            '   Does anyone want to play ?  I'll wait for a while.
            Button2.Visible = False
            Button3.Visible = False
            ListBox1.Dispose()
            Label1.Text = "Waiting"
            StartServer()
        End Sub ' Server Button.
    
        Private Sub Clnt_Found(ByVal state As Object)
            Try
                palPC.EndConnect(C_Token)
                C_Token = Nothing
            Catch ex As Exception
                MsgBox("Clnt_Found     " & ex.ToString)
            End Try
            If palPC.Connected Then
                If Me.InvokeRequired Then
                    Me.Invoke(Sub() GameStart(True))
                Else
                    GameStart(True)
                End If
            Else
                UpDate_L("Sorry... " & palName & " did not accept!")
            End If
        End Sub ' Client: Connected to Server... Or not.
    
        Private Sub Find_Clnt()
            palPC = New TcpClient()
            C_Token = palPC.BeginConnect(Pal, Port, AddressOf Clnt_Found, Nothing)
        End Sub ' Client: Connect to Server.
    
        Private Sub GameStart(ByVal ok As Boolean)
            If ok Then
                Beep()  ' Remote 'I've connected'   :)
                ListBox1.Dispose()
                ListBox2.Dispose()
                Label1.Text = "OK connected to " & palName
                Button4.Visible = True
            End If
            PC_Ears(palPC)
        End Sub ' Connection established.
    
        Private Sub Lbx1() Handles ListBox1.SelectedValueChanged
            '       I am now the Client !
            Dim N As Int32 = CInt(ListBox1.SelectedValue)
            Dim Adr As String = CType(ListBox2.Items(N), String)
            Pal = IPAddress.Parse(Adr)
            palName = CType(ListBox1.Items(N), String).Trim
            Label1.Text = vbCrLf & "Inviting  " & palName & "  to play."
            Label1.Refresh()
            Find_Clnt()  '   Connect to Server
        End Sub ' Make me the Client!
    
        Private Sub StartRead(ByVal Data As AsyncReadState)
            Try
                Data.Stream.BeginRead(Data.Buffer, Data.LastOffset,
                        Data.Buffer.Length - 1, AddressOf ReadData, Data)
            Catch ex As Exception
                Gone()
            End Try
        End Sub
    
        Private Sub StartServer()
            '       I am Server !
            Try
                EarsEP = New IPEndPoint(IPAddress.Any, Port)
                Dim S_Ears As New TcpListener(EarsEP)
                S_Ears.Start()
                S_Token = S_Ears.BeginAcceptTcpClient(AddressOf Svr_Found, S_Ears)
            Catch ex As Exception
                MsgBox("StartServer" & vbCrLf & ex.ToString)
            End Try
        End Sub ' Start listening.
    
        Private Sub Seek()
            Dim Echo, ipa, txt As String, pc As Int32, Yes As Boolean
            ListBox1.Items.Clear()
            ListBox2.Items.Clear()
            For i = 2 To 12
                pc = CInt(i * 100 / 12)
                ipa = "192.168.0." & i.ToString
                Yes = My.Computer.Network.Ping(ipa)
                If i <> MyIDnum And Yes Then
                    Try
                        Echo = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
                        ListBox1.Items.Add("    " & Echo)
                        ListBox2.Items.Add(ipa)
                    Catch ex As Exception
                        UpDate_L(ex.ToString)
                    End Try
                End If
                Label1.Text = "Please wait." & vbCrLf & vbCrLf
                Label1.Text += "Seeking Players...  " & pc.ToString & "%"
                Me.Refresh()
            Next
            If ListBox1.Items.Count > 0 Then
                Label1.Text = "Please select a player."
            Else
                txt = "Sorry... No other computers found."
                txt += vbCrLf & vbCrLf & "Listen for a Player ?"
                Label1.Text = txt
            End If
        End Sub ' Find other computers.
    
        Private Sub Svr_Found(ByVal token As IAsyncResult)
            Dim ipa As String
            S_Ears = CType(token.AsyncState, TcpListener)
            palPC = S_Ears.EndAcceptTcpClient(S_Token)
            ipa = palPC.Client.RemoteEndPoint.ToString
            ipa = ipa.Substring(0, InStr(ipa, ":") - 1)
            Pal = IPAddress.Parse(ipa)
            palName = System.Net.Dns.GetHostEntry(ipa).HostName.ToString
            S_Token = Nothing
            S_Ears.Stop()
            If Me.InvokeRequired Then
                Me.Invoke(Sub() GameStart(True))
            Else
                GameStart(True)
            End If
        End Sub ' Connected to Server... Or not.
    
        Private Sub WhoAmI()
            Dim ad As New List(Of String)
            ad.Clear()
            HostName = Dns.GetHostName()
            Dim host As IPHostEntry = Dns.GetHostEntry(HostName)
            Dim ip As IPAddress() = host.AddressList
            Dim i As Int32
            For i = 0 To ip.Length - 1
                myID = ip(i)
            Next
            Dim ID As String = myID.ToString
            Dim spt() As String = Split(ID, ".")
            MyIDnum = CInt(Val(spt(3)))
        End Sub ' Get my name and address.
    
    
        '                   Running.
    
        Private Sub B4_Click() Handles Button4.Click
            ' Increment 'Byte to send'.
            TextBox1.Text = (CInt(Val(TextBox1.Text)) + 1).ToString
            TextBox1.Refresh()
            WrtStr(palPC.GetStream, TextBox1.Text)
        End Sub ' Send Button.
    
        Private Sub ReadData(ByVal token As IAsyncResult)
            Dim Data As AsyncReadState = CType(token.AsyncState, AsyncReadState)
            Try
                Dim bytesRead As Integer = Data.Stream.EndRead(token)
            Catch ex As Exception
                Gone()
                Exit Sub
            End Try
            Dim msg As String = System.Text.Encoding.ASCII.GetString(Data.Buffer, 1, Data.ProtocolLength)
            UpDate_L(msg)
            UpDate_T(msg)
        End Sub ' Data arrived.
    
        Private Sub PC_Ears(ByVal PC As TcpClient)
            Dim Data As New AsyncReadState(1, PC.GetStream())
            If Label1.Text = "Sent" Then
                UpDate_L("Sent " & TextBox1.Text & vbCrLf & vbCrLf & "So now I'm Listening")
            Else
                UpDate_L("I'm Listening")
            End If
            StartRead(Data)
        End Sub ' Listen to PC Stream.
    
        Private Sub WrtStr(ByVal clientStream As NetworkStream, ByVal txt As String)
            Dim bit As Char = CChar(txt)
            Dim out(0) As Byte
            out(0) = CByte(AscW(bit))
            Dim WrtStat As New AsyncWriteState() With {
                .Message = CType(out(0), String),
                .Stream = clientStream
            }
            Try
                clientStream.BeginWrite(out, 0, 1, AddressOf WrtDone, WrtStat)
            Catch ex As Exception
                Gone()
            End Try
        End Sub ' Send Byte. 
    
        Private Sub WrtDone(ByVal token As IAsyncResult)
            Dim state As AsyncWriteState = CType(token.AsyncState, AsyncWriteState)
            state.Stream.EndWrite(token)
            If token.IsCompleted Then
                UpDate_L("Sent")
                PC_Ears(palPC)
            End If
    
        End Sub ' Byte Sent.
    
        '                   Text updates.
    
        Private Sub UpDate_L(ByVal txt As String)
            If Me.InvokeRequired Then
                Me.Invoke(Sub() UpDate_L(txt))
            Else
                Label1.Text = txt
                Label1.Refresh()
            End If
        End Sub
    
        Private Sub UpDate_T(ByVal txt As String)
            If Me.InvokeRequired Then
                Me.Invoke(Sub() UpDate_T(txt))
            Else
                TextBox1.Text = txt
                TextBox1.Refresh()
            End If
        End Sub
    
        '   End Of Subroutines And Functions
        '____________________________________________
    
        Private Class AsyncReadState
            Public Property Buffer() As Byte()
            Public Property LastOffset As Integer
            Public Property Stream As NetworkStream
            ' 0 until the length has been read
            Public Property ProtocolLength As Byte
    
            Public Sub New(ByVal bufferSize As Integer, ByVal stream As NetworkStream)
                ReDim Buffer(1)
                'ReDim Buffer(bufferSize - 1)
                Me.Stream = stream
                ProtocolLength = 0
            End Sub
    
        End Class
    
        Private Class AsyncWriteState
            Public Property Message As String
            Public Property Stream As NetworkStream
    
        End Class
    
    End Class
    Form1.
    4 x Button.
    2 x ListBox. (ListBox2.Visible = False)
    1 x Label.
    1 x TextBox.
    1 x Timer.


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

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

    Re: Trying to connect to second Laptop.

    Streams can be fussy things in .NET if you aren't used to wrangling them. The convenient part is they behave the same way for both files and network operations.

    When you "write to" a Stream, you're really moving bytes into a buffer. They might get sent immediately, they might not. When you Close() the Stream, it knows you're done, so if it had any data left over it will write that out then close itself. I don't see where you close your stream.

    Maybe that's it. That's all I can see in there. The reason I mentioned naming and organizational conventions is it helps me read your code. "Send and/or recieve a single byte at a time" ought to be about 50 lines of code, but there's 300 in there because you've got a lot of other features bolted on. Maybe those are the problem, maybe not.

    It takes a lot of mental energy for me to remember what " P̶̾̇̓͏͎̼͍C̩͎͕̖͚̰̿̅́́͟_̧̛̪͍̥ͪ̿̔̊ͨͪ̍͘É̡̙̯̽͒́͡à̧̬̯ͫ̿̆ͅr̵̢̮̦̬̪̪͔̃̔s̶̡̙̝̔ͭͨ͜(̗̜͚̱ͥ͐̃ͭ̈͐)̷̝̠̞̓͗͗̿̌ͭ̈́ ͡" does, and where it's located. It's going to take pencil and paper to navigate all of this. The best thing to do when you have a lot of complexity and can't seem to make it work is to start stripping away the complexity. Why did you choose to use asynchronous reads/writes for single-byte transactions? That adds a lot of cognitive overhead for no real benefit. I'd start by chopping out all the "f͎̫͙̱̯͖̥ͨ͂̂̋̍̚ͅỉ͎̭̠̤̫̝̓̀͡n̸͙̱̭̉͐̊ͯ̈́ͫ̄̚͜͞d̩̰̜̺̺̊͛͗̉̂ͪ̓̈́͡ ̵̧̫̥̪͔͓̜̣ͧ̾̋̿ͮ͋̂̃ȁ̷͎̬̪̚̕ ̧͚̬̬͎̙͚̉͂̽͢s̵͇̺͎̭̹̾̒ͣ̓͗̐ͅȅ̢̤͇͚ͅr̪̳̰̉ͬ̅̑̂͐ͤ̚v̜̗̝͚̘̰͑́ͩ̑ͧ̏̀ẹ̡̝̹̍̐͆͟ȑ̶̸̵̹̪̣̟̍̉̃ͧ͑ͥ" junk, the timer that auto-closes the form, and anything not related to "send and receive 1 byte".

    At some point all the extra cognitive load feels a little like malice. Ever seen Kitchen Nightmares? It's a show where Gordon Ramsay goes to a failing restaurant to train them to be a successful restaurant. Almost every episode, there's a part where the person who called him for help tells Ramsay to his face they know food better than he does and they're not going to take his advice. He's walked out on restaurants before. That's kind of where I'm sitting. If I say "do this, it really helps" and I'm met with "I don't think that's important", I start to question why I'm spending 20+ hours writing tutorials.

    If this was a "simple demo app" it would have 1 label and 1 button. Maybe 2 buttons. There's a reason tutorials are all console applications or chat applications: they are conceptually simple!

    I don't know how to help you and I don't know where to start. This is a thread filled with functional examples, but none of the code you've written in the last month looks like the examples.

    Maybe start there. Go fetch an example and get that running. If you can't, then the problem is the network issues we've been telling you to diagnose. VB can't work around those. You have to figure out what's up with your own network and fix that. It is a monumental waste of time to ask questions about why your code isn't working if you can't prove the simplest expression of the idea works 100% of the time on your network. It's like calling tech support when the computer is unplugged.
    Last edited by Sitten Spynne; Nov 1st, 2017 at 12:26 PM.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  18. #98

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    When you "write to" a Stream, you're really moving bytes into a buffer. They might get sent immediately, they might not. When you Close() the Stream, it knows you're done, so if it had any data left over it will write that out then close itself. I don't see where you close your stream.

    Maybe that's it. That's all I can see in there.
    I was wondering about that... I'll test it out when SWMBO's finished with her laptop.

    Why did you choose to use asynchronous reads/writes for single-byte transactions? That adds a lot of cognitive overhead for no real benefit.
    I couldn't find anything to explain how to do it synchronously, except using the console. Until the one which you showed me I'd never used console applications... I didn't even know they existed. I had a go at converting a console application to a Windows one but got far too bogged down, and more than a little tired of 'Option strict doesn't allow'.
    I really didn't want to bother you to go back over the stuff you'd already sent so I tried to figure it out.
    I'd start by chopping out all the "Find a server" junk, the timer that auto-closes the form, and anything not related to "send and receive 1 byte".
    It started out that way. for whatever reason the LAN addresses of these two laptops seem to change, almost on a daily basis, since I had code to detect them, it seemed like a good idea to use it to save having to keep changing the addresses each day.

    I'll go back to the previous version and just put-up-with having to change the addresses. (Or just type 'em in every time I run the code... another pain in the arm)

    Thanks for the reply... you must be getting tired of me by now.


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

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

    Re: Trying to connect to second Laptop.

    I wasted a lot of the afternoon on two drafts that were way too big, but I do want to say some "not code" things before I come back fresh tomorrow and decide what to do.

    You find a lot of console applications because they are really simple, synchronous ways to demonstrate a concept.

    Think about describing a game of checkers. Red player moves. Black player moves. Red player moves. And so on. Any board state has a clear set of moves that leads to it. You always know whose turn it is, and there's no way for play to get interrupted or go in a different order.

    That is how most console applications work. ReadLine() says "it's the user's turn, I need some data". When they press Enter, it's the computer's turn until the next time it needs input. You might add a menu that lets people do different things in a different order, but it's still a lot like checkers: "Choose a menu item. Give me input. I do calculations and show you the output. Repeat."

    Console applications are also nice in that they read "top to bottom". You start at the top of Sub Main(), and they run their lines in order until they reach the bottom. You only tend to go "backwards" if there's some clear construct like a loop. You certainly don't jump around the file willy-nilly.

    Windows Forms is a nightmare compared to that.

    First, there are multiple files to edit. You have a designer and a code file. So before we start you have to go drop controls onto the designer, configure their properties, double-check their names, etc.

    Next, you need to paste in the code. Where does execution start? Well, it could be Sub New(). Or there could be a Load handler. Or a Shown handler. Some controls have TextChanged or similar handlers that might be raised as their properties are initialized. Timers might be started, and could elapse before the Form's even finished displaying. Any number of these handlers might run in any order, and if conditions are right they might happen in a different order every time you run the form! They can be at the top of the file, in the middle, at the bottom, scattered throughout. A Load handler doesn't have to be named "Form1_Load", some trickster might have named it "MeepMorp" or "RunMeFirst" or something else.

    The same's true of event handlers that DON'T run at startup. If there's 4 buttons on the form, is there an order in which I expect them to be clicked? Maybe some are disabled in certain states. What are those states? When do they become enabled? Do some of them then become disabled again? The answers to these questions may be in the designer. They may be in the code. If they're in the code, they could be at the top, bottom, or middle of the file. They could be scattered everywhere. If there are other forms in the project, sometimes people let those forms change these buttons' state.

    So even before we start talking about asynchronous code, WinForms is a mess. A console application might be Sub Main and 5 or 6 helpers. A WinForms equivalent could easily be 10 or 15 different event handlers mixed with those 5 or 6 helper routines. In a console application we usually expect top-to-bottom code flow. In WinForms, control jumps between all parts of the file sporadically as the user makes changes to controls.

    WinForms is more like dodgeball. There are many players on the field, but maybe just one ball. So we have a rough idea of who is on "offense", but it's hard to describe how we got into any particular game state.

    But that's a *simple* WinForms application. In dogeball, you want to throw the ball and pass control around quickly. Now imagine what happens in a game of dodgeball if someone picks up the ball and refuses to throw it. The game grinds to a halt. The end. If no one throws, no one can be hit, so there's not much of a game. This is what happens when you try to write something with networking in a plain old Windows Forms application. Someone gets the ball and holds it for a long time. No one else can do anything.

    So asynchronous Windows Forms is more like hockey. Lots of players are moving about simultaneously. But we don't tend to care about what all of the players are doing, action follows the puck. No one "gets the puck first", it hits the ice and people FIGHT for it. Which player has it? Where's it going to go? What happens after that? We can't predict it. In the end, the highlights of a hockey game represent maybe 3-5 minutes of the whole ordeal. But the only way to get those 3-5 minutes is for a lot of people to skate about chaotically.

    That 5-10 event handler WinForms app will have 10-30 methods in it by the time we make it appropriately asynchronous. Now we not only have to deal with "there are four buttons and I need to make sure you can only click them in the right order", you have to handle "clicking this button starts this process, and you can't do X or Y until it finishes, but Z is still valid so..."

    That's why you don't see a lot of networking WinForms examples. You pretty much can't write interesting synchronous network applications in WinForms. But even synchronous networking code is very complicated and prone to external failures. So when they're trying to teach you "here are the basics of network code", they try to write it with as few of the scary parts as possible.

    And that's why I insist on good organization. It is hard as heck to keep track of even a moderately simple app's structure. You do NOT want your Form to behave like this:
    Code:
    10 I = I + 1
    20 GOTO  50
    30 I = I * 3
    40 GOTO 70
    50 I = I + 2
    60 GOTO 40
    70 PRINT I
    Can you see the potential mistake in that code? How long did it take you?

    You should write WinForms code top to bottom, with Load/Shown and other startup code at the top. If Button1 does a thing, that does a thing, and that starts something asynchronous that finishes, it should look like:
    Code:
    Sub Button1_Click()
    
    Sub DoAThing()
    
    Sub StartTheSecondThing()
    
    Sub WhenTheSecondThingFinishes()
    Your life is hard enough without organizing it this way:
    Code:
    ' Actually this is last
    Sub AardvarkCaught()
    
    ' This is the second thing
    Sub BreakGlass()
    
    ' START HERE!
    Sub MeepMorp() Handles Button1.Click
    
    ' This is the third thing
    Sub StartCatchingAardvark()
    That may be alphabetical, but it doensn't make any sense. I have to scroll down a lot to find the first thing. Then I have to go back up? Then I have to go to the bottom? Then I go to the top? It's like you had a book neatly arranged, then dropped it, and the chapters got mixed up.

    Don't do that. Even when you use bad names, maintaining a "top to bottom" order can make things a lot more clear.

    Tomorrow I'm going to think about this again. Maybe if we try something that isn't networking for a little while, the concepts will become a little more clear. You know what works a lot like networking? File I/O. It uses streams and has the same API. You know what can't get screwed up by a router? File I/O.

    You know what else would make life easier? If we quit using the godawful IAsyncResult pattern. You were hesitant to take on Tasks with lambdas earlier, but in the end I think it's easier to wrap your head around them.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  20. #100

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    When you "write to" a Stream, you're really moving bytes into a buffer. They might get sent immediately, they might not. When you Close() the Stream, it knows you're done, so if it had any data left over it will write that out then close itself. I don't see where you close your stream.
    Hi again, I've been looking into this... I think you'll find I Close() the write stream in...
    Code:
    Private Sub WrtDone(ByVal token As IAsyncResult)
            Dim state As AsyncWriteState = CType(token.AsyncState, AsyncWriteState)
            state.Stream.EndWrite(token)
            If token.IsCompleted Then
                UpDate_L("Sent")
                PC_Ears(palPC)
            End If
        End Sub ' Byte Sent.
    I struggled with this because I originally just copied from WindowsApp17...
    Code:
        Private Sub WhenWriteFinishes(ByVal token As IAsyncResult)
            Dim state As AsyncWriteState = token.AsyncState
            state.Stream.EndWrite(token)
    
            AppendMessage("< " & state.Message)
        End Sub
    I don't actually see anything in the nature of 'End.Write' anywhere but I assumed...
    Code:
    state.Stream.EndWrite(token)
    ...did that.

    As the 'WindowsApp17' code only works with Option Strict OFF, maybe changing the code to appease intellisense has somehow rendered it inoperative ?


    Poppa.


    PS. Just seen your last post, thanks I'll try to remember that.

    Pop.

    PPS.
    Smiles... Not see 'GoTo' in many a year, very nostalgic.

    Pop.
    Last edited by Poppa Mintin; Nov 1st, 2017 at 07:31 PM. Reason: PS added. PPS added.
    Along with the sunshine there has to be a little rain sometime.

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

    Re: Trying to connect to second Laptop.

    EndWrite() is like every other EndSomething() method in this thread. The "End" has nothing to do with Writing, the "End" has to do with the "Begin" you called before it.

    I think I used a grocery store analogy once. "BeginWrite()" is "go to the store". "End Write()" is "call me when you get there". Let's say you had this not-closing code:
    Code:
    Sub DoNotClose(s As Stream)
        s.Write(some stuff)
    End Sub
    The asynchronous version is conceptually like:
    Code:
    Sub DoNotCloseAndCallMeLater(s As Stream)
        Dim state = New WriteState(s, ...)
        s.BeginWrite(state, AddressOf WhenDoNotCloseCallsBack, ...)
    End Sub
    
    Sub WhenDoNotCloseCallsBack(iar As IAsyncResult)
        Dim state = CType(iar.AsyncState, WriteState)
        state.Stream.EndWrite(iar)
    End Sub
    A Close() isn't added by magic. EndWrite() just means "I'm ready to know when you're "done" writing.

    But "done writing" doesn't mean the stream has immediately sent all the bytes. Sometimes, especially when you make small writes, it seems to wait a little while. If you Close() the stream, it immediately pushes everything out, but then your connection is closed. I forgot to mention there is also a Flush() method that forces it to send everything without closing the Stream.

    Sometimes I need Flush(), sometimes I don't, it's inconsistent. If you want everything sent right away, it's probably worth following writes with it. I don't tend to remember it until something breaks.

    I'm only about 25% sure that's the issue here. I only consider Flush() after I've verified everything is connected, and usually what makes me realize this is the problem is I see a symptom like, "I don't get the data when I send it, but when the client calls .Close() on the stream THEN the data arrives.

    Which is why I said to Close() the Stream. It's a good, quick way to decide if Flush() might solve the problem.

    When I get around to a demo today, I'm going to use file I/O instead of network I/O as the demonstration first. That will remove a lot of the "Can I even connect?" complexity and help show off the patterns in a way that, when it fails, you can probably solve by "delete the file and start over".
    Last edited by Sitten Spynne; Nov 2nd, 2017 at 07:31 AM.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by Sitten Spynne View Post
    ... I forgot to mention there is also a Flush() method that forces it to send everything without closing the Stream.

    Sometimes I need Flush(), sometimes I don't, it's inconsistent. If you want everything sent right away, it's probably worth following writes with it. I don't tend to remember it until something breaks.
    ...
    Things may have changed in later versions of the .Net framework, and I know you're using 2017. I tried looking at the later MSDN documentation and the wording is less clear.
    In 4.0 (VS2010 which we still use a fair amount at work) MSDN says
    The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams. Calling the Flush method does not throw an exception."
    And in the object viewer...
    System.Net.Sockets.NetworkStream
    Flushes data from the stream. This method is reserved for future use.
    In the current framework (4.7.1) it is mentioned in connection with being overridden...
    When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device.
    and
    When using the StreamWriter or BinaryWriter class, do not flush the base Stream object. Instead, use the class's Flush or Close method, which makes sure that the data is flushed to the underlying stream first and then written to the file.
    So, it appears that basic Networkstreams is still not buffered and Flush on the networkstream will not have any effect, but if you use Flush on a class that maintains a buffer (and therefore overrides the Flush method), then you can flush that buffer to the network stream.

    As far as " You pretty much can't write interesting synchronous network applications in WinForms", that is pretty much all I do write when dealing with intercommunication with multiple computers over Ethernet or Serial ports. Of course the vast majority (99+ %) of Ethernet intercommunication code I write uses UDP not TCP, (all LAN interactions, not Internet) so that is a significant difference in some of the mechanics.
    Using synchronous receivers running in background threads is certainly simpler to implement, and for some of us over 60 crowd this late in the game, simpler is a big plus.

    I did patch in some synchronous receivers in background threads into the code Poppa posted in post #96 and it works fine on my machine, with either application clicking on the increment button, and the other application getting the updated byte (changed to using a byte type, not an ASCII character being sent in a byte though). The interaction may not be Poppa's intent was (may have wanted turn based logic) and there is a lot of unused code now that I didn't remove. I would rather have a clean example to post but don't have the time. I don't want to step on what Sitten Spynne is doing since he is going to great lengths to educate here so I won't post the patched synchronous version of the code here (its not on this machine anyway, but on another machine that is a little harder to access at the moment).

    The primary reason I posted was just the info about flush on a networkstream, the synchronous input was just an aside, which was already mentioned in post #3 of this thread, and jmcihinney has already posted about the alternative to synchronous starting with post #7 and of course, in greater part by Sitten Spynne throughout this thread.

    Actually, if I was writing a multi-user game communication between users on a local network, I would just be using UDP anyway, not TCP.

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

    Re: Trying to connect to second Laptop.

    Honestly, passel's right. For simple back-and-forth, UDP is probably better. And I didn't think to dig into the documentation to see if NetworkStream.Flush() was a victim of "Microsoft is terrible at OOP design." Liskov Substitution Principle is important!

    Problem is, I tried writing an example and I hit some errors that tell me "I don't know what I'm doing" in this particular circumstance. It looks like it's a little tricky to get UDP working if you want to test on one machine using localhost. That's kind of a big deal for me, I don't have two Windows machines on the same network with which to test. I'm looking into it.

    Do you have any workable examples of soemthing that'll work on localhost, passel?
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  24. #104

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

    Re: Trying to connect to second Laptop.

    Hi,

    I have my code working...

    I took another look at the subroutine 'ReadData'.
    In general when I try a modification to some code, I copy and paste the line (or lines) I'm going to modify and 'comment out' the copy so that (a) I don't forget what was there originally and (b) I can go back to exactly how it was if the mod' fails.

    Code:
        Private Sub ReadData(ByVal token As IAsyncResult)
            Dim Data As AsyncReadState = CType(token.AsyncState, AsyncReadState)
            Try
                Dim bytesRead As Integer = Data.Stream.EndRead(token)
            Catch ex As Exception
                Gone()
                Exit Sub
            End Try
            Dim msg As String = Chr(Data.Buffer(0))
            'Dim msg As String = System.Text.Encoding.ASCII.GetString(Data.Buffer, 0, 1)
            ''Dim msg As String = System.Text.Encoding.ASCII.GetString(Data.Buffer, 1, Data.ProtocolLength)
            UpDate_L(msg)
            UpDate_T(msg)
        End Sub ' Data arrived.
    As you can see, the line to be modified is still 'commented out', and also the first modification.
    The line ''Dim msg... was the original line. Line 'Dim msg... was the first mod', which worked and (correctly) returned "1".
    Then I thought about it a little more and tried the line I'm using, which works correctly with whatever number is sent.


    Poppa.
    Last edited by Poppa Mintin; Nov 2nd, 2017 at 08:13 PM.
    Along with the sunshine there has to be a little rain sometime.

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

    Re: Trying to connect to second Laptop.

    Usually to interface to some application using UDP there is a known port that that one application, which could be considered the "server" side of the connection, expects communication on.
    In a lot of cases, the port they expect the connecting application to bind is also specified.
    So the "server" application may bind to 3000 and expect the client to bind to 3001.
    While that is quite common, that isn't technically the way UDP is designed to work.

    Normally for communication between two applications, while the "server" application binds to a known port, the client application can bind to any port it wants. When the client sends a packet to the server the server's socket automatically retains the address and port the packet came from. When the server uses that socket to send the packet, the return message is sent back to the sender it received the message from.
    This works fine if only two applications want to communicate with each other. If you want more than two applications to communicate, then either you follow the standard UDP protocol, i.e. since the transmitting socket will automatically send to the socket it received from, when you receive a message on the known port, you create a new socket with an arbitrarily bound port, and use that socket to respond. If the client doesn't override the received address and port, i.e. if it doesn't force sending to the known port, when it sends again it will send back to the new socket. You now have two way communication between the two applications using arbitrary ports, leaving the known port free to "listen" for more connections.

    But another approach I've taken when I know I'll have a lot of connections and I don't want to create a socket for each one, is to use the RemoteEndPoint of the "connecting" object as a dictionary key, and a class that keeps track of all the stuff we need to keep track of for the client as the value. In that case, I'll just use the one socket and use the RemoteEndPoint value that is saved to send data to a particular client.

    But, for now what would be a simple example of two instances (or more) of the same executable communicating between them.
    Normally multiple executables can't bind to the same protocol port. You can set an socket option to allow sharing a port, and what Windows does when you share a port vs what the Linux/Unix world does is different and it is probably best not to rely on the way Windows does it. There is the Multicast option, but while I have been in environments that dependend on using Multicast, I haven't had to write any VB code that uses it, so won't attempt to now.
    I have use broadcast quite often.

    I looked and I did have an early experiment of having multiple clients sending heartbeats to a "server" using UDP.
    This was an initial test to verify my concept of using a single socket on the server side to listen to and transmit to an unspecified number of clients by keeping track of the endpoints of the clients.
    The point of the experiment was to launch a number of the clients, I think we needed to support at least 16 simulated vehicles and verify the communication worked and to see if any UDP packets were lost using this scheme.

    The server side in this test doesn't have any controls. It just listens for new connections, adding them to a list, and increments a count for each message received for each client. It periodically transmits the message received count for each client back to the client.
    The client's display the count of how many messages they've sent, and how many messages the server says it has received for that client.

    You press the button on the clients to start sending messages or stop sending messages (starts or stops the timer). When you stop the timer, if the two labels have the same value that means no messages going from the client to the server were lost. I've never seen any packets lost on a Local Area Network and I've run over 75 UDP clients simultaneously.

    In case you're not aware Poppa, you can start multiple instances of a program from the IDE. I don't know if it has changed in VS2017, but in VS2010 in the solution explorer, if you right clicked on the Solution, you would go down to the "Debug" item of the menu, and select "Start New Instance". Of course, you may just want to compile the executable, then select it in explorer and press the Enter key a number of times to launch multiple instances of the client.

    You only run one instance of the Server, you can pick either machine to run it. You should be able to have multiple clients on both the remote machine and the local machine (where the server is running) at the same time. You can run them for a while and then press the button on various clients to stop them transmitting and see if you find any indication of lost packets using UDP on your network.

    What I'm thinking is you could have a "server" which you run. Then when you kick off the "game" playing application, it sends a message to the server, and the server registers it. If there are other machines registered, the server can send the info to the gamer and the gamer can select the remote machine using the endpoint received from the server to start an interactive session with that other gamer. If you want to have three or more players, then you would probably want the server to be the go between. It would receive a message from a client and retransmit the message to the other clients in that game.

    First the Server code. Just need a project, there are no controls associated with the server at this point, but you do need to add a timer component.
    This was early experimental code written a number of years ago, so I won't vouch for the quality, and there are probably some things I've learned since then, that I would might do differently.
    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Net.Sockets
    
    Public Class Form1
    
      Private Structure RemoteVehicleConnection
        Public IPandPort As IPEndPoint       'Identifys the client by its endpoint.
        Public HeartBeatCount As Integer     'Counts the messages received for this client
        Public HearBeatInputCount As Integer 'Holds Count received from client, not used for anything
        Public ID As String                  'Not used currently
      End Structure
    
      Dim rv As RemoteVehicleConnection
      Dim VehicleList As New List(Of RemoteVehicleConnection)
    
      Dim socketIn As New UdpClient(12321)                                'Listen on UDP port 12321
      Dim receiveThread As New Thread(AddressOf Receiver)
      Dim leaving As Boolean
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        receiveThread.IsBackground = True
        receiveThread.Start()
        Timer1.Enabled = True
      End Sub
    
      Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        leaving = True
      End Sub
    
      Private Sub Receiver()
        Dim remoteIP As New IPEndPoint(IPAddress.Any, 0)  'will hold who sent the data 
        Dim b() As Byte 'buffer to receive data
        Dim rvc As RemoteVehicleConnection
    
        Dim found As Boolean
    
        Do Until leaving
          Try
            b = socketIn.Receive(remoteIP)
            found = False
            Monitor.Enter(VehicleList) 'get exclusive access to the list
            For i As Integer = 0 To VehicleList.Count - 1
              With VehicleList(i)
                If IPEndPoint.Equals(.IPandPort, remoteIP) Then 'If it is already in our list
                  found = True
                  rvc = VehicleList(i)
                  rvc.HeartBeatCount += 1
                  rvc.HearBeatInputCount = BitConverter.ToInt32(b, 0)
                  VehicleList(i) = rvc
                  Exit For
                End If
              End With
            Next
            If Not found Then
              rv.IPandPort = remoteIP
              rv.HeartBeatCount = 1
              rv.HearBeatInputCount = BitConverter.ToInt32(b, 0)
              VehicleList.Add(rv)
              remoteIP = New IPEndPoint(IPAddress.Any, 0) 'need a new instance since we've added the previous to our list
            End If
            Monitor.Exit(VehicleList)
          Catch
          End Try
        Loop
    
      End Sub
    
      Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
    
        Monitor.Enter(VehicleList) 'get exclusive access to the list
        Dim b(7) As Byte
        For i As Integer = 0 To VehicleList.Count - 1
          With VehicleList(i)
            Buffer.BlockCopy(BitConverter.GetBytes(.HeartBeatCount), 0, b, 0, 4)
            socketIn.Send(b, b.Length, .IPandPort)
          End With
        Next
        Monitor.Exit(VehicleList)
      End Sub
    End Class
    Now the client code. Need a button, two labels and a timer.
    Code:
    Imports System.Threading
    Imports System.Net
    Imports System.Net.Sockets
    
    Public Class Form1
    
      Dim remoteHeartBeatRcvCount As Integer
      Dim localHeartBeatCount As Integer
    
      Dim socketIn As New UdpClient(0)  'passing 0 here, the system will assign a free port number, generally > 50,000
      Dim receiveThread As New Thread(AddressOf Receiver)
      Dim leaving As Boolean
    
      'use the broadcast address so will transmit to any server on the LAN
      'It could even be on the local computer
      Dim ServerEndPoint As New IPEndPoint(IPAddress.Parse("255.255.255.255"), 12321)
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        receiveThread.IsBackground = True
        receiveThread.Start()
      End Sub
    
      Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs)
        If Not leaving Then
          leaving = True  'Give the thread a chance to exit the receive loop gracefully
          e.Cancel = True 'and it will invoke the close as it exits to finish closing the application
        End If
      End Sub
    
      Private Sub Receiver()
        Dim remoteIP As New IPEndPoint(IPAddress.Any, 0)  'will hold who sent the data 
        Dim b() As Byte 'buffer to receive data
     
        Do Until leaving
          b = socketIn.Receive(remoteIP)
          remoteHeartBeatRcvCount = BitConverter.ToInt32(b, 0)
          Me.BeginInvoke(Sub() UpdateLabels())
        Loop
        Me.BeginInvoke(Sub() Close())
      End Sub
    
      Private Sub UpdateLabels()
        Label1.Text = localHeartBeatCount.ToString
        Label2.Text = remoteHeartBeatRcvCount.ToString
      End Sub
    
      Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
    
        Dim b(7) As Byte
        UpdateLabels()
        localHeartBeatCount += 1
        Buffer.BlockCopy(BitConverter.GetBytes(localHeartBeatCount), 0, b, 0, 4)
        socketIn.Send(b, b.Length, ServerEndPoint)
    
      End Sub
    
      Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Timer1.Enabled = Not Timer1.Enabled
      End Sub
    End Class
    Last edited by passel; Nov 2nd, 2017 at 11:03 PM.

  26. #106

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

    Re: Trying to connect to second Laptop.

    Quote Originally Posted by passel View Post
    In case you're not aware Poppa, you can start multiple instances of a program from the IDE. I don't know if it has changed in VS2017, but in VS2010 in the solution explorer, if you right clicked on the Solution, you would go down to the "Debug" item of the menu, and select "Start New Instance". Of course, you may just want to compile the executable, then select it in explorer and press the Enter key a number of times to launch multiple instances of the client.
    Thanks for this post Passel, I will make time to check it out, we're off on vacation for a while so it won't be until we're back.

    Regarding the part I've quoted, I did know I can start multiple instances of a program, but not from the IDE. I tried the route you suggest to find "Start New Instance" and found it still does as you say. Navigating the VS2017 IDE thus, Project > Properties > Application, there is a checkbox option: "Make single instance application". I don't know if this is new but I suspect not.


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

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

    Re: Trying to connect to second Laptop.

    No that isn't new. It adds code that checks if the application is already running when it starts up and exits if it is. That is sort of the opposite of being able to start debugging multiple instances.

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

    Re: Trying to connect to second Laptop.

    OK, yeah, duh. In my example I was trying to be client/server in one app. I'd found some dark incantations on StackOverflow that involved low-level configuration of the Socket to support it, but that didn't exactly scream, "You're doing this the right way!". I'll retool it to have a distinct client/server mode.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

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

    Re: Trying to connect to second Laptop.

    I was thinking of having a single app handle both, and I wrote up a design outline in a text file several weeks ago but I didn't flesh it out and try to code anything.

    One simple approach would be to have the application try to create a socket with the known port, and if it gets an exception, then it assumes another application got there first on this machine, so binds to a system supplied port and sends a connection message to known port to let the other application know it is there.

    If you're running on two machines, then they'll both bind to the same port on their respective machines without issue, but if you broadcast to try to connect to the "server", you'll pick up your own message in your receiver, so you would have to look for that and filter it out. Perhaps if you broadcast and get responses, you can note the address of the responses and then not broadcast again, but rather send to the specific IP of the machine you want, doing point to point and not needing to filter your own messages. When a new app comes on line it should broadcast once to get a list of servers out there and let the servers know it is there.

    Lots of possibilities.

Page 3 of 3 FirstFirst 123

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