-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
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:
Code:
Dim userInfo = hostInfos.SingleOrDefault(Function(hi) hi.UserName = userName)
If userInfo <> Nothing Then
Quote:
Originally Posted by
yfzpurgatory
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
I'm actually using a new instance of the form. Here's the call:
Code:
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.
Code:
Public Class mdiMain
Public chlChat As New frmChat()
Loading chlChat and using it:
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Here's a screen shot of what I've done with it:
http://i.imgur.com/zuW6R.jpg
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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'.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Here's the disassembly:
Code:
00000080 mov dword ptr [ebp-24h],eax
The error is occurring on this line:
Code:
'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:
Code:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
yfzpurgatory
Here's the disassembly:
Code:
00000080 mov dword ptr [ebp-24h],eax
The error is occurring on this line:
Code:
'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:
Code:
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.
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
Either the server isn't running or you you used the wrong address and/or port when trying to connect to it.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Rovin1955
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?
Quote:
Originally Posted by
Rovin1955
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Hey I am curious, could this be combined into one application that is both a server and a client?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
KyleBoyer
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Look below -_- I'm a newbie on these forums. :X
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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:
Code:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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. ;)
If I can use an example from your own code, where you create the object named server in the class using the following statement
Code:
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)
Code:
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
Code:
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.
Code:
Dim server As New MessageServer(iListenerPort )
And I've added the following event handlers
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
yfzpurgatory
When a MessageServer object is implemented in C# your library throws a NullReferenceException at this line:
Code:
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.
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
yfzpurgatory
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
yfzpurgatory
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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:
Code:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
yfzpurgatory
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
Nightwalker83
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
... 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):
Code:
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:
Code:
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?
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
@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:
Code:
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
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:
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
@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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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:
Code:
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
i00
hello? (*bump)
I'll get to this if and when I can, which may not be any time soon or ever.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
@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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
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.
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
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
Quote:
Originally Posted by
jmcilhinney
I'll get to this if and when I can, which may not be any time soon or ever.
Hope you can *cross fingers*
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.
-
Re: [VB2008/.NET 3.5] Asynchronous TcpListener & TcpClient
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.