# VBForums CodeBank > CodeBank - Visual Basic .NET >  [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient

## jmcilhinney

Someone asked recently if there were any existing components out there that would allow them to send text messages between a client and server using the TcpClient without locking up the UI and without their having to learn the intricacies of the TcpClient class.  I don't know for sure but I'm guessing that the answer is "no", so I decided to create one.

I've attached the project below, so you're welcome to use the source code as a learning tool or as a basis for your own code.  If you do use the code, in part or in full, I don't require any recognition but I do require that you don't claim the code as your own creation.  You can also just compile the library and slot it straight into your own project as a black box if you don't care about how it works.

FEATURES:

* Uses TcpListener and TcpClient to provide communication between server and multiple clients.
* All connection, read and write operations performed asynchronously to avoid UI issues.
* Simple interface for send text messages, i.e. just call Send and specify the message.
* Server can send a message to a single client or all clients with a single method call in each case.
* Uses event model to provide notifications regarding connections and messages.
* Events can be raised in background threads or the UI thread simply by setting a property.
* Solution includes WinForms projects for testing server and multiple clients.
* Code demonstrates various techniques including inheritance, custom events, asynchronous programming and LINQ.

USAGE:

To test out the features you can simply open the project in VS and run it.  The test projects for the client and server will both run and present you with two windows: one for the server and one for the client.  Click the Connect button in the client window to connect to the server.

Both server and client provide a log window to notify you of all connection and communication events.  To send a message from the client to the server simply type into the TextBox at the bottom of the window and click the Send button.  The same goes for the server sending a message to the client.

The client test rig is an MDI application.  Each child window represents a client and multiple clients can connect to the server simultaneously.  Use the File menu to create a new client.

When multiple clients are connected to the server you can select the client to send a message to using the ComboBox at the bottom of the server window.  Clicking the Send All button will send the message to all connected clients.

To use the Wunnell.Net.MessageClientServer.dll assembly in your own applications you'll first want to open the References page of your project properties, add a reference to the assembly and then import the Wunnell.Net namespace.  You can add instances of the client and server classes in code like so:
vb.net Code:
Private WithEvents client As New MessageClient(hostName, remotePort)
Private WithEvents server As New MessageServer(port)
In the case of the client, the host name and remote port are the name or address and port number of the server.  In the case of the server, the port is the port number to listen on.  The server's port and the client's remote port must be the same.

Note that by using WithEvents in the declarations you can use the drop-down lists at the top of the code window to generate event handlers with Handles clauses.  You can use AddHandler if you prefer.

Note that you don't necessarily have to handle any events if you don't want to, but if you want to provide feedback on what's happening you will obviously need to.  Note also that, if you using the library in a WinForms app and you want events raised in the UI thread then you should assign your form to the SynchronisingObject property of the client or server.  All operations will still be performed on background threads.  It's only notifications that will occur on the UI thread.
vb.net Code:
Me.client.SynchronisingObject = Me
To be able to communicate you will first have to call the client's Connect method.  You can then call Send to send a message, e.g.
vb.net Code:
Me.client.Connect()
Me.client.Send("Hello Server")
To send a message from the server to a specific client you simply call Send and specify the client host details and the message.  To send a message to all clients you call Send and just specify the message, e.g.
vb.net Code:
For Each host In Me.server.Hosts
    Me.server.Send(host, "Hello " & host.ToString())
Next
 Me.server.Send("Hello All Clients")
To disconnect you simply dispose the client or the server.

KNOWN ISSUES:

1. If you try to close a client window in the test application without having connected the window will not close. [Fixed in v1.0.0.1 on 2009-10-11. See post #2]
2. HostInfo.Equals throws an exception if passed a value that is not type HostInfo. [Fixed in v1.0.1.0 on 2009-11-10.  See post #6]
3. IOException may be thrown when closing client child window. [Fixed in v1.1.0.1 on 2010-10-10]

The whole solution has been tested but more rigorous testing is still required.  I'll be looking to improve the feature set and address any issues that arise so please feel free to post comments, suggestions and questions here, although I can't guarantee if and when I'll get to them.

UPDATES:

25 Oct 2009: v1.1.0.0 posted.  See post #22 for details of changes.
10 Oct 2010: v1.1.0.1 posted.  Fixes occasional crash when closing client child window.

----------


## jmcilhinney

The problem was that the 'stream' field of the MessageClient class was not set until the connection was established and Close was being called on that field in the Dispose method regardless.  The exception was preventing the form closing.  To resolve the issue the Dispose method was changed from this:
vb.net Code:
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.isDisposed Then
        If disposing Then
            'Close the connection and the underlying stream.
            Me.stream.Close()
            Me.client.Close()
        End If
         Me.stream = Nothing
    End If
     MyBase.Dispose(disposing)
    Me.isDisposed = True
End Sub
to this:
vb.net Code:
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.isDisposed Then
        If disposing Then
            'Close the connection and the underlying stream.
            If Me.stream IsNot Nothing Then
                Me.stream.Close()
            End If
             Me.client.Close()
        End If
         Me.stream = Nothing
    End If
     MyBase.Dispose(disposing)
    Me.isDisposed = True
End Sub

----------


## jmcilhinney

> To be able to communicate you will first have to call the client's Connect method.  You can then call Send to send a message, e.g.
> vb.net Code:
> Me.client.Connect()Me.client.Send("Hello Server")


I just wanted to point out that you can't really use code quite like that.  When you call Connect the connection request is made asynchronously and the ConnectionAccepted event will be raised when that operation completes.  I haven't actually tested the scenario but I imagine that, if you call Connect and then you call Send before receiving the ConnectionAccepted event, an exception will be thrown.

----------


## Farflamex

I'm afraid I've run into an immediate problem. As soon as I start up the program, the server starts running, but as soon as I hit 'Connect' on the client, I get the error message 'When casting from a number, the value must be less than infinity' in this section of code....



```
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        With DirectCast(obj, HostInfo)
            Return Me.HostName.Equals(.HostName, StringComparison.CurrentCultureIgnoreCase) AndAlso _
                   Me.Port = .Port
        End With
    End Function
```

It's on the line 'With DirectCast.......'

One other thing, would it be possible to seperate this into two seperate programs, one for the server and one for the client? I realise it's much easier to test like this but it'll be necessary to split them eventually. Or give me a rough idea which files I'll need for each seperate program?

----------


## jmcilhinney

> I'm afraid I've run into an immediate problem. As soon as I start up the program, the server starts running, but as soon as I hit 'Connect' on the client, I get the error message 'When casting from a number, the value must be less than infinity' in this section of code....
> 
> 
> 
> ```
>     Public Overrides Function Equals(ByVal obj As Object) As Boolean
>         With DirectCast(obj, HostInfo)
>             Return Me.HostName.Equals(.HostName, StringComparison.CurrentCultureIgnoreCase) AndAlso _
>                    Me.Port = .Port
> ...


I'd have to know more about exactly how you're using it to know exactly what the problem is.  Are you running my test apps or are you trying to use the library in your own project?  I'm not sure how you could come up with that error if you're using my test apps as I've checked where HostInfo.Equals method is called in my code and I can't see how that error could occur.  Maybe I've missed something though so, if you are using my test apps, please give me a step by step run down of EXACTLY what you did so I can do the same thing and see if I get the same result.

If you're calling that method then I can only assume that you're using it incorrectly.  The HostInfo.Equals method overrides the Object.Equals method so it will accept any object, but it's supposed to compare HostInfo objects.  It sounds like you're passing it a value that isn't a HostInfo object.  If it is your own code, what is the type and value of 'obj' when that error occurs and can you show me the code that calls that method.

That said, I guess that that method should really return False if the value passed in isn't a HostInfo object.  That's not going to make your code work correctly if you're passing in an object of the wrong type but it will stop it crashing.  I'll make that change and post a new version of the solution.


> One other thing, would it be possible to seperate this into two seperate programs, one for the server and one for the client? I realise it's much easier to test like this but it'll be necessary to split them eventually. Or give me a rough idea which files I'll need for each seperate program?


There's no need or point to breaking it up into two assemblies.  The MessageClient and MessageServer classes both inherit the MessageClientServerBase class so you will need a common assembly somewhere regardless.  The idea is that, if you have two separate applications, i.e. a client and a server, then they both reference the Wunnell.Net.MessageClientServer.dll assembly.  The server application would simply ignore the MessageClient class and only instantiate the MessageServer class, while the client application would do the opposite.  If you have one application that uses a TextBox and another that uses a ComboBox, is it a problem that both those apps have to reference System.Windows.Forms.dll because both those controls are defined in that same assembly?

----------


## jmcilhinney

> I'm afraid I've run into an immediate problem. As soon as I start up the program, the server starts running, but as soon as I hit 'Connect' on the client, I get the error message 'When casting from a number, the value must be less than infinity' in this section of code....
> 
> 
> 
> ```
>     Public Overrides Function Equals(ByVal obj As Object) As Boolean
>         With DirectCast(obj, HostInfo)
>             Return Me.HostName.Equals(.HostName, StringComparison.CurrentCultureIgnoreCase) AndAlso _
>                    Me.Port = .Port
> ...


It seems I may have done you a disservice.  I changed my code a bit and when I ran it I saw that the HostInfo.Equals method was being called by the system when the items were added to the ComboBox and the value they were compared to was DBNull, which would have failed the cast.  Maybe those exceptions were being swallowed on my system but not on yours.  Anyway, I've changed that method from this:
vb.net Code:
Public Overrides Function Equals(ByVal obj As Object) As Boolean
    With DirectCast(obj, HostInfo)
        Return Me.HostName.Equals(.HostName, StringComparison.CurrentCultureIgnoreCase) AndAlso _
               Me.Port = .Port
    End With
End Function
to this:
vb.net Code:
Public Overloads Function Equals(ByVal host As HostInfo) As Boolean
    Return Me.HostName.Equals(host.HostName, StringComparison.CurrentCultureIgnoreCase) AndAlso _
           Me.Port = host.Port
End Function
 Public Overloads Overrides Function Equals(ByVal obj As Object) As Boolean
    Return TypeOf obj Is HostInfo AndAlso _
           Me.Equals(DirectCast(obj, HostInfo))
End Function
Download version 1.0.1.0 once I've uploaded it and see if that solves your problem.

I also found an InvalidOperationException being thrown sometimes when the server is closed while clients are connected that wasn't being caught, so I've addressed that too.

----------


## Farflamex

Thanks, with my level of incompetence, I'm sure we can sort these problems out  :Smilie: 

Hopefully you've sorted that one out, but all I did was load up the program and run it. I didn't make any changes at all. The server starts automatically and I just clicked 'Connect' on the client, and the error appeared. Hopefully the update will resolve that.

As for having two seperate assemblies, this is probably due to my incompetence with VB, but what I was looking to do was to have one program for my server and one for my clients. But I assume what you're saying is, they would both be identical anyway, I just need to set one up as a server, which runs as it does now but doesn't start any clients, and one which only starts the client. I'll tinker around with it once you've uploaded the new code and see if I can sort that without any problems.

----------


## jmcilhinney

> Thanks, with my level of incompetence, I'm sure we can sort these problems out 
> 
> Hopefully you've sorted that one out, but all I did was load up the program and run it. I didn't make any changes at all. The server starts automatically and I just clicked 'Connect' on the client, and the error appeared. Hopefully the update will resolve that.


That makes sense.  From what I saw after I changed the code, that's where I would expect the problem to be because that's when the HostInfo gets added to the ComboBox.  For some reason that exception was crashing the app on your system but it was getting swallowed on mine and the app continued.  I don't know whether that's because of my VS settings or it's a Win7 thing but I'll be looking more closely at the Output window for first-chance exceptions in future.  I think the change I made should fix that issue.


> As for having two seperate assemblies, this is probably due to my incompetence with VB, but what I was looking to do was to have one program for my server and one for my clients. But I assume what you're saying is, they would both be identical anyway, I just need to set one up as a server, which runs as it does now but doesn't start any clients, and one which only starts the client. I'll tinker around with it once you've uploaded the new code and see if I can sort that without any problems.


I think you misunderstand how this is supposed to work.  You say that you want two separate applications for the client and the server.  That's exactly what you already have.  That solution contains three separate projects.  One is the client/server library, one is the client application and one is the server application.

When you run the solution and the two windows pop up, they are two completely separate applications, and each of them references the third.  That's how it would work for you.  You would most likely create a solution with two projects: one for the client and one for the server.  To each of those projects you would add a reference to the Wunnell.Net.MessageClientServer.dll assembly that you created by building my solution, or at least the Wunnell.Net.MessageClientServer project in my solution.

----------


## Farflamex

Ok, just to let you know it now works fine and is sending and receiving messages with no problems between server and client.

Now I just have to work out how where I add my own code for my server and client. The whole MDI thing confuses me. Don't worry, it's not your job to teach me VB, I'll delve into it and see how far I get  :Smilie:

----------


## jmcilhinney

> Ok, just to let you know it now works fine and is sending and receiving messages with no problems between server and client.
> 
> Now I just have to work out how where I add my own code for my server and client. The whole MDI thing confuses me. Don't worry, it's not your job to teach me VB, I'll delve into it and see how far I get


In your server app you create a MessageServer object and handle at least its ConnectionAccepted and MessageReceived events.  Additionally, call its Send method to send messages to the client(s).

For the client, create a MessageClient instance and handle at least its ConnectionAccepted event and, if you want to receive messages from the server, its MessageReceived event too.  Call its Connect method, wait for the ConnectionAccepted event and then you can start calling Send.

That's pretty much it.

----------


## Farflamex

No probs. I understand the basic calls. What I don't understand at the moment is how the program is laid out. I'd like, for example, to just have the single client window, instead of the window within the window which opens multiple clients.

The problem stems from the fact that I've 'upgraded' to VB.net from VB6 and even further back from very old types of BASIC. Whilst I can understand the beauty and power of modern languages, it's a struggle to change my mindset to this new style of programming. So whilst I understand the whole sockets issue, I don't understand all the OOP that it's wrapped up in. Infact when I think about it, there's nothing about the sockets issue that I don't understand - but I have no idea how to translate that into VB.net. All that stuff with delegates and synclocks put my brain into a synclock  :Stick Out Tongue: 

Anyhoo, I'm learning as I go along. I'll try to break this down into something I understand and then build onto it.

----------


## chris128

Nice to see that it wasnt just me that had to ignore the ObjectDisposed exception when calling EndAcceptTcpClient. Same for the IOException when calling EndRead.
I assumed there was a better way to handle this that I just couldnt figure out but seeing you do the same thing makes me feel a bit better about it  :Smilie:

----------


## jmcilhinney

> Nice to see that it wasnt just me that had to ignore the ObjectDisposed exception when calling EndAcceptTcpClient. Same for the IOException when calling EndRead.
> I assumed there was a better way to handle this that I just couldnt figure out but seeing you do the same thing makes me feel a bit better about it


Yeah, I was hunting and hunting for some property that I could test before calling EndWhatever but I couldn't find anything, so I can only assume that catching the exceptions is the only way to go.

----------


## paintballgod

is is possible to send attachments such as pictures from a picturebox in the same way as the text it sent? it may not have anything all to do with the tcpclient but i was wondering.

----------


## jmcilhinney

> is is possible to send attachments such as pictures from a picturebox in the same way as the text it sent? it may not have anything all to do with the tcpclient but i was wondering.


The point of this submission is specifically to send text between a client and server without feezing the UI.  My wrapper class provides only the ability to send and receive text, but that's a decision I made.  It's certainly not a limitation of the TcpClient class.  It sits on top of a NetworkStream, which, like all streams, simply passes binary data form one place to another without any regard for what that data represents.  As such they can send any data you like.  It's up to the application to interpret the binary data and give it meaning.

If you check out my code you'll see that, internally, my MessageServer and MessageClient convert the text passed in to binary form before transmitting it and they convert the binary data received across the connection in text before passing it out to the caller.  You can convert anything at all to binary form, thus you can write your own code to send anything you want using the TcpClient class.

If you want any further information on that, please start your own thread in the appropriate forum as it goes beyond the scope of this topic.  If you want to discuss the asynchronous aspect of my code though, feel free to post here.

----------


## nuster

As a newbie forgive my ignorance. Your solution of 3 projects works fine on my desktop, uncompiled, just in debug. It also works fine on my laptop in debug. As I understand it I will use the entire solution on both computers. My question is how I would specify IP addresses. On my desktop that I would use as the server my first adapter is tied up on an intranet, and that is the adapter that the your test detects. I have a crossover between my laptop and a second adapter on my desktop that pings correct. How do I default your solution to the second adapter? thank you very much for your help.

----------


## jmcilhinney

> As a newbie forgive my ignorance. Your solution of 3 projects works fine on my desktop, uncompiled, just in debug. It also works fine on my laptop in debug. As I understand it I will use the entire solution on both computers. My question is how I would specify IP addresses. On my desktop that I would use as the server my first adapter is tied up on an intranet, and that is the adapter that the your test detects. I have a crossover between my laptop and a second adapter on my desktop that pings correct. How do I default your solution to the second adapter? thank you very much for your help.


My MessageServer class accepts a port number in the constructor and then passes that to the Initialise method, which gets the first IPv4 address on the system and then starts listening on that combination.  You would need to add one or more new constructors that also took an IP address and then use that in a new overload of Initialise.  I should probably make that change myself but, for now, this is the sort of change you'd need to make, from this:
vb.net Code:
Public Sub New(ByVal port As Integer)
    Me.Initialise(port)
End Sub
 Private Sub Initialise(ByVal port As Integer)
    Me._port = port
     'Listen on the first IPv4 address assigned to the local machine.
    Me.server = New TcpListener(Me.GetLocalIPv4Address(), port)
    Me.server.Start()
     'Start listen asynchronously.
    Me.server.BeginAcceptTcpClient(AddressOf AcceptTcpClient, Nothing)
End Sub
to this:
vb.net Code:
Public Sub New(ByVal port As Integer)
    Me.Initialise(port)
End Sub
 Public Sub New(ByVal address As String, ByVal port As Integer)
    Dim ipAddress As IPAddress = Nothing
     If ipAddress.TryParse(address, ipAddress) Then
        Me.Initialise(ipAddress, port)
    Else
        Throw New ArgumentException("String must represent a valid IP address.", "address")
    End If
End Sub
 Private Sub Initialise(ByVal port As Integer)
    'Listen on the first IPv4 address assigned to the local machine.
    Me.Initialise(Me.GetLocalIPv4Address(), port)
End Sub
 Private Sub Initialise(ByVal address As IPAddress, ByVal port As Integer)
    Me._port = port
     Me.server = New TcpListener(address, port)
    Me.server.Start()
     'Start listen asynchronously.
    Me.server.BeginAcceptTcpClient(AddressOf AcceptTcpClient, Nothing)
End Sub

----------


## chris128

Would it not make sense to have the default be to listen on any IP address rather than just the first IP it finds? I'm pretty sure that is what the constructor for TcpListener does when you just pass it a port and no IP address.  :Smilie:

----------


## jmcilhinney

> Would it not make sense to have the default be to listen on any IP address rather than just the first IP it finds? I'm pretty sure that is what the constructor for TcpListener does when you just pass it a port and no IP address.


Sounds reasonable.

----------


## rydinophor

Im getting a lot of issues I can hardly do anything :S. Here is what i have:
Server:


```
Imports Wunnell.Net
Module ModMain
    Private WithEvents server As New MessageServer(4000)
    Sub Main()
        AddHandler server.MessageReceived, AddressOf MessageRecieved

        Console.ReadLine()
    End Sub
    Private Sub MessageRecieved(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        Console.WriteLine(e.Message)
        For Each host In server.Hosts
            server.Send(host, "Hello " & host.ToString())
        Next
        server.Send("Hello All Clients")
    End Sub
    Private Sub Accepted(ByVal Sender As Object, ByVal e As ConnectionEventArgs)
        Console.WriteLine(e.Host.Port)
        For Each host In server.Hosts
            server.Send(host, "Hello " & host.ToString())
        Next
        server.Send("Hello All Clients")
    End Sub

End Module
```

Client Side


```
Imports Wunnell.Net
Public Class Form1
    Private WithEvents client As New MessageClient("localhost", 4000)
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.client.SynchronisingObject = Me
        Me.client.Connect()
        AddHandler client.ConnectionAccepted, AddressOf Accepted
        AddHandler client.MessageReceived, AddressOf MessageRecieved
    End Sub
    Private Sub MessageRecieved(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        MsgBox(e.Message)
    End Sub
    Private Sub Accepted(ByVal Sender As Object, ByVal e As ConnectionEventArgs)
        Me.client.Send("Hello Server")
    End Sub
End Class
```

----------


## jmcilhinney

> Im getting a lot of issues I can hardly do anything :S. Here is what i have:
> Server:
> 
> 
> ```
> Imports Wunnell.Net
> Module ModMain
>     Private WithEvents server As New MessageServer(4000)
>     Sub Main()
> ...


First up, let me point out that there's no point declaring your fields WithEvents if you're going to use AddHandler to attach event handlers. The whole and sole point of WithEvents is so that you can use that field in the Handles clause of your event handler methods.

As for the issue, you're telling the client to connect to "localhost", which is IP address 127.0.0.1, while the server is listening on its network IPv4 address, which will likely be 192.168.x.x. If you change "localhost" to Environment.MachineName in the client then it will work.

I'm going to make some changes to my code, including making the server listen on any address by default. Doing so should mean that "localhost" can be used at the client. As it stands, if you do want to use "localhost" at the client you need to explicitly tell the server to listen on that local loopback address.

----------


## jmcilhinney

Version 1.1.0.0 now attached to post #1.

1. Server now listens on IPAddress.Any by default.  The caller can also specify an IP address, the machine name or "localhost".

2. Server now listens on a random port in the range 1024 to 5000 by default.  The caller can also specify a port number.

3. Removed SynchronisingObject property.  Client and server both now use the SynchronizingContext class to raise all events on the same thread on which the object was created.  This means that, in a WinForms app, you must ensure that the object is created on the UI thread if you want to update the UI from event handlers.

----------


## rydinophor

jmcilhinney, I have another question. Is your library based off the TCPClient and TCPListener, Or based off the Socket Library Or Both.
I prefer using Asynchronous Sockets, A friend of mine told me Threaded sockets are terrible thats the reason I asked.


Regards,
Rydinophor

EDIT:
I keep getting these errors:


```
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
```

and 
Click this link to see where its coming from: http://i36.tinypic.com/243fg4k.png

----------


## jmcilhinney

> jmcilhinney, I have another question. Is your library based off the TCPClient and TCPListener, Or based off the Socket Library Or Both


Have you read the code?  That would answer your question.  Reading the title of this thread should provide a clue too.


> I prefer using Asynchronous Sockets, A friend of mine told me Threaded sockets are terrible thats the reason I asked.


I'm no expert when it comes to network programming.  I've only ever used the TcpClient/TcpListener once before and never used a Socket directly.


> I keep getting these errors:
> 
> 
> ```
> Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
> ```
> 
> and 
> Click this link to see where its coming from: http://i36.tinypic.com/243fg4k.png


I've never seen that error in my own testing so I'd have to know more about how you're using my library to know whether it's an issue with my code or how you're using it.  As I said at the beginning of this thread, I have tested but not as rigorously as I'd like so there amy still be issues lurking.

----------


## chris128

> jmcilhinney, I have another question. Is your library based off the TCPClient and TCPListener, Or based off the Socket Library Or Both.
> I prefer using Asynchronous Sockets, A friend of mine told me Threaded sockets are terrible thats the reason I asked.


You do realise that the TcpClient and TcpListener classes are just wrappers around the Socket class anyway? They just make it a bit easier to use the sockets, they dont do anything differently internally when actually sending/receiving data via the sockets as far as I know.

----------


## jmcilhinney

> You do realise that the TcpClient and TcpListener classes are just wrappers around the Socket class anyway? They just make it a bit easier to use the sockets, they dont do anything differently internally when actually sending/receiving data via the sockets as far as I know.


Quite true.  The TcpClient class has a Client property to get its underlying Socket.  As I said, I've never used the Socket directly though; only the TcpClient and its underlying NetworkStream.

----------


## rydinophor

Error:


```
System.Reflection.TargetInvocationException was unhandled
  Message="Exception has been thrown by the target of an invocation."
  Source="mscorlib"
  StackTrace:
       at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Delegate.DynamicInvokeImpl(Object[] args)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at WindowsApplication1.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.IndexOutOfRangeException
       Message="Index was outside the bounds of the array."
       Source="WindowsApplication1"
       StackTrace:
            at WindowsApplication1.ModHandleData.HandleData(String Data) in C:\Users\ubersaiyanx\Desktop\Pokemon Cobalt Online\Latest\Client\WindowsApplication1\WindowsApplication1\ModHandleData.vb:line 23
            at WindowsApplication1.Form1.client_MessageReceived(Object sender, MessageReceivedEventArgs e) in C:\Users\ubersaiyanx\Desktop\Pokemon Cobalt Online\Latest\Client\WindowsApplication1\WindowsApplication1\Form1.vb:line 16
            at Wunnell.Net.MessageClientServerBase.RaiseMessageReceived(Object e) in C:\Users\ubersaiyanx\Desktop\Message Client-Server\Wunnell.Net.MessageClientServer\MessageClientServerBase.vb:line 240
       InnerException:
```

----------


## jmcilhinney

> Error:


Here's your issue:


> Message="*Index was outside the bounds of the array.*"





> at WindowsApplication1.ModHandleData.HandleData(String Data) in C:\...\*ModHandleData.vb:line 23*


Exceptions can be a bit confusing at first but make sure you DO read the information provided.  Don't just assume it's too hard because, as you can see, the exact location and cause of your issue was in there.

----------


## chris128

> 3. Removed SynchronisingObject property. Client and server both now use the SynchronizingContext class to raise all events on the same thread on which the object was created. This means that, in a WinForms app, you must ensure that the object is created on the UI thread if you want to update the UI from event handlers.


Why did you do this? I've often wanted my classes that use background threads to be able to raise their events on another thread but didnt think it was possible - after reading your post here http://www.vbforums.com/showthread.php?t=589212 I realise that it is possible but I'm wondering if there was some problem you found with doing this that caused you to remove such a feature?

----------


## jmcilhinney

> Why did you do this? I've often wanted my classes that use background threads to be able to raise their events on another thread but didnt think it was possible - after reading your post here http://www.vbforums.com/showthread.php?t=589212 I realise that it is possible but I'm wondering if there was some problem you found with doing this that caused you to remove such a feature?


There was no problem per se.  The way I was doing it originally, i.e. with a SynchronisingObject property, is the same as some classes in the Framework do it.  One advantage of this is that it gives you the choice of leaving the SynchronisingObject property empty and having events raised on a thread pool thread or setting it and having events raised on a specific thread.  I didn't really see a reason why you specifically want my classes to raise their events on thread pool threads though, so the change I made did three things for me:

1. It meant that a caller could completely ignore the fact that there was multi-threading involved and, in fact, wouldn't even know it from the interface.  All interaction with an instance of one of my classes would occur on the same thread without any indication that any other threads were involved.  There was no need for the caller to go to the (admittedly tiny) effort of setting the SynchronisingObject property to get synchronous events.

2. It made my code a bit cleaner.

3. It gave me a chance to play with the SynchronizationContext class, which I haven't had the pleasure of previously.

Like I said, there was nothing actually wrong with the old implementation.  If you're interested in doing something similar but aren't 100% sure how then I'm happy to provide the old code.  That said, you might also be interested in using the SynchronizationContext class as the new code does.

----------


## chris128

Ahh I see, sorry from reading your post saying that you must be certain to create the object on the UI thread if you want to update a form/control I thought that you were no longer providing any kind of 'easy' way of handling the cross thread calls. However, I now realise that the way your class works now is that it raises the events on whatever thread it was created on. So if you create an instance of your class on the UI thread then you dont need to worry about marshaling across the threads in the events that are raised from it, correct?
The MSDN doc on the SynchronizationContext class seems to be pretty light, did you find any other good sources of info on it? I'm currently reading through this: http://www.codeproject.com/KB/cpp/Sy...tTutorial.aspx

----------


## jmcilhinney

> So if you create an instance of your class on the UI thread then you dont need to worry about marshaling across the threads in the events that are raised from it, correct?


Correct.


> The MSDN doc on the SynchronizationContext class seems to be pretty light, did you find any other good sources of info on it? I'm currently reading through this: http://www.codeproject.com/KB/cpp/Sy...tTutorial.aspx


That page and the MSDN doco are all I've read on the subject too.

----------


## chris128

Just found an interesting video here about the alternatives to SynchronizationContext in .NET 4 http://rocksolidknowledge.com/Screen...adAffinity.wmv

Sorry if thats a little off topic for this thread  :Smilie:

----------


## Ianis

Very nice Socket.  :Thumb: 
I would replace the combobox by a listview but u don't really know how to do...
Someone can help me ?

----------


## jmcilhinney

> Very nice Socket. 
> I would replace the combobox by a listview but u don't really know how to do...
> Someone can help me ?


The point of this thread and the attached solution is the asynchronous client/server library.  The WinForms projects were simply to demonstrate that.  Displaying information in a ListView really has nothing to do with the topic of this thread.  I suggest that you start a thread in the VB.NET forum dedicated to displaying information in a ListView.

----------


## Ianis

Hello,
I found a little problem ( but didn't found solution ).



```
FR : Une exception de première chance de type 'System.IO.IOException' s'est produite dans System.dll
EN : A first chance exception of type 'System.IO.IOException' occurred in System.dll
```

I think that Error is occur when the socket is unloaded during a reception of data.

The Debugger report me here :


```
Dim byteCount = Me.stream.EndRead(ar)
```

----------


## jmcilhinney

> Hello,
> I found a little problem ( but didn't found solution ).
> 
> 
> 
> ```
> FR : Une exception de première chance de type 'System.IO.IOException' s'est produite dans System.dll
> EN : A first chance exception of type 'System.IO.IOException' occurred in System.dll
> ```
> ...


A first chance exception is not a problem.  It just indicates that an exception was thrown, which is perfectly legal.  It's when an exception is thrown and not caught that there's an issue.  If you look at the code you'll see that there are several exception handlers in there to catch the exceptions that are thrown when a connection is closed while an asynchronous operation is in progress.  I'm guessing that this is one of those cases.

If the app crashes due to an unhandled exception then by all means let me know exactly where, i.e. which line in which file.  Otherwise it's all part of the plan.  :Smilie:

----------


## Ianis

Hmm i don't reall know why but  the bug don't happen in the original source.
Only with mine ( i modified a the class for working a Chat app) .
And not always.

----------


## Visual Basic.Net

Is there VB.Net 2005 version of this class?
thank's

----------


## jmcilhinney

> Is there VB.Net 2005 version of this class?
> thank's


The code uses various VB 2008 and .NET 3.5 features.  You could certainly implement the same functionality in VB 2005 but you'd have to use loops where I've used LINQ queries, etc.

----------


## Visual Basic.Net

> The code uses various VB 2008 and .NET 3.5 features.  You could certainly implement the same functionality in VB 2005 but you'd have to use loops where I've used LINQ queries, etc.


Thank's alot bro. 
I will appreciate it if you could help me in following problem:
I made a program in vb.net 2005, it using Winsock DLL. Here is the full explanation of it:
http://www.vbforums.com/showthread.php?t=590966


every body told me that problem is from Winsock Dll. However, I downloaded VB.Net 2008 Express Edition, only to test the same program but by using your class. unfortunately, the same problem appear!

Attached the modified project which using your class instead of Winsock Dll.

Thank's in advance

----------


## Ianis

Hello,
i'am trying to use your Class in Console.
But i have several bugs during devugging like :



> La référence d'objet n'est pas définie à une instance d'un objet.





> Object reference not set to an instance of an object.


On Connection Event.

----------


## jmcilhinney

> Hello,
> i'am trying to use your Class in Console.
> But i have several bugs during devugging like :
> 
> 
> On Connection Event.


You'd have to be much more specific.  Exactly what line and exactly what reference is Nothing?  Also, I've not had such issues so I'd need to know exactly how the code is being used.

----------


## Ianis

> You'd have to be much more specific.  Exactly what line and exactly what reference is Nothing?  Also, I've not had such issues so I'd need to know exactly how the code is being used.


There are several Errors which, i think are cause beceause there are no from anymore.
I only tryed to turn the Server into Console.
I am sure my code is good, also errors comes from the class's.

You should try your Server in console.

----------


## jmcilhinney

> There are several Errors which, i think are cause beceause there are no from anymore.
> I only tryed to turn the Server into Console.
> I am sure my code is good, also errors comes from the class's.
> 
> You should try your Server in console.


As should be the case with a class library, that DLL is totally independent of what is using it.  It doesn't care whether the application using it is a windows app, a console app or whatever.  If the library is throwing exceptions it's nothing to do with it being used by a console app specifically.  Either there's a bug in my code or you're using it incorrectly.  There's nothing wrong with a library throwing exceptions.  If it is forced into exceptional situations it should throw exceptions.  You need to either debug your code and stop it doing the wrong thing or, if it's a situation beyond your control, handle the exceptions and react accordingly.  If you can tell me where the issue is then I can check to see whether it's an issue with my code.

----------


## avatar_nz

Firstly, thanks for the source and original post. Simply awesome!
I wrote a tcp client application (using Socketwrench .Net) in VB 2005 back in '07 that I am looking to re-write. I have had a quick look through your source and played around with a few things. I would like to use your code as the basis of my re-write. The problem area I had with the original was/is efficient handling of the returned messages. Each message is encapsulated in xml tags (although, they are not true xml). My original version used a loop until the closing tag was found before sending the message off to a message handling routine (this was a VB6 conversion). I'm sure that using string is probably an in-efficient method given the advances in the framework?
Cheers

----------


## jmcilhinney

> Firstly, thanks for the source and original post. Simply awesome!
> I wrote a tcp client application (using Socketwrench .Net) in VB 2005 back in '07 that I am looking to re-write. I have had a quick look through your source and played around with a few things. I would like to use your code as the basis of my re-write. The problem area I had with the original was/is efficient handling of the returned messages. Each message is encapsulated in xml tags (although, they are not true xml). My original version used a loop until the closing tag was found before sending the message off to a message handling routine (this was a VB6 conversion). I'm sure that using string is probably an in-efficient method given the advances in the framework?
> Cheers


Glad to help.  I'm just not sure whether you're actually asking a question there or not.  If you're saying that you want to pass XML messages back and forth then you might want to use the XmlDocument.LoadXml method to load the received String into an XmlDocument.  To create the String from the XmlDocument in the first place you could use the XmlDocument.Save method and pass a StringWriter, which is like a StreamWriter but writes to a String instead of a Stream.

----------


## Ianis

I found what's going wrong :

it's a Console Application, so this need a 


```
Sub Main()

End Sub
```

But..
With your class i need to add this in a Sub :
ByVal Sender As Object, ByVal e As MessageReceivedEventArgs



```
    Sub Main(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        AddHandler server.MessageReceived, AddressOf MessageRecieved

        Console.ReadLine()
    End Sub
```

But i cant add this to the Main Sub




> No accessible 'Main' method with an appropriate signature was found

----------


## avatar_nz

Thanks John. I will will have a play around with this and some of the other great information from your blogs.
Cheers

----------


## jmcilhinney

> I found what's going wrong :
> 
> it's a Console Application, so this need a 
> 
> 
> ```
> Sub Main()
> 
> End Sub
> ...


You're quire correct that you need a procedure with that signature but it's not supposed to be the Main method.  Your own code is saying that it's supposed to be a method named MessageReceived that has that signature, so why do you need to add those parameters to the Main method?

```
Sub Main()
    AddHandler server.MessageReceived, AddressOf MessageRecieved

    Console.ReadLine()
End Sub

Sub MessageRecieved(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
    '...
End Sub
```

----------


## Ianis

Well ok but, 
do you have a simple exemple of a ModMain in Console.
Just few lines HOWTO replace the Server Main Form > Console
(The most simple you can do with console.writeline / debug.print )

----------


## jmcilhinney

> Well ok but, 
> do you have a simple exemple of a ModMain in Console.
> Just few lines HOWTO replace the Server Main Form > Console
> (The most simple you can do with console.writeline / debug.print )


To be honest, I really don't see that this is appropriate for a Console app anyway.  The whole point of this code is its asynchronous nature, which allows communication to take place in the background while the main thread remains responsive.  That's not an issue with a Console app.  In fact, if you send off other threads to do the work your app is simply going to exit because the main thread will complete immediately.

----------


## Ianis

Do you think there is a way for Make the Server in console ?
Cause the protocol i'm working on make server without Send Message from Server.
The Server is just like  a IRC Server.
Something which allow each client chatting together.
But i prefere have a Console application for a such thing.

I'll explain better if you don't udnerstand

Thanks, Ianis.

----------


## jmcilhinney

> Do you think there is a way for Make the Server in console ?
> Cause the protocol i'm working on make server without Send Message from Server.
> The Server is just like  a IRC Server.
> Something which allow each client chatting together.
> But i prefere have a Console application for a such thing.
> 
> I'll explain better if you don't udnerstand
> 
> Thanks, Ianis.


Beyond the scope of this thread.

----------


## rydinophor

Sorry for the necro post, but that DLL file of yours needs a small edit, Every time a client disconnects unsafely the server crashes, here's where the following bug is located:
*Location: Wunnell.Net.MessageClientServer->MessageServer.vb*

vb Code:
''' <summary>    ''' Receives an incoming message.    ''' </summary>    ''' <param name="ar">    ''' Contains state information for the read operation.    ''' </param>    Private Sub Read(ByVal ar As IAsyncResult)        Dim asyncState = DirectCast(ar.AsyncState, ReadAsyncState)        Dim buffer = asyncState.Buffer        Dim client = asyncState.Client         Try            Dim stream = client.GetStream()             'Complete the asynchronous read and get the first block of data.            Dim byteCount = stream.EndRead(ar)             If byteCount = 0 Then                'If there is no data when an asynchronous read completes it is because the client closed the connection.                Me.RemoveClient(client)            Else                'Start building the message.                Dim message As New StringBuilder(Me.Encoding.GetString(buffer, 0, byteCount))                 'As long as there is more data...                While stream.DataAvailable                    '...read another block of data.                    byteCount = stream.Read(buffer, 0, Me.BufferSize)                     'Build the message block by block.                    message.Append(Me.Encoding.GetString(buffer, 0, byteCount))                End While                 'Listen asynchronously for another incoming message.                stream.BeginRead(buffer, 0, Me.BufferSize, AddressOf Read, New ReadAsyncState With {.Client = client, .Buffer = buffer})                 'Notify any listeners that a message was received.                Me.OnMessageReceived(New MessageReceivedEventArgs(Me.clients(client), message.ToString()))            End If        Catch ex As InvalidOperationException            'The callback specified when BeginRead was called gets invoked one last time when the TcpListener is stopped.            'This exception is thrown when GetStream is called on a disconnected client or EndRead is called on a disposed stream.        End Try    End Sub
I seemed to solve the issue by simply changing:

vb Code:
Catch ex As InvalidOperationException
To the following: 

vb Code:
Catch ex As System.IO.IOException                Me.RemoveClient(client)

Either My Computer Is Messed up or that Current Exception is pointless, it told me to use the system.io exception and it fixed it in a flash.
If you want to you might want to change to the System.IO exception because the current exception fails to work.  :Frown: 

Also The Error Is thrown here and fails to proceed to the exception:
Dim byteCount = stream.EndRead(ar)

P.S. I'm counting on this library for my Pokemon game I'm creating, The client side is in Purebasic, and The Server is in VB.net.

Regards,
Rydinophor

EDIT:
Also, Would You happen to give an example of your server multithreaded? I'm stumped on this part, My friend who is coding with me is confusing me with multithreading with the server side, and I'm completely lost, My idea is throw the recieved data packet onto a thread and have it handle that and continue processing the other packets coming in. I'm quite new to VB.net, I just began last summer.

With Regards,
Rydinophor

----------


## freedompeace

My modified code doesn't send files properly; the files become corrupted.

----------


## ForumAccount

So I pretty much ran this project "straight out of the box", all I did was add a button on the ClientWindow that runs this code when it's clicked:


vb.net Code:
For counter As Integer = 0 To 1000
    Me.client.Send(counter.ToString())
Next

Attached is how the server will receive it. It's easy to see what is happening to the data, but my question is how can this be prevented? I want each number to be received on a separate line. So each message is processed separately, is this possible?

----------


## jmcilhinney

> So I pretty much ran this project "straight out of the box", all I did was add a button on the ClientWindow that runs this code when it's clicked:
> 
> 
> vb.net Code:
> For counter As Integer = 0 To 1000
    Me.client.Send(counter.ToString())
Next
> 
> Attached is how the server will receive it. It's easy to see what is happening to the data, but my question is how can this be prevented? I want each number to be received on a separate line. So each message is processed separately, is this possible?


Check whether each string you receive has a null character terminating it.  If it does, edit your server to detect that null character and treat that as the end of a message.  If there is no null character, edit your client to add one.

----------


## jinx101

First, I have to say, I *love* your post.  This is the absolute easiest implementation of a TCP client/server I've seen in .Net.  Using your methods I got stuff sending back and forth in 5 minutes.  Question though, when I don't use your client's send method, and I connect to the TCP server with telnet... the received message is always garble unless a ascii 10/13 (it looks like the same character is reported regardless of what I type in the telnet window)... is there a quick reason why that's the case (like... does it always require a line terminator and if it doesn't get it in the message it doesn't work)?

Btw, this code rocks.  The last time I needed TCP/IP I used the WinSock control with VB6.  I used a delimited protocol and parsed everything.  I know XML is kind of talky, but it makes creating simple protocol's soooooo easy with serialization.  I have a simple chat client and shared browser (so two people can browse together) setup (Note:  this is just a hobby project, I'm aware of the security implications if I were to implement some of these commands, it was more of just a test).  I have a serialization class that's not shown here that I use.. but it's a good example of how you can easily couple this with your client (I send the XML and then deserialize it when it's received... it looks for the end marker to know the trasmission is done).  I also did this in about 10 minutes so I haven't thought it out further.  ;P



```
Imports Iuf.Extensions

''' <summary>
''' Shared Browser Protocol
''' </summary>
''' <remarks></remarks>
Public Class Protocol

    Private Const END_MARKER As String = "#END"
    Private Const PROTOCOL_VERSION = 1

    Public Shared Function ParseInput(ByVal xml As String) As Message
        xml = xml.Trim(END_MARKER)
        Dim msg As Message = Iuf.Utilities.Serialization.XMLToObject(Of Message)(xml)
        Return msg
    End Function

    Public Shared Function AddEndMarkerToXml(ByVal xml As String) As String
        xml += END_MARKER
        Return xml
    End Function

    Public Shared Function ToXml(ByVal msg As Message) As String
        Return Iuf.Utilities.Serialization.ObjectToXML(msg) & END_MARKER
    End Function

    Public Shared Function ToMessage(ByVal xml As String) As Message
        Return ParseInput(xml)
    End Function

    <Serializable()> _
    Public Class Message

        Sub New()

        End Sub

        Enum Commands
            Chat
            Identify
            Click
            DoubleClick
            ShareUrl
            GotoUrl
            PhotoUrl
            SetWindowTitle
            MoveWindow
            MaximizeWindow
            MinimizeWindow
        End Enum

        Private _command As Commands
        Public Property Command() As Commands
            Get
                Return _command
            End Get
            Set(ByVal value As Commands)
                _command = value
            End Set
        End Property

        Private _arguments As New List(Of String)
        Public Property Arguments() As List(Of String)
            Get
                Return _arguments
            End Get
            Set(ByVal value As List(Of String))
                _arguments = value
            End Set
        End Property

    End Class

End Class
```

----------


## jinx101

Any thoughts on my telnet question?

----------


## rydinophor

can anyone get a console app working using this library? I would love to see something like that, ever since i'm using SDL.NET for my client, a windows form app is pointless, and for the server i prefer a console app to save some cpu, and to not deal with invoking cross threads.

----------


## Zeelia

Hello jmcilhinney!
First of all, I want to thank you for creating these classes which are extremely helpful and easy to use.

I've been using your classes for quite some time now without problems but now I thought of trying to communicate from a website to a VB.Net application. The operation wasn't that successful though.

Does you class have support for websites? I don't think there's any difference from the TcpClass for websites and yours class. However, every time I try to connect from the website, it results with an "Connection refused" error.

Any ideas?

I'm currently using PHP, I've tried the official socket methods and a TcpClass which I found online.
Both of them returns "Connection refused" anyways...

Help appreciated!
//Zeelia

----------


## jmcilhinney

> Hello jmcilhinney!
> First of all, I want to thank you for creating these classes which are extremely helpful and easy to use.
> 
> I've been using your classes for quite some time now without problems but now I thought of trying to communicate from a website to a VB.Net application. The operation wasn't that successful though.
> 
> Does you class have support for websites? I don't think there's any difference from the TcpClass for websites and yours class. However, every time I try to connect from the website, it results with an "Connection refused" error.
> 
> Any ideas?
> 
> ...


It sounds like there's an issue with the way you're trying to connect, not with the classes you're trying to use to connect.

----------


## Zeelia

Hi! Thanks for the quick reply.

I don't know where the problem lies since I'm trying to connect just as I am in VB.Net.
The VB.Net application is able to connect but the PHP one can't...

Here's how I'm trying to connect in PHP:


```
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, $host, $port);
```

These lines would equivalent to the lines I'm using in VB.Net:


```
        Client = New MessageClient(txtIP.Text, CInt(txtPort.Text))
        Client.Connect()
```

Any ideas?

It seems like the PHP version requires the server socket to accept the connection since there is a method in PHP called socket_accept() which the servers use. 
I haven't read through your entire code but I think that your code accepts automatically, right?

*EDIT* I might also be trying to connect to the wrong IP address. Currently I'm trying to connect to 127.0.0.1 but now I remembered that the file lies on a webhost. So I tried to connect to my external IP but it says that it can't find the host

*EDIT** The error was caused by the webhost which only has some specific ports open (which I didn't know)

----------


## zzyzx

Hi,

I am trying to do client application, which would be connected to multiple servers. Can you help me how to run each connection in a different thread? And  how to pass different address to the new instance (Private WithEvents client As New MessageClient(hostName, remotePort))? 
So that application will be like your demo client, but I would like to start a new instance in the new thread, not in the new form. 
Appreciated the example in the code.

----------


## jmcilhinney

> Hi,
> 
> I am trying to do client application, which would be connected to multiple servers. Can you help me how to run each connection in a different thread? And  how to pass different address to the new instance (Private WithEvents client As New MessageClient(hostName, remotePort))? 
> So that application will be like your demo client, but I would like to start a new instance in the new thread, not in the new form. 
> Appreciated the example in the code.


The whole point of my code is that you simply create the objects, tell them to connect and then tell them to communicate.  Any multi-threading is handled internally, so if you want multiple clients then you simply create multiple clients.  If you want to pass them different addresses then that's what you do.  If you know how to pass one address to one MessageClient object then you know how to pass multiple addresses to multiple objects: it's simply doing the one thing multiple times.

----------


## zzyzx

> The whole point of my code is that you simply create the objects, tell them to connect and then tell them to communicate.  Any multi-threading is handled internally, so if you want multiple clients then you simply create multiple clients.  If you want to pass them different addresses then that's what you do.  If you know how to pass one address to one MessageClient object then you know how to pass multiple addresses to multiple objects: it's simply doing the one thing multiple times.


Probably I need to learn a lot about object programming  :Roll Eyes (Sarcastic): . I try to create a service that will communicate with various hardware modules and write data in database. I'm electronic hobbyst, not the proffessional programmers, so maybe you can help me with following code . 


```
Imports Wunnell.Net
Public Class Form1
    Private ReadOnly host As String = "localhost"
    Private ReadOnly port As Integer = 8081
    Private WithEvents client As New MessageClient(host, port)

    Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        Me.client.Dispose()
    End Sub
    Private Sub connectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles connectButton.Click
        'Me.connectButton.Enabled = False

        'Connect to the server.
        'Me.client.Connect()
    End Sub

    Private Sub sendButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles sendButton.Click
        Dim message = Me.messageTextBox.Text
        Me.client.Send(message)
        Me.UpdateLog(String.Format("Message (=>{0}:{1}): {2}", Me.host, Me.port, message))
        Me.messageTextBox.SelectAll()
        Me.messageTextBox.Select()
    End Sub

    Private Sub PromptToReconnect(ByVal message As String, ByVal caption As String, ByVal icon As MessageBoxIcon)
        Me.sendButton.Enabled = False
        Me.connectButton.Enabled = True

        Select Case MessageBox.Show(message, _
                                    caption, _
                                    MessageBoxButtons.YesNoCancel, _
                                    icon)
            Case Windows.Forms.DialogResult.Yes
                'Try again to connect.
                Me.connectButton.PerformClick()
            Case Windows.Forms.DialogResult.No
                'Do nothing.
            Case Windows.Forms.DialogResult.Cancel
                Me.Close()
        End Select
    End Sub

    Private Sub UpdateLog(ByVal text As String)
        Me.logTextBox.AppendText(text & ControlChars.NewLine)
    End Sub
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        client.Connect()
        AddHandler client.ConnectionAccepted, AddressOf Accepted
        AddHandler client.MessageReceived, AddressOf MessageRecieved
        AddHandler client.ConnectionFailed, AddressOf failed
        AddHandler client.ConnectionClosed, AddressOf cclosed
    End Sub

    Private Sub MessageRecieved(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        Me.UpdateLog(String.Format("Message ({0}=>): {1}", e.Host, e.Message))
    End Sub
    Private Sub failed(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        Me.PromptToReconnect("The specified server could not be found.  Would you like to try again?", _
                     "Connection Failed", _
                     MessageBoxIcon.Error)
    End Sub
    Private Sub cclosed(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
        Me.PromptToReconnect("The connection was closed by the server.  Would you like to reconnect?", _
                                     "Connection Closed", _
                                     MessageBoxIcon.Warning)
    End Sub
    Private Sub Accepted(ByVal Sender As Object, ByVal e As ConnectionEventArgs)
        Dim host = e.Host.ToString()
        Me.Text = String.Format("{0}=>{1}", Me.client.LocalPort, host)
        Me.UpdateLog("Info: Connection accepted to " & host)
        Me.sendButton.Enabled = True
    End Sub
End Class
```

As you can see I put all code on an form and this is the end of my programming knowledge  :Embarrassment:  . Now I need a little help on how to dynamically create objects (clients) which would be connected to different servers.

----------


## Johno2518

Hi jmcilhinney,

Im trying to implement a client server. The server is a Windows Service and the client is a Winforms application. However, the service and client keeps crashing on the following code:

Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
        Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
End Sub

I have read bits and pieces on the synchronizationcontext but don't completely understand it. How would you recommend i fix the code to work. Will i need the old version before you used the synchronisatiocontext or is there a configuration i need to set for it to run under a windows service..?

Help would greatly be appreciated!

Thanks

----------


## jmcilhinney

A crash is an unhandled exception.  An exception has an error message, provided as an aid to diagnosing and fixing the problem.

----------


## Johno2518

Considering this code works on a GUI and not as a service i thought it would be a problem with using the synchronizationcontext which is why i didn't provide the exception. Sorry about that.

The code i posted is throwing this error when wrapped in a try catch block:

Sytem.NullReferenceException {"Object reference not set to an instance of an object."}

It was captured in MessageClientServerBase.vb

Is there any other part of the exception you need..?

The only thing i can think of is that because there is no UI thread in a windows service, this is causing the problem but yeah im unsure of how to resolve it.

----------


## jmcilhinney

> Considering this code works on a GUI and not as a service i thought it would be a problem with using the synchronizationcontext which is why i didn't provide the exception. Sorry about that.
> 
> The code i posted is throwing this error when wrapped in a try catch block:
> 
> Sytem.NullReferenceException {"Object reference not set to an instance of an object."}
> 
> It was captured in MessageClientServerBase.vb
> 
> Is there any other part of the exception you need..?
> ...


If it's working in a WinForms app and not in a service then it is likely that the issue is related to that fact, but it's certainly not definite.  Also, the fact that it's a service specifically means that you CAN'T use the ISynchronizeInvoke interface, because there are no controls to call Invoke on.

The thing is, the reason you need to use either the ISynchronizeInvoke interface or the SynchronizationContext class in a WinForms app is that you can only access your UI controls on the UI thread.  In a Windows service there is no UI, so there's no reason to have to marshal your method call(s) to a specific thread.  Basically, you don't need either.  You can do whatever you want on whatever thread you happen to be on at the time.  You just have to make sure that different threads don't interfere with each other's data.

----------


## Johno2518

So what do i change the synchronizationcontext to..? Instead should i just be raising the relevant event..?

----------


## jmcilhinney

> So what do i change the synchronizationcontext to..? Instead should i just be raising the relevant event..?


You shouldn't be changing it to anything.  You should be getting rid of it because, as I said, you don't need it.  Wherever the Send or Post methods of the SynchronizationContext were used, you just call the delegated method directly, e.g. where you had this:
vb.net Code:
mySynchronizationContext.Send(AddressOf SomeMethod)
you would replace it with this:
vb.net Code:
SomeMethod()

----------


## Johno2518

Ok, i'll give it a go.

Thanks for the information.

Just one more quick question. In the GUI, it raises events in the server. Will this work in a windows service. So if i change it to as you described of calling the method directly, will it still raise events..?

----------


## Johno2518

Thanks for the help. It still raises events, so thats good. I have changed the code to this:




```
  ''' <summary>
    ''' Raises the <see cref="ConnectionAccepted" /> event.
    ''' </summary>
    ''' <param name="e">
    ''' Contains the data for the event.
    ''' </param>
    ''' <remarks>
    ''' The event will be raised on the thread on which the current instance was created.
    ''' </remarks>
    Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
        Try
            Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
        Catch Ex As Exception
            RaiseConnectionAccepted(e)
        End Try
    End Sub

    ''' <summary>
    ''' Raises the <see cref="ConnectionClosed" /> event.
    ''' </summary>
    ''' <param name="e">
    ''' Contains the data for the event.
    ''' </param>
    ''' <remarks>
    ''' The event will be raised on the thread on which the current instance was created.
    ''' </remarks>
    Protected Overridable Sub OnConnectionClosed(ByVal e As ConnectionEventArgs)
        Try
            Me._synchronisingContext.Post(AddressOf RaiseConnectionClosed, e)
        Catch Ex As Exception
            RaiseConnectionClosed(e)
        End Try
    End Sub

    ''' <summary>
    ''' Raises the <see cref="MessageReceived" /> event.
    ''' </summary>
    ''' <param name="e">
    ''' Contains the data for the event.
    ''' </param>
    ''' <remarks>
    ''' The event will be raised on the thread on which the current instance was created.
    ''' </remarks>
    Protected Overridable Sub OnMessageReceived(ByVal e As MessageReceivedEventArgs)
        Try
            Me._synchronisingContext.Post(AddressOf RaiseMessageReceived, e)
        Catch Ex As Exception
            RaiseMessageReceived(e)
        End Try
    End Sub
```

The reason is this code needs to be portable for clients and servers that may run in a service or winforms application. I know its not that ellegant, but it tries to use the standard code (for winforms) and if it fails because its running as a service it uses the other code to raise the event.

If there is a better way of detecting what kind of thread is being run, please let me know. At the moment this works and is all i need for the time being but would appreciate some detection code sample (if any exists).

Thanks again!

----------


## jmcilhinney

> The reason is this code needs to be portable for clients and servers that may run in a service or winforms application. I know its not that ellegant, but it tries to use the standard code (for winforms) and if it fails because its running as a service it uses the other code to raise the event.
> 
> If there is a better way of detecting what kind of thread is being run, please let me know. At the moment this works and is all i need for the time being but would appreciate some detection code sample (if any exists).
> 
> Thanks again!


I do wish that people would provide the whole story up-front.  If you're trying to write code that can handle two different situations then that's going to be different to code that handles just the first situation and different again to code that handles just the second situation.  If you want a solution then we need to know what problem we're solving.  If you only provide half the relevant information then you're unlikely to get a working solution.  Keep that in mind when posting in future.

Anyway, you said originally that you got a NullReferenceException.  That is presumably because Me._synchronisingContext is Nothing, which is presumably the case because SynchronizingContext.Current returns Nothing when not in either a WinForms or WPF application.  As is always the case, you shouldn't try to do something and then clean up when it fails if it would be simple to check whether the action is valid beforehand.  In this case, that check is indeed very simple:
vb.net Code:
If Me._synchronisingContext Is Nothing Then
    'No synchronisation required.
    RaiseConnectionAccepted(e)
Else
    'Marshal a call to the main thread.
    Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
End If

----------


## Johno2518

Originally i only wanted it to work for a service, but i then thought more about the typical usage of the DLL which could comprise of both.

I changed my mind on how i was going to use the library. Your last reply makes sense.

My solution was just a quick one to see if it resolved the situation for the time being.

Thanks for the help. Greatly appreciated  :Smilie:

----------


## darkdemon28

I was sent to this thread by a user on the MS Forumns site. The project makes absolutely no sense to me what so ever. I've migrated over from VB6 and have been nearly tearing my hair out trying to build a simple Client/Server app but it just won't work! Then I saw this solution from the guy who suggested it and it made me even more angry because I don't understand it at all. OK I'm very new to vb.net and refuse to go "back to school" as I've hear the phrase used before. When I read the sample code it didnt have anything in there about how to accept the connection from the client or how to put the received message/text into a simple text box, absolutely nothing! I'm sorry but I HATE people that produce what they call easy to use solutions that are as complicated as hell to use!

Erm hello, a tutorial might be nice instead of a project that yeah works but doesnt show how to do any of the things I want to do, simply or simplicity is what im looking for NOT complicated. I'm sorry but I don't understand properties, methods etc... that well in Vb.net. Why can't someone just come up with a simple solution to the problem that doesn't include 101 references here and there and everywhere!

Client: One text box, one button ("Send"), one button ("Connect") :-
Click Connect, Write in the text box "Hello world", Click Send = Job Done!
Simple code to do this please!

Server: One text box
Sub Routine to accept connection, process message/text received :-
Message Received and processed : Put into the text box = Job Done!
Simple code to do this please!

Someone for pittys sake work with me on this, I have a major problem and stress out very very easily and become angry very quickly (its called a brain defect - not enough of a chemical allowing me to retain control of myself - rather like ADHD), my apologies for any offence but can't help it.

Dave.

----------


## Hack

First off, the solution posted here is simple...very simple.  In fact, given the task, and the language, I'm not sure how you could write the code to do it any more simply.   This is *NOT* complicated, providing you have some experience in VB.NET.

However, there may be a couple of reasons why you think it is complicated.

Reasons such as...


> OK I'm very new to VB.net


And



> I'm sorry but I don't understand properties, methods etc... that well in Vb.net.


At this point in your VB.NET career I would venture to say that, given those two things, nearly everything will be complicated for you.    It will continue to be complicated for you until you have the one thing you don't have now, and that is experience.

Second, I don't care about your medical conditions and I don't care about your emotional state.   What I do care about is your attitude and that needs to be addressed if you wish to continue be a member in good standing on this web site.

----------


## Shinra

> There was no problem per se.  The way I was doing it originally, i.e. with a SynchronisingObject property, is the same as some classes in the Framework do it.  One advantage of this is that it gives you the choice of leaving the SynchronisingObject property empty and having events raised on a thread pool thread or setting it and having events raised on a specific thread.  I didn't really see a reason why you specifically want my classes to raise their events on thread pool threads though, so the change I made did three things for me:
> 
> 1. It meant that a caller could completely ignore the fact that there was multi-threading involved and, in fact, wouldn't even know it from the interface.  All interaction with an instance of one of my classes would occur on the same thread without any indication that any other threads were involved.  There was no need for the caller to go to the (admittedly tiny) effort of setting the SynchronisingObject property to get synchronous events.
> 
> 2. It made my code a bit cleaner.
> 
> 3. It gave me a chance to play with the SynchronizationContext class, which I haven't had the pleasure of previously.
> 
> Like I said, there was nothing actually wrong with the old implementation.  If you're interested in doing something similar but aren't 100% sure how then I'm happy to provide the old code.  That said, you might also be interested in using the SynchronizationContext class as the new code does.


can you provide me with the old source plz? i would like to see the difference.
thankyou before.

----------


## jmcilhinney

> can you provide me with the old source plz? i would like to see the difference.
> thankyou before.


I don't actually have the old code anymore, but I can certainly recreate it without too much trouble.  When I get a chance today, I'll re-implement one of the classes that currently uses a SynchronizationContext and give it a SynchronisingObject property.

----------


## jmcilhinney

> can you provide me with the old source plz? i would like to see the difference.
> thankyou before.


It took a little longer to get around to it than I planned but I've redone the project so that the MessageClient and MessageServer classes now use a SynchronisingObject property.  Do a "Find in Files" on that and you'll find all the changes.

----------


## i00

I keep getting "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host." aswell .. me on line "Dim byteCount = stream.EndRead(ar)" of MessageServer.Read - it's in a try catch and still throws the error  :Frown: 

Anyone solved this?

Thanks
Kris

----------


## i00

Um... how am i supposed to uniquely identify a user ...

Just say I have a LAN of 100 people accessing a remote server across the net - to the server they all will have the same IP address and the MessageReceived etc events just pass around the HostInfo structure that only contains the IP and port but nothing to uniquely identify each connection.

Thanks
Kris

----------


## i00

all good ... by the port... whops

----------


## i00

um... also i am using:

Data = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.Unicode.GetBytes(e.message))

to convert the MessageReceived Response to ascii... but if the data is split across one send on the client (sent in vb script with windsock) the Data has some rubbish chrs at the end and the first received message and the 2nd received message has some rubbish chrs at the begining of data.

Is it possible to talk more natively in ascii rather than having to convert from unicode?

Thanks
Kris

----------


## jmcilhinney

> um... also i am using:
> 
> Data = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.Unicode.GetBytes(e.message))
> 
> to convert the MessageReceived Response to ascii... but if the data is split across one send on the client (sent in vb script with windsock) the Data has some rubbish chrs at the end and the first received message and the 2nd received message has some rubbish chrs at the begining of data.
> 
> Is it possible to talk more natively in ascii rather than having to convert from unicode?
> 
> Thanks
> Kris


If you want to pass the data as ASCII then just call ASCII.GetBytes when sending and ASCII.GetString when receiving.  Once you convert a String to binary though, you MUST convert that binary back to a String using the same encoding.  Think about it.  Binary data is just numbers.  It's how you interpret those numbers that gives them meaning.  If you have a set of numbers that represents some Unicode text, how can you convert it to text using ASCII and expect to get a sensible result?

----------


## jmcilhinney

By the way, I didn't in my code but you can use a StreamWriter to write to the NetworkStream at one end and a StreamReader to read the NetworkStream at the other.  You simply provide the Stream and the Encoding when you create them and then use them in the same way as you would to read or write a file.

----------


## i00

> If you want to pass the data as ASCII then just call ASCII.GetBytes when sending and ASCII.GetString when receiving.  Once you convert a String to binary though, you MUST convert that binary back to a String using the same encoding.  Think about it.  Binary data is just numbers.  It's how you interpret those numbers that gives them meaning.  If you have a set of numbers that represents some Unicode text, how can you convert it to text using ASCII and expect to get a sensible result?


I am using ascii.getstring when receiving ... and it is putting the junk there

and the data was sent in ascii with the clients ... the clients use winsock in a vb script btw...

Kris

----------


## jmcilhinney

If the client sent the data as ASCII then you can read it as ASCII.  If there's junk in the data then it was put there by the client.  They must be adding some sort of header and/or footer to the data.  If you can send ASCII data using a TcpClient and read it correctly using your server then you know it's not the server that's the issue.  You need to determine what that header/footer is so that you can parse it and remove it from the data.

----------


## i00

Great - 99&#37; working now ... but this error makes it unusable (see attached screenshot)

Thanks
Kris

----------


## i00

Just had another error on the same line this one reads: "Unable to read data from the transport connection: EndReceive can only be called once for each asynchronous operation.."

----------


## i00

This is the stack trace for "Unable to read data from the transport connection: EndReceive can only be called once for each asynchronous operation.." that occurs on the line "Dim byteCount = stream.EndRead(ar)"



```
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at Wunnell.Net.MessageServer.Read(IAsyncResult ar) in C:\SARAH Registration Server\SARAH Registration Server\Wunnell.Net.MessageClientServer\MessageServer.vb:line 452
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
```

Any ideas?

Thanks
Kris

----------


## i00

The call stack for the "forcibly closed" error is:



```
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at Wunnell.Net.MessageServer.Read(IAsyncResult ar) in C:\SARAH Registration Server\SARAH Registration Server\Wunnell.Net.MessageClientServer\MessageServer.vb:line 452
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
```

----------


## jmcilhinney

I just thought that I mention that I'm not ignoring these posts.  I just don't know the solution because I have never encountered these errors and I don;t have the time for extensive testing right now.  You might do better to post in the VB.NET forum about this specific problem and link back to this thread.  Someone may have solved a similar issue who would not ever see your question in this thread.

----------


## i00

Also get another error occasionally - does not take me to a line though ...

Error is: "Exception has been thrown by the target of an invocation."

This is the call stack:



```
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)\r\n
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)\r\n
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)\r\n
   at System.Delegate.DynamicInvokeImpl(Object[] args)\r\n
   at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)\r\n
   at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)\r\n
   at System.Threading.ExecutionContext.runTryCode(Object userData)\r\n
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)\r\n
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)\r\n
   at System.Windows.Forms.Control.InvokeMarshaledCallbacks()\r\n
   at System.Windows.Forms.Control.WndProc(Message& m)\r\n
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)\r\n
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)\r\n
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)\r\n
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)\r\n
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)\r\n
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)\r\n
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)\r\n
   at System.Windows.Forms.Application.Run(ApplicationContext context)\r\n
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()\r\n
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()\r\n
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)\r\n
   at SARAH_Registration_Server.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81\r\n
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)\r\n
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)\r\n
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()\r\n
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)\r\n
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n
   at System.Threading.ThreadHelper.ThreadStart()
```

----------


## jmcilhinney

> Also get another error occasionally - does not take me to a line though ...
> 
> Error is: "Exception has been thrown by the target of an invocation."


That error message occurs on the original thread when an exception occurs on a secondary thread.  It's a safe bet that the original exception is being thrown in one of the callbacks.  Is there an inner exception?  There should be and that should contain the original exception.

----------


## Pc_Not_Mac

Very nice example.

----------


## ThomasJohnsen

Also thank you from Denmark  :Thumb: .
This piece of code is simple, well-commented and very easy to expand upon.

I'm using a rewritten version of the code (allowing encryption, signatures and more complex data-transmission) with great success as an integrated part of a larger solution. There are occasional minor problems, that probably ties to the rewrites, but I'll mention one here anyways, since the solution may be helpful:
* Loss of net on either side caused an unhandled exception, that had to be handled in an application-event (NetworkAvailabilityChanged).

Regards and thanks again
Tom

----------


## i00

I am using this to talk between a vb6 winsock control

and all seems to be working well except for one thing...

I can receive data with no problems from the .net server, but when i send it i get no errors... the vb6 app just never receives the data - never had a problem before with the vb6 server that i used to use.

Any ideas?

Thanks
Kris

----------


## jmcilhinney

> I am using this to talk between a vb6 winsock control
> 
> and all seems to be working well except for one thing...
> 
> I can receive data with no problems from the .net server, but when i send it i get no errors... the vb6 app just never receives the data - never had a problem before with the vb6 server that i used to use.
> 
> Any ideas?
> 
> Thanks
> Kris


None I'm afraid.

----------


## i00

dw worked it out

Kris

----------


## i00

Great stuff all working well as an app ... just when i make it a service i get the following error:



```
System.NullReferenceException was unhandled
  Message="Object reference not set to an instance of an object."
  Source="Wunnell.Net.MessageClientServer"
  StackTrace:
       at Wunnell.Net.MessageClientServerBase.OnConnectionAccepted(ConnectionEventArgs e)
       at Wunnell.Net.MessageServer.AcceptTcpClient(IAsyncResult ar)
       at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
       at System.Net.ContextAwareResult.CompleteCallback(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Net.ContextAwareResult.Complete(IntPtr userToken)
       at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
       at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
       at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
  InnerException:
```

(No inner exception)

I made a test app that does the following (only one user connects to the test app so didnt bother having a message buffer for each user):

The test app throws the same error...

The test app consists of:


vb Code:
Public Class Service1
     Private WithEvents server As Wunnell.Net.MessageServer
     Protected Overrides Sub OnStart(ByVal args() As String)
        server = New Wunnell.Net.MessageServer(8016)
    End Sub
     Protected Overrides Sub OnStop()
        server.Dispose()
    End Sub
     Dim message As String
     Private Sub server_MessageReceived(ByVal sender As Object, ByVal e As Wunnell.Net.MessageReceivedEventArgs) Handles server.MessageReceived
        message &= e.Message
        Dim arrMessage = Split(message, vbCrLf)
        For i = LBound(arrMessage) To UBound(arrMessage)
            If i = UBound(arrMessage) Then
                'we are the last one
                message = arrMessage(i)
            Else
                If LCase(arrMessage(i)) = "action:ping" Then
                    server.Send(e.Host, "Action:pong" & vbCrLf)
                End If
            End If
        Next
    End Sub
End Class

any ideas?

Thanks
Kris

----------


## jmcilhinney

The exception is telling you that there's a NullReferenceException in MessageClientServerBase.OnConnectionAccepted.  What line is it thrown on and what reference on that line is Nothing?

----------


## i00

hrm ..ok ... the following was causing the issue:


vb Code:
Private _synchronisingContext As SynchronizationContext = SynchronizationContext.Current

Worked fine after changing to:


vb Code:
Private _synchronisingContext As New SynchronizationContext

----------


## i00

> The exception is telling you that there's a NullReferenceException in MessageClientServerBase.OnConnectionAccepted.  What line is it thrown on and what reference on that line is Nothing?


Fixed as mentioned above ... and it was this throwing it:


vb Code:
Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
        Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
    End Sub

_synchronisingContext was nothing

Regards
Kris

----------


## jmcilhinney

That's because the SynchronizationContext class only works in WinForms and WPF applications.  It's purpose is to marshal a method call to the UI thread.  There's no UI in a Windows service so there's no UI.  There's no need to marshal method calls to a specific thread to updated controls so the SynchronizationContext class is not relevant.

----------


## berniesf

Lovely work!  :Smilie:  Congratulations. I have to admit you saved me some billions years to make a lib like this hehehe.

I have one doubt. I observed you used Dim buffer As Byte() = Me.Encoding.GetBytes(message), in Send methods, to send data. I can remove this, and send data in ascii instead? is safe to do this? why do you use encoding? (just a curiosity)

Again, thanks for this great job!

Bernardo Salazar
Venezuela

----------


## berniesf

Ready, im figured out how to transmit and receive in ASCII. Just replaced Me.Encoding.GetString with Me.Encoding.ASCII.GetString in server and client classes, rebuilded de DLL, and voila!

Sorry for disturbing you in programmer's olympus! hehehehe  :Stick Out Tongue:

----------


## jmcilhinney

> Ready, im figured out how to transmit and receive in ASCII. Just replaced Me.Encoding.GetString with Me.Encoding.ASCII.GetString in server and client classes, rebuilded de DLL, and voila!
> 
> Sorry for disturbing you in programmer's olympus! hehehehe


That may get the job done but it's not the right way to do it. If you want to convert text to binary or vice versa then you need to use an Encoding object. ASCII is just an Encoding object that encodes in ASCII. If you wanted to use ASCII then you should have done one of two things:

1. Assigned System.Text.Encoding.ASCII to the Encoding property and used the code as is.
2. Got rid of the Encoding property and just used System.Text.Encoding.ASCII.GetBytes and .GetString instead.

----------


## berniesf

Efectively, im replaced the line Me.Encoding.ASCII.GetString (that line give me a warning) with System.Text.Encoding.ASCII.GetString and all is working as suposed to do. Many thanks, and congratulations for your cool project.  :wave:

----------


## berniesf

Hi, im back again with a little question  :big yellow:  
Im added a dictionary (string, date) to project, everytime clients transmit data (key are host: port, value are hour), updates the dictionary with the last hour of transmition. A timer see every 30 seconds the dictionary, if any value are greater than 60 minutes, it remove from combobox and dictionary, but... how i can remove from hosts list and how close the port used? i see in MessageServer class a private sub called RemoveClient. Its possible to invoke that sub to close the port inside my app? or another mechanism to close a port and remove from hosts list?(i am making this 'cos sometimes clients disconnects and server keep port open, in this way i close the unused ports).  Thanks again!

----------


## jmcilhinney

> Hi, im back again with a little question  
> Im added a dictionary (string, date) to project, everytime clients transmit data (key are host: port, value are hour), updates the dictionary with the last hour of transmition. A timer see every 30 seconds the dictionary, if any value are greater than 60 minutes, it remove from combobox and dictionary, but... how i can remove from hosts list and how close the port used? i see in MessageServer class a private sub called RemoveClient. Its possible to invoke that sub to close the port inside my app? or another mechanism to close a port and remove from hosts list?(i am making this 'cos sometimes clients disconnects and server keep port open, in this way i close the unused ports).  Thanks again!


You are only using one port at the server end.  If you want to close a client connection then call Close on the TcpClient.

----------


## berniesf

Sorry for disturbing you... how can call TcpClient close from inside server app? i have some minutes trying but nothing, my level of expertise are very low.  :Frown:

----------


## jmcilhinney

> Sorry for disturbing you... how can call TcpClient close from inside server app? i have some minutes trying but nothing, my level of expertise are very low.


When you accept a connection from a client a TcpClient is created.  If you want to close that connection then you call Close on that TcpClient.

----------


## berniesf

Hi again!

After tons of coffee cups, boxes of cigarrettes, and an attemp to commit suicide  :Stick Out Tongue:  i have this:

    Public Sub TerminateClient(Host As String)
        For Each client As KeyValuePair(Of TcpClient, HostInfo) In Me.clients
            If client.Value.ToString = Host Then
                Me.RemoveClient(client.Key)
                Exit For
            End If
        Next
    End Sub

I added to MessageServer class. Its right?
Greetings from Venezuela

----------


## jmcilhinney

Does that RemoveClient method call Close on the TcpClient?

Also, from that code alone, it looks like the HostInfo should be the keys and the TcpClient should be the value.  Are you using a TcpClient to get a HostInfo from that Dictionary anywhere else?  If not then you should switch them.

----------


## berniesf

Hi JMCILHINNEY!

Let me comment mi Sub. I call RemoveClient, 'cos i observed you call that routine when error occurs on Read sub on MessageServer class. I think this remove client. 
Im using the dictionary that is declared at the very beginning of the MessageServer class, is declared in this way:

    Private ReadOnly clients As New Dictionary(Of TcpClient, HostInfo)

MessageServer add a element to this dictonary on AcceptTCPClient

            'Remember the client and its host information.
            Me.clients.Add(client, host)

After studying your code (mainly MessageServer class), i made the routine that i posted before, but i dont know if im in the right path.

Greetings!

Bernardo Salazar

----------


## creativedas

Dear Mr. jmcilhinney,

Your Message Client-Server is an amazing program that works fine. But, it has some problem with the following issues. Can you tell me how can I fix that?

*Problem*
When the client computer gets shutdown due to a power lose or something it raises an error.

"IO Exception was unhandled"

Error Message:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.


The same happens on the client side too.

Can you fix the problem please?

Thanks in advance.




















fashion games, utorrent

----------


## jmcilhinney

> Dear Mr. jmcilhinney,
> 
> Your Message Client-Server is an amazing program that works fine. But, it has some problem with the following issues. Can you tell me how can I fix that?
> 
> *Problem*
> When the client computer gets shutdown due to a power lose or something it raises an error.
> 
> "IO Exception was unhandled"
> 
> ...


You can see that there are various exception handlers in the code to handle various situations like that.  This sounds like one more like that that you can add for yourself.

----------


## ForumAccount

> Nice to see that it wasnt just me that had to ignore the ObjectDisposed exception when calling EndAcceptTcpClient. Same for the IOException when calling EndRead.
> I assumed there was a better way to handle this that I just couldnt figure out but seeing you do the same thing makes me feel a bit better about it





> Yeah, I was hunting and hunting for some property that I could test before calling EndWhatever but I couldn't find anything, so I can only assume that catching the exceptions is the only way to go.


You two might be interested in this: VS 2010 [RESOLVED] Checking for an error before it happens [TcpListener] 

I've also taken a look at the IOException that you are seeing when you call EndRead on a disposed client stream. Looks like this occurs when the internal Socket is null. You could run this check against the stream:


```
Imports System.Reflection
Imports System.Net.Sockets

''' <summary>
''' Provides various Tcp related functions.
''' </summary>
Public NotInheritable Class TcpUtilities

    '//fields
    Private Shared ReadOnly SocketPropertyInfo As PropertyInfo

    '//constructors
    Shared Sub New()
        TcpUtilities.SocketPropertyInfo = GetType(NetworkStream).GetProperty("Socket", _
                                                  BindingFlags.NonPublic Or _
                                                  BindingFlags.Instance)
    End Sub

    Private Sub New()
    End Sub

    '//functions
    ''' <summary>
    ''' Determines whether you can safely call <see cref="NetworkStream.EndRead">EndRead</see> 
    ''' on a <see cref="NetworkStream">NetworkStream</see> object.
    ''' </summary>
    ''' <param name="stream">
    ''' The <see cref="NetworkStream">NetworkStream</see>
    ''' to test.
    ''' </param>
    Public Shared Function CanEndRead(ByVal stream As NetworkStream) As Boolean
        If stream IsNot Nothing Then
            Dim value = TcpUtilities.SocketPropertyInfo.GetValue(stream, Nothing)
            Return value IsNot Nothing
        End If
        Return False
    End Function

End Class
```

I realize it utilities Reflection, but it really shouldn't be that slow.

----------


## macdaddy2

Thank you jmcilhinney!  I have been searching for a way to add tcp communication to one of my applications for over a week and happened upon this example.  It worked perfectly right out of the box.  My only tweak was to send serialized objects instead of free form text.  This project saved me a lot of time!

As a side note, even though it wasn't the intended purpose, this project is also a great example of how to use inheritance in a real world situation.

Thanks again!

----------


## sherrel

Hi.  Newbie here.  :Confused: 

I would like to try and write a program in VB 2010 that queries and receives data to/from a technical instrument (an RF spectrum analyzer).  The analyzer requires that the ASCII codes STX (0x02 - start of text) and ETX (0x03 - end of text) be sent to it before and after each query (example - Chr(STX) & "frequency?" & Chr(ETX) ).  The analyzer only accepts the standard 128 character ASCII table.

I believe that I read that* jmcilhinney*'s *Wunnell* code converts everything to binary before sending, because it expects the server to translate it back (so as to accommodate unicode characters).

Can anybody tell me what lines need to be changed in order to send and receive standard ASCII?

----------


## jmcilhinney

> I believe that I read that* jmcilhinney*'s *Wunnell* code converts everything to binary before sending, because it expects the server to translate it back (so as to accommodate unicode characters).
> 
> Can anybody tell me what lines need to be changed in order to send and receive standard ASCII?


It's not to accommodate Unicode characters.  It's because bytes are the only thing you can transmit.  Any data that you want to transmit must be converted to a Byte array  It's then up to the server to interpret those bytes in the appropriate way.  In your case, you just need to make sure that you use an ASCIIEncoding object to convert your text to Bytes, i.e. use System.Text.Encoding.ASCII.GetBytes().  I'm not sure whether that's what I do in the code here but, if not, the only difference would the actual encoding object.  All the rest would be the same.

----------


## sherrel

OK.  I think I see in the client transmit code where I would change *Dim buffer As Byte() = Me.Encoding.GetBytes(message)* to *Dim buffer As Byte() = System.Text.Encoding.ASCII.GetBytes(message)* in the MessageClient.vb file; is that not correct?

But I don't seem to be able to locate where I would change the decoding for the client receive in order to receive ASCII from the spectrum analyzer instead of binary.  Or am I completely misunderstanding things?   :Confused: 

FYI.  My project will be to send a series of 12 standard queries to the analyzer (such as frequency?, bandwidth?, reference level?, etc.), and to receive back 11 answers, and the response to the 12th query will consist of about 4000 bytes representing the data points of the trace displayed on the analyzer  screen.  I will stuff all this into a .CSV file for later analysis by another pre-written program.

----------


## jmcilhinney

In that code of mine, Me.Encoding is an Encoding object.  If you simply assign System.Text.Encoding.ASCII to that property then you don't have to change my code at all.

As for receiving data, there would be a corresponding call to the GetString method of an Encoding object.  You simply use an ASCIIEncoding object read, just as you did to write.

----------


## ibennz

Very nice work !!! but could you help me how set my ip address to allow two pc (not on lan) to connect on it. I tried ip forward unsuccesfully . looked for NaT . Didn't understood . My ip is already static. Is there a way to do it via codes on vb2008?

----------


## jmcilhinney

> Is there a way to do it via codes on vb2008?


No.  It's a router issue and well beyond the scope of this thread.

----------


## ibennz

I need a little help with :
Private WithEvents server As New MessageServer(port) 

How to make the listner listen on a specific IP adress? since user IP wont be forwarded , i wanted also them to use the server form.

----------


## jmcilhinney

> How to make the listner listen on a specific IP adress?


If you're asking that question then you haven't actually read the code.  I don't have the time, or the inclination, to explain every little detail to everyone.  That's why I provided copious comments throughout the code.  Read them.

----------


## ibennz

The thing is I read all ur code.. I changed this :



```
    Public Sub New()
    
        Me.Initialise(IPAddress.Any, 0)
    End Sub
```

To this :


```
   Public Sub New()
        Dim ExtIp As IPAddress = IPAddress.Parse("_external ip")

        Me.Initialise(ExtIp, 3000)
    End Sub
```

The server form still doesnt work on other pc . I changed down some others setting that was related to server IP/Port and the application just crashed. So If you dont mind, I would need your help. Thanks in advance.

----------


## jmcilhinney

> The thing is I read all ur code.. I changed this :
> 
> 
> 
> ```
>     Public Sub New()
>     
>         Me.Initialise(IPAddress.Any, 0)
>     End Sub
> ...


You obviously didn't read it properly because the MessageServer has multiple constructors and at least one of them, I believe more than one, allow you to specify an IP address.  You don't have to change any code in the MessageServer class at all.  You simply have to create the MessageServer instance with the appropriate constructor.

----------


## ibennz

I tried that already : 



```
 Private WithEvents server As New MessageServer("External_ip")
```

event that:


```
 Private WithEvents server As New MessageServer("External_ip:Port")
```

Application crash. Any clue ?

----------


## jmcilhinney

> I tried that already : 
> 
> 
> 
> ```
>  Private WithEvents server As New MessageServer("External_ip")
> ```
> 
> event that:
> ...


I must have missed where you mentioned that you'd already tried that.  I must also have missed where you provided information about the exception that occurred.  If I seem a bit miffed it's because I am.  I'm more than happy to help with legitimate issues but all this back and forth because you're not reading information already providing and you're not providing information required to diagnose the issue is a big waste of my time.  I shouldn't have to ask for an error message.

----------


## ibennz

Im using my external ip .(forwarded) I tried with local ip (127.0.0.1) and worked . Also with my internal IP4 Address(only on current pc , when i send it to friend . Doesn't ). Any clue?



```
System.InvalidOperationException was unhandled
  Message="An  error; is produced during the creation of the form. For more information, consult Exception.InnerException.  error is: The required address is not valid in its context"
  Source="testoi"
  StackTrace:
       &#224; testoi.My.MyProject.MyForms.Create__Instance__[T](T Instance) dans 17d14f5c-a337-4978-8281-53493378c1071.vb:ligne 190
       &#224; testoi.My.MyProject.MyForms.get_Form1()
       &#224; testoi.My.MyApplication.OnCreateMainForm() dans C:\Users\user\AppData\Local\Temporary Projects\testoi\My Project\Application.Designer.vb:ligne 35
       &#224; Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       &#224; Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       &#224; Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       &#224; testoi.My.MyApplication.Main(String[] Args) dans 17d14f5c-a337-4978-8281-53493378c1071.vb:ligne 81
       &#224; System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       &#224; Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       &#224; System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       &#224; System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Net.Sockets.SocketException
       Message="The required address is not valid in its context"
       Source="System"
       ErrorCode=10049
       NativeErrorCode=10049
       StackTrace:
            &#224; System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
            &#224; System.Net.Sockets.Socket.Bind(EndPoint localEP)
            &#224; System.Net.Sockets.TcpListener.Start(Int32 backlog)
            &#224; Wunnell.Net.MessageServer.Initialise(IPAddress ipAddress, Int32 port)
            &#224; Wunnell.Net.MessageServer..ctor(String address, Int32 port)
            &#224; testoi.Form1..ctor() dans C:\Users\user\AppData\Local\Temporary Projects\testoi\Form1.vb:ligne 4
       InnerException:
```

----------


## lastly

I am completely new to vb.  When I try to run this I am getting the following message:

"a project with an Ouput Type of Class Library cannot be started directly.  In order to debug this project, add an executable project to this solution which references the library project.  Set the executable project as the startup project."

I have no idea what this means or how to do this.  When I click under Client Test and try to run in debug mode I get this message.  What should I do?

----------


## jmcilhinney

> I am completely new to vb.  When I try to run this I am getting the following message:
> 
> "a project with an Ouput Type of Class Library cannot be started directly.  In order to debug this project, add an executable project to this solution which references the library project.  Set the executable project as the startup project."
> 
> I have no idea what this means or how to do this.  When I click under Client Test and try to run in debug mode I get this message.  What should I do?


You've got the wrong project selected as the startup project for the solution.  In the Solution Explorer, right-click the appropriate project and select it as the startup project.

I have to say though, if you don't know that then the concepts demonstrated by this solution will almost certainly be a mystery to you.  Maybe you should get a good grasp of the basics and start with simpler things before trying to tackle this sort of thing.

----------


## ibennz

@ jmcilhinney well I heard you cant listen on other ip than these avaible on the machine. So I guess tcp communication is useless If you dont forward the ip/port on the pc you are actually using. Ive also tried to figure if there was a way to open a port and send the message ignoring about the fact the ip isnt forwarded or static . Doesn't worked. Also trying to look if there is a way to forward or create a temporary IP to allow communication , But no success . So if you have any tips , I would appreciated. Looked also on socket side and winsock , both are almost the same than .net tcpListner. Looked UDP , same and API isnt what i was looking for. FTP have too much issues and it doesnt keep direct connection like TCP. If there is any other type of communication also that is similar to TCP , I would appreciate few links . Thanks in advance.

And if you know about this : 



```
Re: Access Visual Studio Development Server from other pc
Jun 22, 2009 03:46 PM|LINK

Hi, I understand this issue has been closed for a while but will post this here for the sake of anyone else looking for an answer. If you want to connect to your development server from a remote box you can do it my redirecting the request through a proxy on your local machine. Using something like MSSoapT does the trick nicely and it also allows you to see the SOAP or whatever content you are sending or receiving. Hope this helps someone!
```

----------


## ibennz

Which kind of encoding you are using ? When I try to send data from anyother client it doesn't decode it correctly . 



```
Try
                Dim str As String = Me.Text
                Dim sw As IO.StreamWriter
                Try
                    sw = New IO.StreamWriter(client.GetStream)
                    sw.Write(str)
                    sw.Flush()
                Catch ex As Exception

                End Try
            Catch ex As Exception

            End Try
```

I was able to decode the sent info of your server to my client by trying the encode methode. But I dont know how encode text and sent it in the right format to allow your server to read it . There is the code I used to read the previous information sent to my client.



```
 Private Sub DoRead(ByVal ar As System.IAsyncResult)
      
        Dim totalRead As Integer
        Try
            totalRead = client.GetStream.EndRead(ar) 'Ends the reading and returns the number of bytes read.
        Catch ex As Exception
            'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections            'to this client and remove it from the list of connected clients.
        End Try
        If totalRead > 0 Then
            'the readBuffer array will contain everything read from the client
            Dim receivedString As String = System.Text.Encoding.Unicode.GetString(readBuffer, 0, totalRead)
            MessageReceived(receivedString)
        End If
        Try
            client.GetStream.BeginRead(readBuffer, 0, BYTES_TO_READ, AddressOf DoRead, Nothing) 'Begin the reading again.
        Catch ex As Exception
            'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections                'to this client and remove it from the list of connected clients.
        End Try
    End Sub
```

----------


## ibennz

Found out . Encode text as byte then as ASCII:



```
Dim byt As Byte() = System.Text.Encoding.Unicode.GetBytes(Me.Text)
                Dim str As String = System.Text.Encoding.ASCII.GetString(byt)
```

----------


## OBijac

Let me start by saying thanks! This is excellent stuff. It saved me a lot of time writing my own way of communicating over LAN.
I have one problem though which I can't quite figure out why is happening.

When i close the connection (shut down any client) the server automatically shuts down too.  :Confused:  There isn't any error, it just ends.

I work in VS2010. Let me point out that everything else is working properly on both end and that I've used the exact examples as those in the Message Client-Server project. The only difference is that I didn't use MDI form for the client.

Btw, one interesting remark. When I run client minimized, and close him by right clicking on the taskbar and choosing close window, then everything works fine - the Closed connection event is raised on the server side, and most importantly, it continues to run.

Every suggestion would be valuable since I have no clue what to do next.

----------


## OBijac

Whenever I close any client the server shuts down -> unhandled exception. I tried everything I could think of but without result so far...


System.IO.IOException was unhandled
  Message=Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
  Source=System
  StackTrace:
       at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
       at Wunnell.Net.MessageServer.Read(IAsyncResult ar)
       at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
       at System.Net.ContextAwareResult.CompleteCallback(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Net.ContextAwareResult.Complete(IntPtr userToken)
       at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
       at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
       at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
  InnerException: System.Net.Sockets.SocketException
       Message=An existing connection was forcibly closed by the remote host
       Source=System
       ErrorCode=10054
       NativeErrorCode=10054
       StackTrace:
            at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
            at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
       InnerException:

----------


## jmcilhinney

You will see in my code that there are a few places that I am handling and swallowing exceptions that occur due to asynchronous operations in progress when connections are closed.  It sounds like this might be another that you would have to add an exception handler for.

----------


## OBijac

Thx, I'll try that.

Another thing. When you shut down the server, the client detects that and the ConnectionClosed event occurs, along with the prompt to reconnect. But if you start the server again and choose on the client side to try to reconnect, it doesn't work. Any ideas why?

----------


## i00

Doesn't appear to work when started in a thread that isn't the initial application thread  :Frown:  ... as SynchronizationContext.Current returns nothing in this case

Is there a way around this? As I am making a plugin for an application that is closed source and i do not have access to the application thread  :Frown: .

Thanks Kris

----------


## jmcilhinney

SychronizationContex.Current will always return a value no matter what thread your on IF you are in a Windows Forms or WPF application. The point of invoking a method on a specific thread is to be able to access a control directly. Outside of WinForms and WPF there are no controls so there's no need to invoke a method on a specific thread.

If you were in one of those types of apps then the only way that you would not be able to use SynchronizationContext successfully is if the application created the instance of your type in a secondary thread in the first place. If the application developer wants to do that then you simply raise your event or whatever on whatever thread you're on and it's then the app's responsibilty to invoke back to the UI thread.

----------


## jmcilhinney

> Thx, I'll try that.
> 
> Another thing. When you shut down the server, the client detects that and the ConnectionClosed event occurs, along with the prompt to reconnect. But if you start the server again and choose on the client side to try to reconnect, it doesn't work. Any ideas why?


I would have to test to work that out, which I can't do right now, but the first thing that springs to mind is that the port number changes.

----------


## i00

> SychronizationContex.Current will always return a value no matter what thread your on IF you are in a Windows Forms or WPF application. The point of invoking a method on a specific thread is to be able to access a control directly. Outside of WinForms and WPF there are no controls so there's no need to invoke a method on a specific thread.
> 
> If you were in one of those types of apps then the only way that you would not be able to use SynchronizationContext successfully is if the application created the instance of your type in a secondary thread in the first place. If the application developer wants to do that then you simply raise your event or whatever on whatever thread you're on and it's then the app's responsibilty to invoke back to the UI thread.


It is a console application, and i do not have access to the source code of it ... does this mean this method isn't possible?

Thanks
Kris

----------


## OBijac

> I would have to test to work that out, which I can't do right now, but the first thing that springs to mind is that the port number changes.


That has crossed my mind. Is there a way to set the clients port #, rather than randomizing it? (I presume it works that way since it's always different and I couldn't find any variables that points to that)

----------


## Signalman

This looks lie an example of what I am looking for.  the only problem is that when I download it, and load it into VB.net 2010 express, upon pressing F5 to run, it generates an error
'_A Project With an Output type of class library can not be started directly'  In order to debug, as an executable project to this solution which references the library project.  Set the executable project as the startup project.  _ 

This does not make any scene to me  :Sick:

----------


## jmcilhinney

> This looks lie an example of what I am looking for.  the only problem is that when I download it, and load it into VB.net 2010 express, upon pressing F5 to run, it generates an error
> '_A Project With an Output type of class library can not be started directly'  In order to debug, as an executable project to this solution which references the library project.  Set the executable project as the startup project.  _ 
> 
> This does not make any scene to me


That's because you haven't set the startup project of the solution properly.  The IDE has probably selected the first project by default or whatever project you currently have open.  You need to explicitly select the application project as the startup project, not a library project.

----------


## Signalman

thanks, that's got it working.  All I have got to do is work out how the prog works & incorporate it into my project.  :wave:  :wave:  :wave:

----------


## OBijac

> You will see in my code that there are a few places that I am handling and swallowing exceptions that occur due to asynchronous operations in progress when connections are closed.  It sounds like this might be another that you would have to add an exception handler for.


Tried catching exceptions everywhere and without luck.

I returned to your original example project and the same thing happened there too. I use VS2010 (.net 4) and convert your project with 0 errors so I guess it should work.

Once again, the issue is this. When connected, if you terminate the client for any reason (for example, manually end the client process), the server crashes and reports the following: An unhandled exception ("System.IO.IOException") occured in Wunnell.MessageServerTest.exe [5580].

I'm a newb when it comes to writing this type of applications, but I have a hunch this has to do with disposing the client. If the client simply ends - the server crashes, but if I do a "Me.client.Dispose()" before it ends - everything checks out fine. The problem is, when the client process ends (and it could happen for various reasons) I'm unable to dispose the client because your ClientWindow_FormClosed event never occurs...

If this makes any sense to you, please help  :Smilie:

----------


## scorpydude

Removed

----------


## OBijac

Any idea what to do next?

----------


## jmcilhinney

If there's an unhandled exception then you can handle the exception.  You're obviously not doing it in the right place or else you're trying to catch the wrong type of exception.

----------


## scorpydude

removed

----------


## OBijac

> If there's an unhandled exception then you can handle the exception.  You're obviously not doing it in the right place or else you're trying to catch the wrong type of exception.


When you're right - you're right!  :Smilie:  I was doing it the wrong way.
Thank you very much for the help. One thing still puzzles me. Could you tell me, how could I set the port # of the Client's local end of the connection?

You see, if the Client's connection with the Server is lost, and restored back again, the prompt to reconnect won't work.
As you wrote earlier, this is probably because the port # changes.



> I would have to test to work that out, which I can't do right now, but the first thing that springs to mind is that the port number changes.

----------


## salinski

Hi ¡

i've used this library and works fine¡ thanks¡

but, i've found a possible issue, the initial SEQuence number at the establishment of a TCP socket seems random, with numbers like 237927293, where it must be 0, is this a problem of an uninitialized variable? thanks for all. :Smilie:

----------


## tokneneng

Hi! jmcilhinney Thank you for sample code. I'm getting tired of searching the web about asynchronous socket and found your sample project so basically this what I need. I have modified your code how it disconnect and connect on my application. I'm using listview ipaddress is save as listview tag while port is subitems the port is changing every now and so I can't save it to my database. Now My issue is sending message to client on your sample you used combox, my question is how can I make dirertcast work on me as I used listview tag and subitems. is there a work around for it? Below is the code I have on sending message. Also one more question on your client how does it handle when client gets' power off or network cable was accidentally unplug. 



```
    Private Sub SendMessageToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SendMessageToolStripMenuItem.Click
        Dim message As String = InputBox("Enter your message to selected terminal", "Message")

        If message = String.Empty Then
            Exit Sub
        Else
            For Each checkedItems As ListViewItem In Me.lv_main.SelectedItems
                Dim host = DirectCast(checkedItems.Tag & ":" & checkedItems.SubItems(18).Text, HostInfo)

                'Send the message to the selected client.
                Me.server.Send(host, message)
            Next
        End If
    End Sub
```

----------


## tokneneng

I even try this one but directcast always give me error...



```
    Private Sub SendMessageToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SendMessageToolStripMenuItem.Click

        Dim strMsg As String = InputBox("Enter your message to selected terminal", "Message")

        If strMsg = String.Empty Then
            Exit Sub
        Else
            For Each SelectedItems As ListViewItem In Me.lv_main.SelectedItems
                hostsComboBox.Items.Clear()
                hostsComboBox.Items.Add(SelectedItems.Tag & ":" & SelectedItems.SubItems(18).Text)

                If hostsComboBox.SelectedItem Is Nothing Then
                    hostsComboBox.SelectedIndex = 0
                End If

                Dim host = DirectCast(Me.hostsComboBox.SelectedItem, HostInfo)

                ' SEND MESSAGE TO ALL CLIENT SELECTED
                Me.server.Send(host, strMsg)
            Next
        End If
    End Sub
```

----------


## tokneneng

Hi jmcilhinney I need help I on this project, I have problem when client disconnected/ via power off or unplug cable my client get still connected on my status. I made a timer so when client disconnect it will auto connect. my problem is on me.client.dispose() once I dispose client me.client.connect() I have an error it says I need to unload all instance before connecting again.

----------


## jmcilhinney

> Hi jmcilhinney I need help I on this project, I have problem when client disconnected/ via power off or unplug cable my client get still connected on my status. I made a timer so when client disconnect it will auto connect. my problem is on me.client.dispose() once I dispose client me.client.connect() I have an error it says I need to unload all instance before connecting again.


That's too vague a description I'm afraid.

----------


## tokneneng

Sorry for that. I have your DLL on my project. When I properly close the server and the client I have no issue. However I came to an issue where in I tried to power off and unplug network cable to test the continuity of server and client communication this comes the problem. So what I did I created a timer on the client side which tick every secs to check for connection issue on the server when on the timer I have this:


vb Code:
Private Sub tmr_idle_Tick(sender As System.Object, e As System.EventArgs) Handles tmr_idle.Tick        If tsl_idle.Text = "Disconnected" Or tsl_idle.Text = "Connection was closed by the server." Then            'Me.Dispose()            Me.client.Connect()            tmr_idle.Enabled = False        Else            If tsl_idle.Text = "Connected" Then                tmr_idle.Enabled = False                Exit Sub            End If        End If    End Sub

When server back on client does not connect again.

----------


## jmcilhinney

Firstly, you should not be testing the Text of a TextBox to determine a state.  If there are only two possible states then you should probably be using a Boolean.  If there are multiple states then you should be using an enumeration.

As for your issue, you've show us the code and told us that it doesn't do what it's supposed to.  So, what does happen?

----------


## tokneneng

> Firstly, you should not be testing the Text of a TextBox to determine a state.  If there are only two possible states then you should probably be using a Boolean.  If there are multiple states then you should be using an enumeration.
> 
> As for your issue, you've show us the code and told us that it doesn't do what it's supposed to.  So, what does happen?


Thanks for the clarification regarding the textbox... about the code client does not connect nothing happen timer just keep on running. On server side I put a break point on server_ConnectionAccepted to see if communicate with the server but it does not break. This happen when I shutdown the client and re run it again to check if client auto connect to the server.

----------


## tokneneng

hi jmcilhinney can you gave idea how to fix it? thanks

----------


## jmcilhinney

I haven't looked at this code for a long time.  It would be my guess that the TcpClient involved has been disposed and therefore cannot connect.  You should check whether that is the case and, if so, either don't let the TcpClient be disposed until you are genuinely finished with or else create a new one when needed.

----------


## i00

mixed packets?

I am trying to send a heap of packets so made the send and receive accept objects instead of a string (that gets serialized into a byte array of course)...

Works fine for one or two images ... but if i go:


vb Code:
For Each item In FileIO.FileSystem.GetFiles("C:\TestImages",FileIO.SearchOption.SearchTopLevelOnly,"*.jpg")
            Me.client.Send(New Bitmap(item))
        Next

It works for the first few then the packets get mixed up and it throws on the de-serialization ...

Any ideas on how to fix this?

Thanks
Kris

----------


## jmcilhinney

@i00, I'm afraid I don't know.

----------


## formlesstree4

I would make the byte array by hand; the easiest way I know of doing that is reading the image to a memorystream, then calling the .ToByteArray(); however, since you have the path of the file, just ReadAllBytes() into an array, and handle it on the other side. I've never had the problem with that sort of working.

EDIT: I speak from experience on this; serialization is nice for storing data locally, but really gets wonky when transferring across a network.

----------


## creativedas

Dear Friend,

Your code is great, really great! Can you help me to fix a problem that happens to the client when the server window is in closed state?

When the client's FailedtoConnect is raised, your code prompts with a dialog box to get connected. I removed the question and directly put "client.connect" method instead of asking the question. But, it doesn't get connected when the Server is back online.

Can you please point out why?

Thank and regards,
creativedas

----------


## mmansf1234

Hi, your code is excellent. I have one issue that i hope that you can solve. I am sending data that is variable in length and the textbox is adding it in chunks. I would like to concatenate it into a onle-line entry. y string is terminated with a 'z'. I have no real control on the client transmission (and Arduino with an ehernet shield) with the exception of adding a null or not after the string to send. Either way the data appears in the text box on various lines.

*I am sending:*
IFC01:2023-2023-2023-2023-2023-2023-2023-2023-951-952-953-953-954-954-954-955-287-286-286-286-259-259-260-261-233-233-234-234-235-235-235-236-z
*and getting varying amounts per line:*
Message (192.168.0.103:1025=>): I
Message (192.168.0.103:1025=>): F
Message (192.168.0.103:1025=>): C0
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): :
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 0
Message (192.168.0.103:1025=>): 2
Message (192.168.0.103:1025=>): 3
Message (192.168.0.103:1025=>): -
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 0
Message (192.168.0.103:1025=>): 2
Message (192.168.0.103:1025=>): 3
Message (192.168.0.103:1025=>): -1
Message (192.168.0.103:1025=>): 023
Message (192.168.0.103:1025=>): -
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 0
Message (192.168.0.103:1025=>): 2
Message (192.168.0.103:1025=>): 3-
Message (192.168.0.103:1025=>): 1023-1023-1023-961-880-881-883-884-8
Message (192.168.0.103:1025=>): 8
Message (192.168.0.103:1025=>): 5
Message (192.168.0.103:1025=>): -885-88
Message (192.168.0.103:1025=>): 7-
Message (192.168.0.103:1025=>): 8
Message (192.168.0.103:1025=>): 87-149-148-148-149-149-149
Message (192.168.0.103:1025=>): -
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 48-147-12
Message (192.168.0.103:1025=>): 4-122
Message (192.168.0.103:1025=>): -
Message (192.168.0.103:1025=>): 120
Message (192.168.0.103:1025=>): -1
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 8-
Message (192.168.0.103:1025=>): 116
Message (192.168.0.103:1025=>): -
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 1
Message (192.168.0.103:1025=>): 4-112-109-z

----------


## mmansf1234

By the way I know that the above 2 sections do not coincide as sent and received. I hav to cut and paste from 2 locations. I have 2 clients that I am working with at the same time and the Arduino has no cut and pastable regions.

----------


## mmansf1234

Hi jmcilhinney,

Actually, I figured it out. It only took me "a few hours". I found a piece of code for making delays with an input parameter of integer (for the seconds).

I then ended up putting it in a new line, just after the Read subroutine (I'm talking about the MessageServer code).  This 2 second delay is not bad for my purposes and gives the buffer for each client to fill up with the entire transmission from the client(s). I would have liked to have found a more "correct" way to handle this. Something that would check each transmission for the "z" and not send the message to the textbox until it found it. But, alas, I have spent too many hours finding a usable tcp server for my purposes.

I still have to handle some exceptions like when clients disconnect without grace.

My revisions:

    Private Sub Read(ByVal ar As IAsyncResult)
        Delay(2)
    ... The rest of this code is unchanged.
    End Sb

    Private Sub Delay(ByVal dblSecs As Double)
        Const OneSec As Double = 1.0# / (1440.0# * 60.0#)
        Dim dblWaitTil As Date
        Now.AddSeconds(OneSec)
        dblWaitTil = Now.AddSeconds(OneSec).AddSeconds(dblSecs)
        Do Until Now > dblWaitTil
            ' Allow windows messages to be processed
        Loop

    End Sub


Anyway, I want to thank you for your code. By far the best that I have found.

----------


## yfzpurgatory

Sorry for the double post.  I wasn't aware that messages had to be approved by an administrator, didn't see the first show up, so I posted again.  I'm still looking for a way to add additional properties to the collection that more uniquely identify each client, such as usernames, etc. and eventually a database backend that stores email accounts, passwords, and other information to be used at login.  Here's a screen shot of what I've done with your amazing library so far:

3 Clients Connected:
http://imgur.com/skWr4

1 Client Connected, 2 Disconnected Clients Closed:
http://imgur.com/Y0Lnl

Server Shutdown, 1 Disconnected Client Open:
http://imgur.com/NB71E

I've customized my GUI quite a bit.  The Start and Stop buttons aren't necessary anymore since the socket is opened when the application is executed.  I may reuse them as "Load" and "Refresh" buttons for my database back-end when I get it finished.  Thanks again!

----------


## yfzpurgatory

Hey, jmc.  Awesome wrapper.  I've been beating my head against a wall trying to get some type of secure asynchronous connectivity going for the last 2 and a half days.  I've blazed through about a dozen different tutorials without even a remote understanding of Socket networking.

I only have one question.  I'm going to use this (with full referencing leading back to you which I'll probably contact you some time in the future about) to write a text-based MMO, and I need some way of storing a large amount of variables or properties in the List that stores the connection information.  Is there a way to go about doing this without utterly destroying your library (rewriting it or amending it)?  I'm getting a little lost on how the connection information is handled and how its passed through each method, how to sort through the List to find a particular connection that you want without utilizing a ListView or other control, etc.

I greatly appreciate any help you can give me.  Once again, awesome job on this.  I got a server and multiple clients connecting and disconnecting without any issues in a matter of minutes.

----------


## jmcilhinney

@yfzpurgatory, I'm glad that you found my demo useful, as that's exactly why I created it in the first place.  One good thing about this being posted on a forum is that I get a notification if anyone posts to this thread, so it's easier to keep adding and providing help if required.  I haven't actually touched the code for a while though, so I'm not as familiar with it as I used to be.  In theory, you should simply be able to add extra properties to the HostInfo type and everything will continue to work exactly as it does now.  Adding is not a problem.  It's only if you remove something that you might break existing code.

If I remember correctly, HostInfo is a structure.  If you do want to extend the HostInfo type then it may be more appropriate to implement it as a class instead.  If you were going to do that then you may have to review how it's used to make sure that the change from a value type to a reference type didn't cause any issues.  If it did then you could still make the change but just change the way you handle instances.

There could be various ways to implement the searching you suggest but some of them may require changes to existing code.  If you want to stick with the List(Of HostInfo) then you can use LINQ something like this:
vb.net Code:
Dim match = myList.FirstOrDefault(Function(o) o.Name = name) If match <> Nothing Then

----------


## yfzpurgatory

@jmc, I was looking at the library and the HostInfo type and it doesn't look like there would be an issue adding Username, Password, etc. and since it is a type, I could utilize Random Access Files to store and retrieve information until I get more comfortable with it.  I'm pretty new to OOP as I stated above, so it may take me a while to get things how I would like them.  As you can see from the pictures, I've done quite a bit already.  

I've thought about making a separate Type to store usernames and all of that and index through and assign the information to them by use of the ConnectionEvent's IndexOf property like I did with my ListView:


```
Private Sub server_ConnectionClosed(sender As Object, e As Wunnell.Net.ConnectionEventArgs) Handles server.ConnectionClosed
        Dim tempClient = e.Host
        Me.clients.Remove(tempClient)
        Me.RemoveFromList(tempClient.ToString)
        Me.UpdateLog("SERVERINFO" & SEP_CHAR & "Connection closed from " & tempClient.ToString & " @ " & Date.Now)

        Connected = Connected - 1
        Me.UpdateConnectedLabel(Connected)
    End Sub

    Private Sub RemoveFromList(ByVal user As String)
        lsvClients.Items.RemoveAt(user.IndexOf(user))
    End Sub
```

But there's going to be inherent problems associated with doing it that way.  An example would be, "User 1 private messages User 2."  In this case, User 1 will receive an instant response because the server has his/her connection info readily available through ConnectionEventArgs; User 2's information, however, will have to be pulled through a unique identifier.  Do you have any suggestions?

----------


## jmcilhinney

There's actually already the NetworkCredential class that you could use, although it might have a little more functionality than you actually need.  If you want to use that type or define your own, you could then add a Credential property to the HostInfo type and assign an instance of your type to that.

----------


## yfzpurgatory

Adding a Credential property to HostInfo and assigning an instance of my custom type to it sounds like it would work perfectly.  Is there any way that you could create a Credential property for me (I have no idea what it is or how to use it), comment it, and show me how to utilize it in conjunction with another Type?  I'm not trying to be stingy with your time, but MSDN isn't exactly explicit about what things do.

----------


## jmcilhinney

You already know how to do it.  You can see how the HostInfo type is defined so defining a Credential type will be exactly the same.  As for adding a property to HostInfo, it will be exactly the same as the properties it already contains.

----------


## yfzpurgatory

I'm not aware of what a credential is or how it is used; I haven't seen or used terminology like "delegate", "invoking", or "credentials" in any previous applications, so its pretty foreign to me.  As for editing your library I'm going to see what I can do.  Can your Type be used to store and access data in a RAF like any other type, or has that changed too since VB6?

----------


## jmcilhinney

In a programming context, a user's credentials are basically their user name and password.

I'm not familiar with the term RAF but, from what I can see, it's some sort of file type.  In VB.NET you would use a DLL if you want a type library that can be used in multiple applications or to segregate certain functionality from the main application.

----------


## yfzpurgatory

Ah, okay.  Yes, RAF stands for Random Access File.  It's more than likely an outdated technique of using Types to store and collect data from files.  I haven't attempted it yet but I feel certain that I can add what I want to your library and it'll work.  I'll just have to use the connection information to sort through the HostInfo list to find a connection with a specific username as that is how clients will ultimately be uniquely identified in a chat or game setting, or rather how they will be visually represented on screen.

Thanks for the help, once again.  I think I got it from here, and like I've said, your library works wonderfully.  I've had no hangups in its implementation; the built in error handling is superb.

p.s. I'd rather ask here since this deals with your code and how you implemented it in your example with a MDI Parent.  My MDI Parent does all of the connection work; it connects, sends, and receives messages.  However, I have a child form that visually represents the data received.  Here's the code:



```
Private Sub client_MessageReceived(sender As Object, e As Wunnell.Net.MessageReceivedEventArgs) Handles client.MessageReceived
        Dim tempData() As String = e.Message.ToString.Trim.Split("|")
        Select Case tempData(0)
            Case "GLOBALCLIENTMSG"
                UpdateLog("GLOBALCLIENTMSG", tempData(1).Trim, tempData(2).Trim)
        End Select
    End Sub

    Public Sub UpdateLog(ByVal msgtype As String, ByVal text As String, ByVal user As String)
        Select Case msgtype.Trim
            Case "SERVERINFO"
                frmChat.rtbChat.SelectionColor = Color.Blue
                frmChat.rtbChat.AppendText("Info: ")
                frmChat.rtbChat.SelectionColor = Color.Black
                frmChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                frmChat.rtbChat.ScrollToCaret()
            Case "SERVERMSG"
                frmChat.rtbChat.SelectionColor = Color.Aqua
                frmChat.rtbChat.AppendText("Server: ")
                frmChat.rtbChat.SelectionColor = Color.Black
                frmChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                frmChat.rtbChat.ScrollToCaret()
            Case "GLOBALCLIENTMSG"
                frmChat.rtbChat.SelectionColor = Color.Blue
                frmChat.rtbChat.AppendText("[" & user.Trim & "]: ")
                frmChat.rtbChat.SelectionColor = Color.Black
                frmChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                frmChat.rtbChat.ScrollToCaret()
        End Select
    End Sub
```

In VB6, we could call any form from the MDI Parent and ask it to perform a task and it would be done.  In VB 2010, I've read that you have to ask whether an Invoke is needed and if so, use a delegate method to perform the action.  This is extremely confusing for me.  You can see what I've done, frmChat.rtbChat.AppendText.  I've made sure that data is being handled exactly how I wanted it to and it gets all the way through the Select Case statement; the problem is that it is not being written to the RichTextBox on the child form.

Could you offer some advice or point me in the direction of a tutorial involving delegates and cross-form/thread operations?  Thanks again.

----------


## jmcilhinney

> Ah, okay.  Yes, RAF stands for Random Access File.  It's more than likely an outdated technique of using Types to store and collect data from files.  I haven't attempted it yet but I feel certain that I can add what I want to your library and it'll work.  I'll just have to use the connection information to sort through the HostInfo list to find a connection with a specific username as that is how clients will ultimately be uniquely identified in a chat or game setting, or rather how they will be visually represented on screen.


The term "random access file" doesn't really get used in .NET because all files can be accessed randomly and it's only at the application level that you might limit that.  In .NET you can use various types of streams, readers and writers to read and write files in different ways but there's always a FileStream underneath anything else you may use and a FileStream inherently allows you to access any position in the file at random.

To locate a particular user's connection information in a List(Of HostInfo) might look like this:

```
Dim userInfo = hostInfos.SingleOrDefault(Function(hi) hi.UserName = userName)

If userInfo <> Nothing Then
```




> Thanks for the help, once again.  I think I got it from here, and like I've said, your library works wonderfully.  I've had no hangups in its implementation; the built in error handling is superb.
> 
> p.s. I'd rather ask here since this deals with your code and how you implemented it in your example with a MDI Parent.  My MDI Parent does all of the connection work; it connects, sends, and receives messages.  However, I have a child form that visually represents the data received.
> 
> In VB6, we could call any form from the MDI Parent and ask it to perform a task and it would be done.  In VB 2010, I've read that you have to ask whether an Invoke is needed and if so, use a delegate method to perform the action.  This is extremely confusing for me.  You can see what I've done, frmChat.rtbChat.AppendText.  I've made sure that data is being handled exactly how I wanted it to and it gets all the way through the Select Case statement; the problem is that it is not being written to the RichTextBox on the child form.
> 
> Could you offer some advice or point me in the direction of a tutorial involving delegates and cross-form/thread operations?  Thanks again.


Having to call Invoke and use a delegate has nothing specific to do with MDI forms.  That is only required when you are executing code on a thread other than the UI thread and then want to get data from or to the UI.  It's crossing the thread boundary to access a control that requires invoking a delegate.

Your first issue is that you are using the default instance.  Follow the Blog link in my signature and check out my post on Default Form Instances to learn what they are and why they can't help you in this scenario.  To learn how to access the UI correctly from a secondary thread, follow the CodeBank link in my signature and check out my thread on Accessing Controls From Worker Threads.

----------


## yfzpurgatory

I'm actually using a new instance of the form.  Here's the call:


```
Private Sub StartChatToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles StartChatToolStripMenuItem.Click
        Call New frmChat() With {.MdiParent = Me}.Show()
        StartChatToolStripMenuItem.Enabled = False
End Sub
```

As you can see it was taken directly from your own MDIParent and children forms in your example.  I browsed through your BackgroundWorker and default instance tutorails; I do not feel that multi-threading is really relevant.  I'm going to look into using delegates.

Edit:
I didn't have to use a background worker or delegates.  The error in using "Call New" is that you aren't identifying the form and thus can't use it on the UI thread, from what I understand.. even if you do use delegates.  I'm using this instead and it works perfectly now:

Setting chlChat as our new instance.


```
Public Class mdiMain
    Public chlChat As New frmChat()
```

Loading chlChat and using it:


```
Private Sub StartChatToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles StartChatToolStripMenuItem.Click
        chlChat.MdiParent = Me
        chlChat.Show()
        StartChatToolStripMenuItem.Enabled = False
    End Sub

    Public Sub UpdateLog(ByVal msgtype As String, ByVal text As String, ByVal user As String)
        Select Case msgtype.Trim
            Case "SERVERINFO"
                chlChat.rtbChat.SelectionColor = Color.Blue
                chlChat.rtbChat.AppendText("Info: ")
                chlChat.rtbChat.SelectionColor = Color.Black
                chlChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                chlChat.rtbChat.ScrollToCaret()
            Case "SERVERMSG"
                chlChat.rtbChat.SelectionColor = Color.Aqua
                chlChat.rtbChat.AppendText("Server: ")
                chlChat.rtbChat.SelectionColor = Color.Black
                chlChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                chlChat.rtbChat.ScrollToCaret()
            Case "GLOBALCLIENTMSG"
                chlChat.rtbChat.SelectionColor = Color.Blue
                chlChat.rtbChat.AppendText("[" & user.Trim & "]: ")
                chlChat.rtbChat.SelectionColor = Color.Black
                chlChat.rtbChat.AppendText(text.Trim & ControlChars.NewLine)
                chlChat.rtbChat.ScrollToCaret()
        End Select
    End Sub
```

And a picture of it all working:
http://imgur.com/9So0V

----------


## jmcilhinney

Originally, you were explicitly creating a new instance of the form when displaying it but, as you have correctly said, you were not keeping a reference to that instance and could therefore not access it later.  When you were trying to update the form you were in fact using the default instance.  You were successfully updating a form instance but it was not the same form instance that you had displayed to the user.  It was the default instance for the secondary thread that you were executing on, which had never been displayed to the user at all.

----------


## yfzpurgatory

Exactly.

Edit:
I successfully added the property Username to HostInfo.  It wasn't difficult or overly complicated.  I can't exactly explain what I did wrong, but it had to do with trying to add it to another project without rebuilding the .dll, and trying to use HostInfo in a separate project that was still using the old .dll.  I fixed it by copying the project files into my project folder, adding it to my solution, rebuild it after alterations, and make sure I removed the reference for the old DLL and add the reference for the new DLL.

Works perfectly.  I'll have some screen shots soon.

Edit2:
I removed the username property from HostInfo.  I couldn't get updating to work for the list, so I'm using the ListView instead.  I'm going to have to compare a lot of things against a lot of things to eventually get data from a file, but I know how to do it; just worried that it'll take too much processing power away from everything else.  Thanks again for the library.  I highly doubt I'll be posting here again.  I'll message you later in order to get referencing information for when the project is complete so that you receive proper credit.

----------


## yfzpurgatory

Here's a screen shot of what I've done with it:

----------


## tokneneng

> I would have to test to work that out, which I can't do right now, but the first thing that springs to mind is that the port number changes.


Hi jmcilhinney I just like to raise this issue again been banging my head to fix this but I could find solution, I step over on each line of code to check when client click reconnect it does nothing.  Below is the code where error occur. Port and Address Still has value even client was dicconected.



```
Private Sub Connect(ByVal ar As IAsyncResult)
        Try
            'Complete the asynchronous connection.
            Me.client.EndConnect(ar) ' < ----- This line error occur (A connect request was made on an already connected socket)

            'Get the port that was assigned to the local end point.
            Me._localPort = DirectCast(Me.client.Client.LocalEndPoint, IPEndPoint).Port

            Me.stream = Me.client.GetStream()

            Dim buffer(Me.BufferSize - 1) As Byte

            'Listen asynchronously for an incoming message.
            Me.stream.BeginRead(buffer, 0, Me.BufferSize, AddressOf Read, buffer)

            'Notify any listeners that the connection was successful.
            Me.OnConnectionAccepted(New ConnectionEventArgs(Me.server))
        Catch ex As SocketException
            'The specified server was not found.
            Me.OnConnectionFailed(New ConnectionEventArgs(Me.server))
        End Try
    End Sub
```

----------


## tokneneng

Hi jmcilhinney please need help... Still issue about client disconnect and reconnect. can you please help how to initialize connection when client reconnect. Below is the code what I'm trying to accomplish but I'm having same error. I'm out of idea right now been trying to solve this since the last time I posted my last question.

    Public Sub Connect()
        Try
            If Me.isDisposed Then
                'MyBase.New(BufferSize, Encoding)
                Me.Initialise(Me.server.HostName, Me.server.Port)
                Me.client.BeginConnect(Me.server.HostName, Me.server.Port, AddressOf Connect, Nothing)
            Else

                'Connect asynchronously to the server.
                Me.client.BeginConnect(Me.server.HostName, Me.server.Port, AddressOf Connect, Nothing)
            End If
        Catch ex As SocketException

        End Try
    End Sub

Error : 
Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.

----------


## Niya

The object is disposed and yet you are still calling its methods. When an object is disposed its done, you can't continue using it.


vbnet Code:
If Me.isDisposed Then
'MyBase.New(BufferSize, Encoding)
Me.Initialise(Me.server.HostName, Me.server.Port)
Me.client.BeginConnect(Me.server.HostName, Me.server.Port, AddressOf Connect, Nothing)

The above code is just blasphemous. You just don't do that....ever

----------


## tokneneng

> The object is disposed and yet you are still calling its methods. When an object is disposed its done, you can't continue using it.
> 
> 
> vbnet Code:
> If Me.isDisposed Then
'MyBase.New(BufferSize, Encoding)
Me.Initialise(Me.server.HostName, Me.server.Port)
Me.client.BeginConnect(Me.server.HostName, Me.server.Port, AddressOf Connect, Nothing)
> 
> The above code is just blasphemous. You just don't do that....ever


Hi! Niya thanks for the reply yes your correct it's already dispose, what i'm trying to do is to re initialize new socket and right now I'm stack with it I have no Idea how to do it. Can you help me out?

----------


## Niya

You cannot re-initialize a disposed object. If any class allowed this it would be a bad design. You simple create a new one, or you don't dispose of it in the first place.

----------


## yfzpurgatory

Hey, Jmc.  I encountered an issue when I upgraded to VS Professional 2010.  Everything was going just fine until then.  The error is on the client side when I'm closing the application:

Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.

It occurs in MessageClient.vb and is in the Read method.  Running the application as release and/or without debugging returns no errors and everything runs just fine.  Is there any insight you can give me into why this is happening?

Edit:  I'm assuming there needs to be some type of graceful closing that needs to happen, because I've been able to error the server and the client depending on where I dispose of the client object.  When I don't dispose of the client object, the server will error in MessageServer on the Read line.  I'm honestly not to sure as I haven't ripped your source apart and have used it as is.  Thanks for the help.

----------


## jmcilhinney

> Hey, Jmc.  I encountered an issue when I upgraded to VS Professional 2010.  Everything was going just fine until then.  The error is on the client side when I'm closing the application:
> 
> Cannot access a disposed object.
> Object name: 'System.Net.Sockets.NetworkStream'.
> 
> It occurs in MessageClient.vb and is in the Read method.  Running the application as release and/or without debugging returns no errors and everything runs just fine.  Is there any insight you can give me into why this is happening?
> 
> Edit:  I'm assuming there needs to be some type of graceful closing that needs to happen, because I've been able to error the server and the client depending on where I dispose of the client object.  When I don't dispose of the client object, the server will error in MessageServer on the Read line.  I'm honestly not to sure as I haven't ripped your source apart and have used it as is.  Thanks for the help.


There are various situations where, as far as I can tell, the only way to be notified at one end that the other end has disconnected is to catch an exception.  I have done that in some cases in the existing code but it hasn't been tested rigorously so there may be others.  It sounds like you may have encountered one.

All I can suggest is test repeatedly to make sure that you understand under exactly what circumstances the exception is being thrown and what exception it is and, if you cannot prevent it, add the appropriate exception handling to your code.  That's exactly what I would do.

----------


## yfzpurgatory

Here's the disassembly:



```
00000080  mov         dword ptr [ebp-24h],eax
```

The error is occurring on this line:



```
'Complete the asynchronous read and get the first block of data.
Dim byteCount = Me.stream.EndRead(ar)
```

Since that line is inside of a Try statement, all I would need to do is add a Catch ex As statement line for IO.NetworkStream, right?

Edit:  You already had it setup to catch an IOException, so I simply added Exit Sub (very distasteful way of handling it) to the Catch:



```
       Catch ex As IOException
            Exit Sub
            'The callback specified when BeginRead was called may get invoked one last time when the TcpClient is disposed.
            'This exception is thrown when EndRead is called on a disposed client stream.
        End Try
```

Seems to work just fine now.  In fact, the application was doing exactly what your comment says may happen.  I also had to add in the following:

NullReferenceException and ObjectDisposedException.  Seems to be fine now.  When I have the time, I'm going to have to go through your code more thoroughly and find out why a disposed object is being called to begin with.

----------


## tokneneng

> Here's the disassembly:
> 
> 
> 
> ```
> 00000080  mov         dword ptr [ebp-24h],eax
> ```
> 
> The error is occurring on this line:
> ...


Same issue here VS2010,  I haven't time to get back to the code to not disposed the client when server get closed so client can re connect again.

----------


## Rovin1955

Hi,
I am using VS2008 Express.
When I attempt to connect the client, I get the following message box:
"The specified server could not be found. Would you like to try again?"
Please could you let me know what is wrong.
Many Thanks

----------


## jmcilhinney

> Hi,
> I am using VS2008 Express.
> When I attempt to connect the client, I get the following message box:
> "The specified server could not be found. Would you like to try again?"
> Please could you let me know what is wrong.
> Many Thanks


Either the server isn't running or you you used the wrong address and/or port when trying to connect to it.

----------


## Rovin1955

Hi Jmc,
I am using your Server app to communicate with remote sensors.
This all works very well and I am able to receive data and send data to the remote sensors using the sendButton_Click function.
My requirement is to be able to send data to the remote sensors without user intervention.
How would I substitute the "Me.hostsComboBox.SelectedItem" for my own Remote IP and Port in the:
Dim host = DirectCast(Me.hostsComboBox.SelectedItem, HostInfo)
Best Regards

----------


## jmcilhinney

> Hi Jmc,
> I am using your Server app to communicate with remote sensors.
> This all works very well and I am able to receive data and send data to the remote sensors using the sendButton_Click function.
> My requirement is to be able to send data to the remote sensors without user intervention.
> How would I substitute the "Me.hostsComboBox.SelectedItem" for my own Remote IP and Port in the:
> Dim host = DirectCast(Me.hostsComboBox.SelectedItem, HostInfo)
> Best Regards


I'm guessing that hard-coding them into the app would be inappropriate.  Generally this sort of thing is done by adding an entry to the config file and reading the data from there.  You can then edit the config file by hand any time to change that data and thereby change how the app behaves.  The simplest option for working with the config file is via the Settings page of the project properties.  In your case, you'll probably want to use Application scope for one String and one Integer setting.  If you then open App.config from the Solution Explorer you can see how they're stored.

----------


## Rovin1955

> I'm guessing that hard-coding them into the app would be inappropriate.  Generally this sort of thing is done by adding an entry to the config file and reading the data from there.  You can then edit the config file by hand any time to change that data and thereby change how the app behaves.  The simplest option for working with the config file is via the Settings page of the project properties.  In your case, you'll probably want to use Application scope for one String and one Integer setting.  If you then open App.config from the Solution Explorer you can see how they're stored.


Hi jmc,
It would be impossible for me to hard-code the remote IP and Port into the app.
Let me explain:
All remote devices are on Dynamic IP addresses using GSM modems. Every time the GSM re-connects, the IP address changes.
What I am doing on the server side (running your app) is that each message that I receive from a remote device has the unique device ID, I then write the IP, Port and Unique ID to a database.
When I need to send a message to a particular remote device, I retrieve the IP and Port that corresponds to the Unique ID from the database, append the message and send.
One workaround could be reading the IP/Port from the database and setting the hostsComboBox.Text property to that value, the messageTextBox.Text property to the "message" and then invoke the sendButton_click event.
I have not tried this and it seems very cumbersome.
Best Regards

----------


## jmcilhinney

> It would be impossible for me to hard-code the remote IP and Port into the app.


Probably a good thing I didn't recommend that then, isn't it?


> Let me explain:


You don't need to.  You just need to do what I suggested, i.e. add a couple of settings and then edit them by hand in the config file after deployment if required.

----------


## Rovin1955

> add a couple of settings and then edit them by hand in the config file after deployment if required.


Hmm,
I do not know how to go about this - could you guide me?
Cheers

----------


## yfzpurgatory

Hey Jmc, have a quick question for you.

I'm attempting to use your library (which I've modified slightly) in a C# app but I cannot for the life of me figure out how to call or explicitly implement the event handlers for ConnectionAccepted, ConnectionClosed, and MessageReceived.  Any ideas or advice?

I appreciate it, and thanks in advance,
RCG

----------


## jmcilhinney

> Hey Jmc, have a quick question for you.
> 
> I'm attempting to use your library (which I've modified slightly) in a C# app but I cannot for the life of me figure out how to call or explicitly implement the event handlers for ConnectionAccepted, ConnectionClosed, and MessageReceived.  Any ideas or advice?
> 
> I appreciate it, and thanks in advance,
> RCG


If you don't know how to handle events in C# then please start a new thread in the C# forum and keep this thread to questions on this topic specifically.

----------


## yfzpurgatory

> If you don't know how to handle events in C# then please start a new thread in the C# forum and keep this thread to questions on this topic specifically.


I transitioned from VB.NET to C# about a month ago, and I taught myself .NET/OOP in about the same amount of time, so naturally I have a few problem areas; those just happen to be generics and delegates (which event handlers sort of fall under).  Anywho, I got it all fixed up.  All I had to do was instantiate a server/client object, subscribe the event handlers to the object members in the class constructor using methods I wrote in the class, and it's good to go.

Thanks again for the help.

----------


## nbl1268

Hi all, 
I'm looking for some guidance on just how to change the setup of this tcp messageserver so that i can set the port address for listening based on a parameter i read in from the command line eg Arg (1).
I can see that the constructors allow for passing in the port value, however, not sure how to make use of this in my formload method and still have the eventshandlers for ConnectionAccepted, MessageRecieved and ConnectionClosed work.
Thanks
Neil

----------


## KyleBoyer

Hey I am curious, could this be combined into one application that is both a server and a client?

----------


## jmcilhinney

> Hey I am curious, could this be combined into one application that is both a server and a client?


Certainly.  The definition of a server is a hardware or software entity that receives connection requests while a client is an entity that requests connections.  It's quite possible for one machine or application to be both a client and a server.  Exactly how it would be designed depends on exactly what the aim is but there's no issue with a single entity making and accepting connection requests.

----------


## KyleBoyer

Look below -_- I'm a newbie on these forums. :X

----------


## KyleBoyer

> Certainly.  The definition of a server is a hardware or software entity that receives connection requests while a client is an entity that requests connections.  It's quite possible for one machine or application to be both a client and a server.  Exactly how it would be designed depends on exactly what the aim is but there's no issue with a single entity making and accepting connection requests.


Thanks for clearing that up for me! I seem to have done it in this application I made called P2P, but it is very slow and bugy. Do you think you could check out my source and fix it or tell me how I should go about fixing it? I would love to go the Asynchronous route, but I am not sure how to. I am currently using a timer to receive.

Source here:
https://www.dropbox.com/sh/p8racx1l7lqj3br/ZTqA6bxuIA

----------


## nbl1268

Hi JMc,

I'm using your sample code (v1.1.0.1) and looking to understand how to set/change the port for the listener (MessageServer) at run time rather than fixed in code.
Can you help me with this?

Thanks
Neil

----------


## jmcilhinney

> Hi JMc,
> 
> I'm using your sample code (v1.1.0.1) and looking to understand how to set/change the port for the listener (MessageServer) at run time rather than fixed in code.
> Can you help me with this?
> 
> Thanks
> Neil


The port is just a number.  You can get that number any way you want.  If you need user input then get user input, the same way you would any other time.  As it's a number, a NumericUpDown seems the logical option, although you could use a TextBox if you wanted to.

----------


## yfzpurgatory

> If you don't know how to handle events in C# then please start a new thread in the C# forum and keep this thread to questions on this topic specifically.


When a MessageServer object is implemented in C# your library throws a NullReferenceException at this line:



```
Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
        Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
End Sub
```

The error occurs when a client connects.  I'm assuming the same error will occur for the rest of the event handlers.

----------


## nbl1268

> The port is just a number.  You can get that number any way you want.  If you need user input then get user input, the same way you would any other time.  As it's a number, a NumericUpDown seems the logical option, although you could use a TextBox if you wanted to.


Hi JMc,

Seems I haven't been very clear with my question to you.   :Confused: 

I do not have an issue with setting the port value, as it is nothing but an integer in the range of 0 to 65535.  Equally, I can use the public property you have provided in your example code to read the current port value that the TCPListener is expecting TCP connections to arrive on.

I do know how to read an integer from a User using Textbox, NumericUpDown, also from application setting using My.Settings and how to read an integer from the command line using the args(i) string array... just to name a few.   :Wink: 


If I can use an example from your own code, where you create the object named _server_ in the class using the following statement


```
        Private WithEvents server As New MessageServer(12345)
```

The object _server_ is declared using port value of 12345 before any events are activated... as such _server_ exists and is ready for use when the form is loading and for any other subsequent events to use.

For my application, I am reading from the command line a set of configuration items, which includes the port number that I need the TCPlistener to be operating on.  
In this case it is contained in args(2) (exact code I'm using to read command line is below)  



```
        Dim args() As String

        Try
            ' get commandline args
            args = Environment.GetCommandLineArgs
            sDataSource = args(1).ToUpper
            iListenerPort = CInt(args(2))
            UpdateLog("Info: Command Line Arguments Loaded")
        Catch ex As Exception
            ' load defaults
            sDataSource = "E6410\SQLEXPRESS"
            iListenerPort = 6002
        End Try
```

Where I am struggling is I can not see a way for me to set the actual port number to be something other value other than by manually changing this value before I build/compile this code.

I can not simply apply a new port value in my form load event using the port parameter 
eg


```
        server.Port(iListenerPort)
```

as it this parameter is readonly and there is no code in the MessageServer Class to support changing the port number.

I have already attempted to declare the object in my Form load event using the following statement where _iListenerPort  = 6002_ for testing.


```
        Dim server As New MessageServer(iListenerPort )
```

And I've added the following event handlers


```
        AddHandler server.ConnectionAccepted, AddressOf server_ConnectionAccepted
        AddHandler server.MessageReceived, AddressOf server_MessageReceived
        AddHandler server.ConnectionClosed, AddressOf server_ConnectionClosed
```

The problem I am finding here is that the server object is localised to this event and not accessible to other events, eg those referenced by the event handlers
Very specifically the Hosts object is empty when the server.send method is called.


So, returning to my original question, how do I declare an object (in my case _TCPserver_) as type MessageServer with a port value that I have read from the command line (using Args() string array) using the constructors that you have provided that is accessible to all other events in my application?  

I'm thinking that maybe I need to be looking at how to add code to your MessageServer class to allow me to set the Port property and have the TCPListener (that already exists) stop, change port value and start. 

Thanks
Neil

----------


## jmcilhinney

> When a MessageServer object is implemented in C# your library throws a NullReferenceException at this line:
> 
> 
> 
> ```
> Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
>         Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
> End Sub
> ```
> ...


That would suggest that nothing is being assigned to the _synchronisingContext field, so you need to work out why.  I doubt that it's got anything to do with C#.  I think you'll find that SynchronizationContext.Current will return a null reference if you're not using it in either a WinForms or WPF application.  Could that be the reason in your case?

----------


## yfzpurgatory

> That would suggest that nothing is being assigned to the _synchronisingContext field, so you need to work out why.  I doubt that it's got anything to do with C#.  I think you'll find that SynchronizationContext.Current will return a null reference if you're not using it in either a WinForms or WPF application.  Could that be the reason in your case?


I'm using it in a WinForms application at the moment, so I'm sure that isn't the issue.  As for working out why it's throwing that error I'm honestly at a loss.  I'm running over it right now and it is showing null.  I can connect fine (although I'm seeing 2-3 errors popping up due to the read/write methods, NullReferenceExceptions, IOException, ObjectDisposedException), I can close the server and it'll update all connected client's fine, I can restart the server and reconnect just fine, but when I go to close a client using client.Dispose() the server hangs on that method (OnConnectionClosed now).

If I remove client.Dispose(), the ConnectionClosed event will never be raised, even when the client application is stopped or shut down.

----------


## Niya

> I think you'll find that SynchronizationContext.Current will return a null reference if you're not using it in either a WinForms or WPF application.


If you call Current in a non-UI thread it would be null. When a .Net Winforms application starts, the UI thread is created along with a SynchronizationContext for it and the message loop.

----------


## jmcilhinney

> I'm using it in a WinForms application at the moment, so I'm sure that isn't the issue.  As for working out why it's throwing that error I'm honestly at a loss.  I'm running over it right now and it is showing null.  I can connect fine (although I'm seeing 2-3 errors popping up due to the read/write methods, NullReferenceExceptions, IOException, ObjectDisposedException), I can close the server and it'll update all connected client's fine, I can restart the server and reconnect just fine, but when I go to close a client using client.Dispose() the server hangs on that method (OnConnectionClosed now).
> 
> If I remove client.Dispose(), the ConnectionClosed event will never be raised, even when the client application is stopped or shut down.


If that field is a null reference then obviously no value was ever assigned to it, so you need to look at where you expected a value to be assigned and determine why it's not.

----------


## yfzpurgatory

> If that field is a null reference then obviously no value was ever assigned to it, so you need to look at where you expected a value to be assigned and determine why it's not.


I've been over the code numerous times and I've found no reason for it not to function correctly.  Believe I'm just going to move on and hope you decide to rewrite this library at some point in time for C# and/or .NET 4 or 4.5.

----------


## jmcilhinney

> I've been over the code numerous times and I've found no reason for it not to function correctly.  Believe I'm just going to move on and hope you decide to rewrite this library at some point in time for C# and/or .NET 4 or 4.5.


That wouldn't help.

----------


## yfzpurgatory

> That wouldn't help.


I don't see why it wouldn't when something about C# is causing it not to function correctly.  When I use the library in VB.NET 2010 everything works just fine; zero problems that I haven't fixed myself.  When I try the same in C# 4 it's a completely different story.  For some reason it just isn't jiving well on these lines:



```
Protected Overridable Sub OnConnectionAccepted(ByVal e As ConnectionEventArgs)
        Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)
End Sub
```

Nothing has been changed, and I know I'm not going crazy.  I've ran over the entire library multiple times, and I've very thoroughly went over both the read and send methods line by line to no avail.  It has left me completely dumbfounded.  The only event that is raised is MessageReceived; both ConnectionClosed and ConnectionAccepted fail, although the client connects.

----------


## Nightwalker83

> I don't see why it wouldn't when something about C# is causing it not to function correctly.  When I use the library in VB.NET 2010 everything works just fine; zero problems that I haven't fixed myself.  When I try the same in C# 4 it's a completely different story.  For some reason it just isn't jiving well on these lines:


Please stop talking about "C#" in this thread/section. If have a C# question post it here.

----------


## yfzpurgatory

> Please stop talking about "C#" in this thread/section. If have a C# question post it here.


When the problem is 100% relevant to this topic and this library, no, I don't think I will.  What I will do, however, is completely wash my hands of this library.  An "MVP" my ass.

----------


## drankof

> ... nothing is being assigned to the _synchronisingContext field, so you need to work out why. ... SynchronizationContext.Current will return a null reference if you're not using it in either a WinForms or WPF application.


FOREWORD: I opened my account on this forum today for two reasons; 1) to continue discussing a legitimate question in a reasonable tone, and more importantly, to say that this code is the most amazing code I have ever gotten off the internet. Seriously. I'm also a new guy to .net, coming from AmigaBasic (joke, vb6) 1 month ago. In my month of scouring the internet looking and learning to make test programs to learn the language, I have BY FAR learned more from this code than from anything else. Multiple programs from one solution, all while sharing and building a library, with all sorts of fancy commenting and region stuff I never knew existed. The library implements great into other programs, too! THANK YOU so much. I'm a big fan.

That said, I'm working in VB2010 (.net 4.0) and am bumping into a similar issue. The server (as far as I can tell) must be run from a form in order for the SynchronizationContext.Current to not return a null value.

Making a Windows Forms Application launched from sub main (to make it behave as similar as possible to module-based code), I put the following in a blank new form's code (it's basically just a stripped down version of the test server):


```
Module serverModule
    Public Sub main()
        serverWindow.Show()
        Application.Run()
    End Sub
End Module

Public Class serverWindow

    Public WithEvents server As New MessageServer(12345)
    Public ReadOnly hosts As New List(Of HostInfo)

    Private Sub server_ConnectionAccepted(ByVal sender As Object, ByVal e As Net.ConnectionEventArgs) Handles server.ConnectionAccepted
        hosts.Add(e.Host)
    End Sub

    Private Sub server_MessageReceived(ByVal sender As Object, ByVal e As Net.MessageReceivedEventArgs) Handles server.MessageReceived
        server.Send(e.Message)
        If e.Message = "exit" Then Me.Close()
    End Sub

    Private Sub server_ConnectionClosed(ByVal sender As Object, ByVal e As Net.ConnectionEventArgs) Handles server.ConnectionClosed
        Dim host = e.Host
        hosts.Remove(host)
    End Sub

    Private Sub MainWindow_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        server.Dispose()
        Application.Exit()
    End Sub
End Class
```

Clients can connect and talk, the server repeats the chat, and clients can even shut down the server with "exit". The server only has a single blank window running, which I guess could be hidden, but I what I originally wanted was to run the server from a module.

A nearly identical module-based version:


```
Module serverModule

    Public Sub main()
        Application.Run()
    End Sub

    Public WithEvents server As New MessageServer(12345)
    Public ReadOnly hosts As New List(Of HostInfo)

    Private Sub server_ConnectionAccepted(ByVal sender As Object, ByVal e As Net.ConnectionEventArgs) Handles server.ConnectionAccepted
        hosts.Add(e.Host)
    End Sub

    Private Sub server_MessageReceived(ByVal sender As Object, ByVal e As Net.MessageReceivedEventArgs) Handles server.MessageReceived
        server.Send(e.Message)
        If e.Message = "exit" Then shutdown()
    End Sub

    Private Sub server_ConnectionClosed(ByVal sender As Object, ByVal e As Net.ConnectionEventArgs) Handles server.ConnectionClosed
        Dim host = e.Host
        hosts.Remove(host)
    End Sub

    Private Sub shutdown()
        server.Dispose()
        Application.Exit()
    End Sub

End Module
```

Whenever a client joins, the same line "Me._synchronisingContext.Post(AddressOf RaiseConnectionAccepted, e)" says object reference not set to an instance of an object.

The same error occurs when I try to reproduce the same thing by running the server from a class (without a form). Yet the client seems to run great from a module.

So I guess the question is, would it, and if so, how would it be possible to run a server using your current library without it running from a form?

----------


## jmcilhinney

@drankof, I'm glad that you found the code useful.  As I said, SynchronizationContext.Current returns Nothing when used in other than a Windows Forms or WPF app.  That's because the whole point of the SynchronizationContext class is to allow you to execute code on the thread that owns a specific control.  If you have no controls then it doesn't matter what thread you execute code on.  If you don't want to use my library in a GUI app then you can get rid of all the stuff relating to the SynchronizationContext.  If you want to be able to use it in both GUI and non-GUI apps then you'll need to do something like this:

```
If mySynchronizationContext Is Nothing Then
    'Non-GUI app so call your method directly on the current thread.
Else
    'GUI app so invoke your method via the SynchronizationContext.
Else
```

In non-GUI apps, some additional thread synchronisation may be required to ensure that actions occur in the appropriate sequence but that is beyond the scope of this thread.

----------


## drankof

> As I said, SynchronizationContext.Current returns Nothing when used in other than a Windows Forms or WPF app.  *That's because the whole point of the SynchronizationContext class is to allow you to execute code on the thread that owns a specific control.*  If you have no controls then it doesn't matter what thread you execute code on.  If you don't want to use my library in a GUI app then you can get rid of all the stuff relating to the SynchronizationContext. 
> ...
> *In non-GUI apps, some additional thread synchronisation may be required to ensure that actions occur in the appropriate sequence* but that is beyond the scope of this thread.


Wow...it works by executing code on a thread that owns a control, which would need a form, that makes perfect sense. I think that just explained about 1/2 of what I didn't/don't understand regarding how the asynchronization/multithreading(/not pausing just to passively listen for people joining...not sure what word is appropriate) works on this server. Now I just need to finish investigating some of the other intricacies of threading, in general. Thank you so much and for the tip on how to implement it without a form/GUI.  :Thumb:

----------


## vagkom

Great Work, lean programming!
I develop listeners quite a while for a GPRS project. Let me put a question on the table:
When a GPRS device connects to the listener it takes an IP address and a random port. Then the device looses the connection and later connects to listener with the same address and same port. What is happening ? So far the program crashes. In a previous listener I kept a list of ip addresses and manually I perform a check (if exists) before connection. Do you think any other way to prevent a "same port" situation ?

Best Regards
Vangelis

----------


## dbasnett

@jmcilhinney - I looked at your post in the code bank.  I was wondering why you chose the ports you did?  It seems that you should be using port numbers 4915265535.

----------


## i00

Hi, I said a long time ago that it wasn't receiving packets in order... here is the case...

This is my modified MessageClient.Read:


vb Code:
Private Sub Read(ByVal ar As IAsyncResult)        Try            'The stream will be Nothing if the client has been disposed.            If Me.stream IsNot Nothing Then                Dim buffer = DirectCast(ar.AsyncState, Byte())                 'Complete the asynchronous read and get the first block of data.                Dim byteCount = Me.stream.EndRead(ar)                 If byteCount = 0 Then                    'If there is no data when an asynchronous read completes it is because the server closed the connection.                    Me.OnConnectionClosed(New ConnectionEventArgs(Me.server))                Else                    'Start building the message.                    'Dim message As New StringBuilder(Me.Encoding.GetString(buffer, 0, byteCount))                     OnDataChunkRecieved(New DataChunkRecievedEventArgs() With {.Chunk = buffer})                                        'As long as there is more data...                    While Me.stream.DataAvailable                        '...read another block of data.                        byteCount = Me.stream.Read(buffer, 0, Me.BufferSize)                        OnDataChunkRecieved(New DataChunkRecievedEventArgs() With {.Chunk = buffer})                    End While                     'Listen asynchronously for another incoming message.                    Me.stream.BeginRead(buffer, 0, Me.BufferSize, AddressOf Read, buffer)                     'Notify any listeners that a message was received.                    'Me.OnMessageReceived(New MessageReceivedEventArgs(Me.server, message.ToString()))                End If            End If        Catch ex As IOException            'The callback specified when BeginRead was called may get invoked one last time when the TcpClient is disposed.            'This exception is thrown when EndRead is called on a disposed client stream.        End Try    End Sub

I will try to describe this the best way i can ... but basically ... when there is no more data available in the Me.stream.DataAvailable loop ... because we have reached the end of the stream that the client has received sofar (but it is still sending such as a large file).. it will then come back to this sub again as the server is still sending ... and Dim buffer = DirectCast(ar.AsyncState, Byte()) then starts reading data from a random chunk... not necessarily the next chunk that was sent...

also ... if i change the code to this it works:



```
                    While Me.stream.DataAvailable
                        '...read another block of data.
                        byteCount = Me.stream.Read(buffer, 0, Me.BufferSize)
                        OnDataChunkRecieved(New DataChunkRecievedEventArgs() With {.Chunk = buffer})
                        'wait for a second to see if more data is coming...
                        System.Threading.Thread.Sleep(100)
                    End While
```

As this seems to make it slow down enough to receive the next chunk ... but this is not good of course as it slows it down ... and the data may take more than 100ms to get the next bit... it is just proof of concept...

Any ideas jmcilhinney?

Thanks,
Kris

----------


## i00

hello? (*bump)

----------


## jmcilhinney

> hello? (*bump)


I'll get to this if and when I can, which may not be any time soon or ever.

----------


## Niya

@i00

Your problem is the overall design. You should *never* depend on the socket implementation to tell you when a download is complete. *Always* design at least a minimum protocol. My favored method is attaching a prefix that at the start of a stream that tells me how many bytes to expect so I keep track of the number of bytes at the receiving end that we have received at any point. Using this method, one can determine when a download is complete.

----------


## i00

> @i00
> 
> Your problem is the overall design. You should *never* depend on the socket implementation to tell you when a download is complete. *Always* design at least a minimum protocol. My favored method is attaching a prefix that at the start of a stream that tells me how many bytes to expect so I keep track of the number of bytes at the receiving end that we have received at any point. Using this method, one can determine when a download is complete.


OK ... But if I do this ... I still have a problem ... how do I wait for the rest of the data? because Me.stream.DataAvailable will return false but it will still be transmitting...

Edit: also this download also relies on the data not being long enough to be split into multiple packets

Kris

----------


## i00

> I'll get to this if and when I can, which may not be any time soon or ever.


Hope you can *cross fingers*

----------


## Niya

I'm currently putting together two small applications to demonstrate a good way to handle file transfers over TCP/IP using Winsock through the TcpListener/TcpClient classes. I'll post it in the code bank when I'm done. Hopefully it would make things a little clearer.

----------


## Niya

Ok, I've posted two sample applications that show how to transfer a file between a client and a server using WinSock. They should give you an idea about to detect completion of data transfers. Here is the Code Bank thread.

----------


## iProgrammer

I am sorry if I am bumping an old thread, but I have come across a serious problem and no luck with fixing it.

I wanted the ability to force close few clients upon particular conditions (like chat spam). I have added the following code to the MessageServer class



```
    Public Sub Close(ByVal host As HostInfo)
        Dim client = (From c In Me.clients.Keys _
                      Where Me.clients(c).Equals(host) _
                      Select c).First()

        Me.RemoveClient(client)
    End Sub
```

And in the RemoveClient method, I have added



```
   client.GetStream().Close()
            client.Close()
```

This works perfectly fine to disconnect a particular client when the HostInfo is passed to the Close method. However, there is a problem. Whenever I try to close a connection, all the other connections from the same host are also closed. 
For example, If I have three hosts connected... 192.168.1.2:2554, 192.168.1.2:2555 and 192.168.1.4:8888 and if I try to disconnect the 2nd host, the 1st host is also getting disconnected because it is from the same host, whereas the 3rd connection is working fine. This seems to be very strange. I have come across another thread at Stackoverflow mentioning the same problem, but I had no idea how to proceed.

http://stackoverflow.com/questions/9...r-tcpclients-a

----------


## jmcilhinney

@iProgrammer, while reviving a very old thread is generally not a great idea, it's not really a problem in the case of CodeBank threads like this one.  With regards to your issue, it's quite a while since I looked at this code but I may have some time in the next couple of days so I'll see if I can see a way to resolve your issue.

----------


## iProgrammer

> @iProgrammer, while reviving a very old thread is generally not a great idea, it's not really a problem in the case of CodeBank threads like this one.  With regards to your issue, it's quite a while since I looked at this code but I may have some time in the next couple of days so I'll see if I can see a way to resolve your issue.


I totally understand. Thanks for your time

----------


## jafcarsa

Hi !!! I'm will try use this library, but the server is a windows service. This produce that the service dead by SynchronizationContext class. Someone could help me ? A light for resolve this...

----------


## jmcilhinney

> Hi !!! I'm will try use this library, but the server is a windows service. This produce that the service dead by SynchronizationContext class. Someone could help me ? A light for resolve this...


The point of the SynchronizationContext is to be able to marshal a method call to the UI thread in order to update the UI.  There's no UI in a Windows Service so there's no need to update anything specifically on the UI thread, therefore there's no need for the SynchronizationContext.  It only works in Windows Forms and WPF applications because those are the only applications that need to use it.  In a Windows Service you will still need to synchronise multiple threads such that they don't interfere with each other but there's no need to perform any particular operation on any particular thread.

----------


## jafcarsa

> The point of the SynchronizationContext is to be able to marshal a method call to the UI thread in order to update the UI.  There's no UI in a Windows Service so there's no need to update anything specifically on the UI thread, therefore there's no need for the SynchronizationContext.  It only works in Windows Forms and WPF applications because those are the only applications that need to use it.  In a Windows Service you will still need to synchronise multiple threads such that they don't interfere with each other but there's no need to perform any particular operation on any particular thread.


Thanks you jmcilhinney for your answer and time. I understand this and i try explain to you. I want the server to be a service because I'm using it to send notification messages to clients (as messenger). The client has a graphical interface. The problem is that when a client connects to the server, the service drop me a NullException, as the context for the service is null. I tried to work without this class, but then the server not notify to customers. Any idea?

----------


## jmcilhinney

> Thanks you jmcilhinney for your answer and time. I understand this and i try explain to you. I want the server to be a service because I'm using it to send notification messages to clients (as messenger). The client has a graphical interface. The problem is that when a client connects to the server, the service drop me a NullException, as the context for the service is null. I tried to work without this class, but then the server not notify to customers. Any idea?


You don't use the SynchronizationContext in a Windows Service because there's no UI and no UI thread.  If what you did without it doesn't work then you did it wrong but there's no way for us to know what you did wrong if we don't know what you did.  I suggest that you start a new thread on the topic and make reference to this thread if appropriate.

----------


## jafcarsa

> You don't use the SynchronizationContext in a Windows Service because there's no UI and no UI thread.  If what you did without it doesn't work then you did it wrong but there's no way for us to know what you did wrong if we don't know what you did.  I suggest that you start a new thread on the topic and make reference to this thread if appropriate.


Thanks you jcmilhinney !!!  :Smilie:  Regards...

----------


## Mogge

First of all - jmcilhinney - great job!
This STILL rocks!  :Smilie: 

I am sorry if I am bumping an old thread but just a few questions / surgestions to this.

As a start - I use vb in vs.net 2013 and the code works 100% after the standard auto convert. The Demo/Test works as intended. Great.

A few things:
   * The possibility to set host and port IN RUNTIME instead of doing it in the CODE - look #218, please. This describe very much what I'm after.
   * The possibility to send files - I can see that this was a subject in some of the post but for a newbee like me it's difficult to figure out how I must do this.
   * The possibility to open/close connections during RUNTIME - how sould I invoke this?


Again - THANKS!!! The code is VERY well documented and really easy to understand. Excellent.

Thx for answering.


Best Regards
Mogge

----------


## jmcilhinney

> First of all - jmcilhinney - great job!
> This STILL rocks! 
> 
> I am sorry if I am bumping an old thread but just a few questions / surgestions to this.
> 
> As a start - I use vb in vs.net 2013 and the code works 100% after the standard auto convert. The Demo/Test works as intended. Great.
> 
> A few things:
>    * The possibility to set host and port IN RUNTIME instead of doing it in the CODE - look #218, please. This describe very much what I'm after.
> ...


Bumping an old CodeBank thread is far less of an issue than bumping an old question thread.  You just may not be guaranteed of getting a reply from the original author if they're not still around or subscribed to the thread and others may not be inclined to open a thread from the New Posts link when it's already got lots of replies.  I'm still around and still subscribed to all my CodeBank threads though, so no issue here.

The original point of this thread was to demonstrate the use of asynchronous methods.  The TCP communication and chat client was just a means to an end, not an end in itself.  That's why I haven't really looked at improving those aspects of the demo substantially.  Let me see if I can address your questions, although I'm not actually looking at the code right now because I'm on a train on the way to work.

1. I can't recall exactly where the host name and port number are specified but, wherever it is, you can use whatever values you want from whatever source you want.  Simply change any values that I've hard-coded to variables that are populated from user input.  You can do that any way that you want.
2. The only thing that gets sent form one end to the other is Bytes.  This demo creates those Bytes from a String and then back again but the Bytes can represent anything you want.  If you are going to send data of different types though, you're going to have to send a header with each message so that the receiver knows how to interpret it.  The rules about how to interpret communication is the protocol for your app.
3. If I remember correctly, the client app lets you open and close child windows to open and close connections to the server, so that can already be done.  If you want to use a different prompt to open and close a connection then by all means do so, but the actual opening and closing will still be done the same way.

You need to separate the different parts of the app and realise which parts change and which stay the same.  You can change a higher layer without changing what happens below it.

----------


## Niya

Boo!!

----------


## lazreg

Thank you so much Mr jmcilhinney ,,,
i'm a newbie 
wow it's wonderful ,, that's what i need if r u agree to edit and use it again ...
just a little edit and u 'll be appreciated 
1 - Sending & Receiving msgs with UTF8 Encoding.
2- About server : when receive a msg from client i need to catch it's ID (or something like this) and resend it  to the same client in the same time for example :
Client ID or Name:  
client-1:   sends msg "1" to the Server and the Server resend msg "One" to the same client (client-1)
client-2:   sends msg "2" to the Server and the Server resend msg "Two" to the same client (client-2)
and so on ....
thank u in advance

----------


## cary1234

I wanted to modify the code so it can connect to other PC within the same network.

This is my attempt, changing this code



```
''' <summary>
''' A window to represent a client that sends text messages to and receives text messages from a server.
''' </summary>
Public Class ClientWindow

#Region " Fields "

    ''' <summary>
    ''' The name of the server to connect to.
    ''' </summary>
    ''' <remarks>
    ''' In this case use the local machine.
    ''' </remarks>
    Private ReadOnly host As String = Environment.MachineName
    ''' <summary>
```

To this code



```
''' <summary>
''' A window to represent a client that sends text messages to and receives text messages from a server.
''' </summary>
Public Class ClientWindow

#Region " Fields "

    ''' <summary>
    ''' The name of the server to connect to.
    ''' </summary>
    ''' <remarks>
    ''' In this case use the local machine.
    ''' </remarks>
    Private ReadOnly host As String = "192.168.110.140"
```

They are in the same network. My IP is 192.168.110.130 and the IP of the server listener is 192.168.110.140. Any idea why isn't this approach working?

----------


## jmcilhinney

> I wanted to modify the code so it can connect to other PC within the same network.
> 
> This is my attempt, changing this code
> 
> 
> 
> ```
> ''' <summary>
> ''' A window to represent a client that sends text messages to and receives text messages from a server.
> ...


I just tested with two of my own machines and it worked fine with either a machine name or an IPv4 address.

----------


## cary1234

Thank you so much, yeah it's also for me now. I think the problem is in my firewall. I just turned it off and everything is working fine now.

----------


## jmcilhinney

> Thank you so much, yeah it's also for me now. I think the problem is in my firewall. I just turned it off and everything is working fine now.


When I first ran the project on either machine, I was prompted to allow a firewall exception to be created automatically.  I would think that the whole thing would either fail on the one machine and on multiple machines or else work in both cases.

----------


## Johno2518

Hi All,

I know it's been a long time, I have been using this library for a long time (~8 or so years). I have been tweaking it and maintaining it for my purposes. I have not made any changes to my version for ~2 years however it was definitely time to allow others to use it.

While the code has been re-written to C# (not the purpose of this forum), I am supplying the link for anyone who may whish to download / compile the library for use with a couple additional changes / enhancements.

https://github.com/Johno-ACSLive/ACS-Messaging

I will eventually create a CI / CD pipeline for automated build releases and also provide a NuGet package but the source is available. I still have the VB.NET version prior to conversion (I don't believe I made any functional changes to the code). I don't plan on making this available (only because C# seems to be treated better when it comes to things like .NET Core / Standard which is where I will be moving the project to) but can if anyone is interested.

Very big thank you to jmcilhinney for the original project, it definitely helped greatly with network communication between client/server applications I developed!!!

Thanks

----------


## Johno2518

Hi All,

I know it's been a long time, I have been using this library for a long time (~8 or so years). I have been tweaking it and maintaining it for my purposes. I have not made any changes to my version for ~2 years however it was definitely time to allow others to use it.

While the code has been re-written to C# (not the purpose of this forum), I am supplying the link for anyone who may whish to download / compile the library for use with a couple additional changes / enhancements.

https://github.com/Johno-ACSLive/ACS-Messaging

I will eventually create a CI / CD pipeline for automated build releases and also provide a NuGet package but the source is available. I still have the VB.NET version prior to conversion (I don't believe I made any functional changes to the code). I don't plan on making this available (only because C# seems to be treated better when it comes to things like .NET Core / Standard which is where I will be moving the project to) but can if anyone is interested.

Very big thank you to jmcilhinney for the original project, it definitely helped greatly with network communication between client/server applications I developed!!!

Thanks

----------


## jmcilhinney

> Very big thank you to jmcilhinney for the original project, it definitely helped greatly with network communication between client/server applications I developed!!!
> 
> Thanks


I'm very pleased that my demo was put to good use.

----------


## PacificPilotNZL

Hello,

I love the idea of this library, but even using the test application included in the solution, the text would come through in other characters. An example of this is:

Sending "Test" over TCP would turn into "敔瑳" in the output window.

It's also only accepting every second connection.

Would appreciate your help, Thanks, Will

----------


## jmcilhinney

> Hello,
> 
> I love the idea of this library, but even using the test application included in the solution, the text would come through in other characters. An example of this is:
> 
> Sending "Test" over TCP would turn into "敔瑳" in the output window.
> 
> It's also only accepting every second connection.
> 
> Would appreciate your help, Thanks, Will


That sounds like an encoding issue. I haven't looked at this code for some time but I certainly don't recall that behaviour. Did you just use the attached solution as is? What version of VS are you using? I'll take a look some time soon but it's 1.30 AM here, so not right now.

----------


## Erden

Hello,

I have been using the library for a while and it's been working great. 

I have one problem; sometimes when the server is working on a virtual environment (VMWare) everything works well except when the client is closed, the server still sees the client as connected.

I was wondering if I am missing something or there is a solution for that?

Thanks!

----------


## Niya

> I have one problem; sometimes when the server is working on a virtual environment (VMWare) everything works well except when the client is closed, the server still sees the client as connected.


Is client being closed explicitly? Or is it being closed implicitly? Implicit would be something like shutting down the computer without closing the client, disconnecting the ethernet cable etc....

----------


## Erden

It is closed explicitly.

----------


## Niya

Ok. Well in general when writing TCP/IP applications and a connection is closed, ideally you want the endpoint that is closing to send a message to the other endpoint telling it this. Relying solely on the TCP/IP network stack to manage this is a bad idea. In order to make TCP/IP connections reliable, they had to make it extremely forgiving when it comes to closed connections to support cases where the connection is intermittent. TCP/IP by design tries as much as possible to *avoid* assuming that a connection is closed when conditions are unclear.

My recommendation would to implement a message in your protocol that tells the server when a connection is being closed. This is the proper practice.

----------


## Erden

> My recommendation would to implement a message in your protocol that tells the server when a connection is being closed. This is the proper practice.


Thanks a lot Niya, for the explanation and recommendation. I'll implement a connection closing protocol. 

All the best.

----------


## MHutcheon

Hello, I am quite new to vb.net programming and this has caught my interest - I have plans for an application to grab a portion of the screen and send it to remote clients. Could the code in the opening post be adapted to send images rather than text strings?

Regards,
Malcolm

----------


## jmcilhinney

> Could the code in the opening post be adapted to send images rather than text strings?


Absolutely, I haven't looked at the internal workings of that Send method in a long time but it's Bytes that actually get sent so you can send anything that you can convert to Bytes, so anything at all. You could add an overload of Send that accepted an Image rather than a String and then converted that Image to Bytes and sent those in basically the same way. I have another CodeBank thread about saving Images to a database and that shows how to convert an Image to a Byte array and back again.

Note that, if you intend to send different types of data, you'll need to precede that data with a code to indicate what type of data it is, so the receiver knows how to convert it back again.

----------


## MHutcheon

> Absolutely, I haven't looked at the internal workings of that Send method in a long time but it's Bytes that actually get sent so you can send anything that you can convert to Bytes, so anything at all. You could add an overload of Send that accepted an Image rather than a String and then converted that Image to Bytes and sent those in basically the same way. I have another CodeBank thread about saving Images to a database and that shows how to convert an Image to a Byte array and back again.
> 
> Note that, if you intend to send different types of data, you'll need to precede that data with a code to indicate what type of data it is, so the receiver knows how to convert it back again.


Hi there!

Thanks for your encouraging reply, and indeed for still being around some 13 years after the original post!  :Smilie: 

I think I am good with converting the image to a byte array, but I will search for your thread to see if I can improve mine based on it.

I am not asking you to do this for me, I won't learn anything if you do  :Smilie: , but as I am still new, am I correct in assuming, in *MessageServer.vb*, with regards to Sending I am looking at adapting:



```
    Public Sub Send(ByVal hostName As String, ByVal port As Integer, ByVal message As String)
        Dim client = (From c In Me.clients.Keys _
                      Let h = Me.clients(c) _
                      Where h.HostName = hostName AndAlso h.Port = port _
                      Select c).First()

        Me.Send(client, message)
    End Sub
...
    Public Sub Send(ByVal host As HostInfo, ByVal message As String)
        Dim client = (From c In Me.clients.Keys _
                      Where Me.clients(c).Equals(host) _
                      Select c).First()

        Me.Send(client, message)
    End Sub
...
    Public Sub Send(ByVal message As String)
        For Each client In Me.clients.Keys
            Me.Send(client, message)
        Next
    End Sub
```

and from *MessageClient.vb*:



```
    Public Sub Send(ByVal message As String)
        'Convert the text message to binary data.
        Dim buffer As Byte() = Me.Encoding.GetBytes(message)

        'Write the data asynchronously.
        Me.stream.BeginWrite(buffer, 0, buffer.Length, AddressOf Write, Nothing)
    End Sub
```

----------


## jmcilhinney

@MHutcheon, this is the important part:

vb.net Code:
'Convert the text message to binary data.
Dim buffer As Byte() = Me.Encoding.GetBytes(message)
That is converting the String to a Byte array. You need to accept an Image and convert that to a Byte array. The thread I was referring to that demonstrates that is here:

https://www.vbforums.com/showthread....a-in-Databases

Note that, as an Image may be fairly big, you might want to write it in chunks.

----------


## MHutcheon

> @MHutcheon, this is the important part:
> 
> vb.net Code:
> 'Convert the text message to binary data.
Dim buffer As Byte() = Me.Encoding.GetBytes(message)
> That is converting the String to a Byte array. You need to accept an Image and convert that to a Byte array. The thread I was referring to that demonstrates that is here:
> 
> https://www.vbforums.com/showthread....a-in-Databases
> 
> Note that, as an Image may be fairly big, you might want to write it in chunks.


Hi,

My code is stopping at this point, saying:



> 'Public Overrides Function GetBytes(s As String) As Byte()':
>         Argument matching parameter 's' cannot convert from 'Byte()' to 'String'.


and when I hover over _message_ it is confirming for me message is a byte array - byte() - and has a length of 36167 bytes. If I read it correctly, the code is trying to convert my array back to a string? This is well beyond my level  :Frown: 

PS - apologies if I am straying off course here...

----------


## jmcilhinney

> when I hover over _message_ it is confirming for me message is a byte array - byte() - and has a length of 36167 bytes. If I read it correctly, the code is trying to convert my array back to a string? This is well beyond my level


The point of calling Encoding.GetBytes is to convert a String to a Byte array. You're not using Strings so you don't use that method at all, especially not to pass a Byte array in. As you can see from then existing code, you get the Byte array from the original data and then you write it to the stream. Your original data is an Image. Get a Byte array from that and then write it to the stream.

----------


## MHutcheon

> The point of calling Encoding.GetBytes is to convert a String to a Byte array. You're not using Strings so you don't use that method at all, especially not to pass a Byte array in. As you can see from then existing code, you get the Byte array from the original data and then you write it to the stream. Your original data is an Image. Get a Byte array from that and then write it to the stream.


I thought that was what I was trying to. Here is my code to generate the byte  array:


```

picScreenCapture.Image = CropImage
Dim ms As New MemoryStream
CropImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)

Dim arrImage() As Byte
arrImage = ms.GetBuffer

For Each recipient In arListOfRecipients
    Dim arElements As String() = recipient.ToString.Split(New String() {":"}, StringSplitOptions.None)
    Dim tmpIP As String = arElements(0)
    Dim tmpPort As Integer = arElements(1)
                
   IMGserver.Send(tmpIP, tmpPort, arrImage)
Next
```

but using this generates the error in post 271.

I don't really understand how get the code to use the different instances of MessageServer.

----------

