0

I am developing a piece of scientific software in VB.net that I intend to distribute. Part of the application will involve communication with a server (and other clients). For all intents and purposes the communication will be like a chat application.

I have developed the software using sockets, and it works fine when testing at home on my local network. Below is basically how I send messages:

Dim serverIPString as String = "192.168.1.5"
Dim serverPort as long = 65500
dim messageString as String = "Hello"
Dim Client As New System.Net.Sockets.TcpClient(serverIPString, serverPort)
Dim Writer As System.IO.StreamWriter(Client.GetStream())

Writer.Write(messageString)
Writer.Flush()
Writer.Close()

And this is how I listen:

Public Class TCPIPListener
    Dim initalised As Boolean = False
    Dim port As Long
    Dim IP As System.Net.IPAddress
    Dim ourListener As TcpListener
    Dim ourClient As TcpClient
    Dim ourMessage As String

    '''''''''''
    '' ctors ''
    '''''''''''

    Public Sub New()
        initalised = False
    End Sub

    'Takes IP and port and starts listeing
    Public Sub New(inIP As String, inPort As Long, inExchange As messageExchange)
        'Try to set the IP
        Try
            IP = System.Net.IPAddress.Parse(inIP)
        Catch ex As Exception
            Exit Sub
        End Try

        'Set the port
        port = inPort

        initalised = startListener()

    End Sub

    '''''''''''''''
    '' Listening ''
    '''''''''''''''

    Private Sub Listening()
        ourListener.Start()
    End Sub

    'starts listener
    Public Function startListener() As Boolean
        ourListener = New TcpListener(IP, port)
        ourClient = New TcpClient()

        Dim ListenerThread As New Thread(New ThreadStart(AddressOf Listening))
        ListenerThread.Start()

        initalised = True

        Return True
    End Function

    'Called from a timer on the form
    Public Function tick() As Boolean
        If Not initalised Then
            Return False
        End If

        If ourListener.Pending = True Then
            ourMessage = ""

            ourClient = ourListener.AcceptTcpClient()

            Dim Reader As New System.IO.StreamReader(ourClient.GetStream())
            While Reader.Peek > -1
                ourMessage = ourMessage + Convert.ToChar(Reader.Read()).ToString
            End While

            messagebox(ourMessage)
        End If

        Return True
    End Function
End Class

Using this approach, every client will be listening for messages sent from the server, and any messages sent will go to the server and be directed to the relevant client - it's a little inefficient but necessary for the way my software works.

The problem is that I am having real trouble getting this to work across the internet. If I send a message to a local IP address it works fine, even from the debugger. If I use a external IP address I get the following:

No connection could be made because the target machine actively refused it XXX.XXX.XXX.XXX:65500"

I have turned on port forwarding with my router and set up the correct port (65500 here) to forward to my PC running the lister (192.168.1.5) for both TCP and UDP. This website it tells me this port is open, and those either side are not.

If I right click on the exe and run as administrator, my antivirus pops up and says it is doing something suspicious when I start the listener (which I guess if anything is encouraging). If I then add my application to the list of exceptions and run it again, then check to see if the port is listening (using this) I find my application listening on the correct port (if I stop the application it is gone). However the client application still gives the same error above. If I use a random IP address rather than the one of the listener I get a different error:

{"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond XXX.XXX.XXX.XXX:65500"}

I suspect I am not taking the correct approach to this. I am fine with most aspects of VB, but have not really tackled this sort of problem before. When it comes to distributing software I really don't want my customers to have to mess around with deep settings to get this application to work. Any help will be immensely useful to me!

Another problem I guess I will face in the future is if multiple clients have the same external IP but different internal IPs (I intend to distribute to universities). Under these circumstances I guess port forwarding will not work.

Thanks very much in advance (and apologies for the long post)!

Community
  • 1
  • 1
Johnboydump
  • 11
  • 1
  • 2
  • A client initiating a connection should use one of the random, ethereal ports as its source port. Only the server should have a defined port number. Once the client establishes a TCP connection, it should just keep it until the application is closed on the client. TCP is a bidirectional connection of peers (no clients or servers, which is an application concept, not relevant to TCP). This will avoid your problem with needing to port forward on both ends, and solve the problem with multiple clients behind one NAT address. – Ron Maupin Aug 30 '16 at 01:53
  • Ok thanks. Yeah, this makes sense; I can just store the TcpClients as they connect. This solves this part of the problem at least – Johnboydump Aug 30 '16 at 02:16

1 Answers1

1

If you set your server to listen for connections on 192.168.1.5 then it will only allow connections from that specific IP address. The address you give a TcpListener is the IP address which you will accept connections from.

Since the 192.168.1.5 address is internal no one outside your network will be able to connect to your server. Make your server listen to 0.0.0.0 (or the equivalent IPAddress.Any) instead to make it allow connections from anyone.

Visual Vincent
  • 17,424
  • 5
  • 24
  • 66