-
1 Attachment(s)
[VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: Fixed Known Issue 1
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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....
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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....
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.......'
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.
Quote:
Originally Posted by
Farflamex
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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....
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.......'
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Farflamex
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.
Quote:
Originally Posted by
Farflamex
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 :)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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 :)
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 :p
Anyhoo, I'm learning as I go along. I'll try to break this down into something I understand and then build onto it.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 :)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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 :)
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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. :)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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. :)
Sounds reasonable.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Im getting a lot of issues I can hardly do anything :S. Here is what i have:
Server:
Code:
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
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
rydinophor
Im getting a lot of issues I can hardly do anything :S. Here is what i have:
Server:
Code:
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
Code:
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
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.
-
Improvements in version 1.1.0.0
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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:
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
rydinophor
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.
Quote:
Originally Posted by
rydinophor
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.
Quote:
Originally Posted by
rydinophor
I keep getting these errors:
Code:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
chris128
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Error:
Code:
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:
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
rydinophor
Error:
Here's your issue:
Quote:
Message="Index was outside the bounds of the array."
Quote:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
chris128
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
chris128
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.
Quote:
Originally Posted by
chris128
That page and the MSDN doco are all I've read on the subject too.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 :)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 ?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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 ?
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Hello,
I found a little problem ( but didn't found solution ).
Code:
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 :
Code:
Dim byteCount = Me.stream.EndRead(ar)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Ianis
Hello,
I found a little problem ( but didn't found solution ).
Code:
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 :
Code:
Dim byteCount = Me.stream.EndRead(ar)
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. :)
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Is there VB.Net 2005 version of this class?
thank's
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Visual Basic.Net
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.
-
1 Attachment(s)
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Hello,
i'am trying to use your Class in Console.
But i have several bugs during devugging like :
Quote:
La référence d'objet n'est pas définie à une instance d'un objet.
Quote:
Object reference not set to an instance of an object.
On Connection Event.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Ianis
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Ianis
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
I found what's going wrong :
it's a Console Application, so this need a
But..
With your class i need to add this in a Sub :
ByVal Sender As Object, ByVal e As MessageReceivedEventArgs
Code:
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
Quote:
No accessible 'Main' method with an appropriate signature was found
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Thanks John. I will will have a play around with this and some of the other great information from your blogs.
Cheers
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Ianis
I found what's going wrong :
it's a Console Application, so this need a
But..
With your class i need to add this in a Sub :
ByVal Sender As Object, ByVal e As MessageReceivedEventArgs
Code:
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
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?
Code:
Sub Main()
AddHandler server.MessageReceived, AddressOf MessageRecieved
Console.ReadLine()
End Sub
Sub MessageRecieved(ByVal Sender As Object, ByVal e As MessageReceivedEventArgs)
'...
End Sub
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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 )
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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 )
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
Beyond the scope of this thread.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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. :(
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
My modified code doesn't send files properly; the files become corrupted.
-
1 Attachment(s)
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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?
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Any thoughts on my telnet question?