Problem closing TcpClient app

N

Nickneem

I hope there's someone out there who knows what's wrong with my code.
I'm writing an app to connect with a TCPClient and send orders back and
forth..

Problem is that when I exit the application with me.close not all
threads are being closed, so I can't restart my app...
Same thing when I send a disconnect to the server, I can't reconnect
so I guess it must have something to do with blocking / endread?

Private Function ConnectToServer() As Boolean
Try

'Creates a TCPClient using a localend point.
'connect to the server
Dim ip As System.Net.IPAddress =
IPAddress.Parse(Global.Settings.GetString(SettingKeys.IpAddress))
client = New TcpClient
client.Connect(ip, PORT_NUM)

Threading.Thread.Sleep(MySleep) 'Misschien te weinig tijd
tussen connect
'en(beginread)


' Start an asynchronous read invoking DoRead to avoid
lagging the user
' interface.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE,
AddressOf DoRead, Nothing)

' Make sure the window is showing before popping up
connection dialog.
Me.Show()
SendData("CONNECT|" & lblEmployee.Text)
Log("After senddata", LogWriter)
Catch Ex As SocketException
Select Case Ex.ErrorCode
Case 10060
MsgBox("Server with IP: " &
Global.Settings.GetString(SettingKeys.IpAddress) & " on port: " &
Global.Settings.GetString(SettingKeys.PortNumber) & " unreachable!", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 10061
MsgBox("Server's down. Restart server and try
again.", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 11001
MsgBox("No server known as: ", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 10065
MsgBox("No wireless connection?", _
MsgBoxStyle.Exclamation,
Me.Text)
Case Else
MsgBox("Unknown error: " & Ex.ErrorCode)
client.Close()
ShowOptionsForm()
End Select
ClientConnected = False 'zet vlag connection is uit
If IsDBNull(client) Then Exit Function

If Not IsNothing(client) Then
'Close stream so that our AsyncReader are closed
'01-01-05 even uitgezet
' client.GetStream.Close()

'Close tcpClient
client.Close()
End If
End Try
Return True
End Function

'['CLOSE' PART]

Private Sub MainForm_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Try
If ClientConnected = True Then
SendData("DISCONNECT")
End If

Threading.Thread.Sleep(MySleep)

' Send only if server is still running.
Call ResetSocket()

Threading.Thread.Sleep(MySleep)
Catch ex As Exception
End Try
End Sub

'[CLEAN UP]
Private Sub ResetSocket()
Try
If Not client.GetStream Is Nothing Then
client.GetStream.Close()
End If
client.Close()
streamRead.Close()
streamRead = Nothing
client = Nothing
Catch ex As Exception
End Try
End Sub

I saw some other 'similar' postings:
http://groups.google.nl/group/micro...854ab5?q=close+&rnum=4&hl=nl#e3480a4eeb854ab5

but I am unable / incapable to solve this myself...

Thanks in advance,

Mike Dole
 
P

Paul G. Tobey [eMVP]

So, your network code is running in one or more separate threads? If so,
you *must* create some means for those threads to exit when it's time for
the application to leave. If you don't, the application actually continues
to run, although the main window may be closed and it may not have any other
user interface. In the case of threads which are using sockets, set an
'exit now' flag, close the sockets from the UI thread when you're about to
call Me.Close, and wait for each thread to exit before calling Me.Close.

Paul T.

Nickneem said:
I hope there's someone out there who knows what's wrong with my code.
I'm writing an app to connect with a TCPClient and send orders back and
forth..

Problem is that when I exit the application with me.close not all
threads are being closed, so I can't restart my app...
Same thing when I send a disconnect to the server, I can't reconnect
so I guess it must have something to do with blocking / endread?

Private Function ConnectToServer() As Boolean
Try

'Creates a TCPClient using a localend point.
'connect to the server
Dim ip As System.Net.IPAddress =
IPAddress.Parse(Global.Settings.GetString(SettingKeys.IpAddress))
client = New TcpClient
client.Connect(ip, PORT_NUM)

Threading.Thread.Sleep(MySleep) 'Misschien te weinig tijd
tussen connect
'en(beginread)


' Start an asynchronous read invoking DoRead to avoid
lagging the user
' interface.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE,
AddressOf DoRead, Nothing)

' Make sure the window is showing before popping up
connection dialog.
Me.Show()
SendData("CONNECT|" & lblEmployee.Text)
Log("After senddata", LogWriter)
Catch Ex As SocketException
Select Case Ex.ErrorCode
Case 10060
MsgBox("Server with IP: " &
Global.Settings.GetString(SettingKeys.IpAddress) & " on port: " &
Global.Settings.GetString(SettingKeys.PortNumber) & " unreachable!", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 10061
MsgBox("Server's down. Restart server and try
again.", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 11001
MsgBox("No server known as: ", _
MsgBoxStyle.Exclamation,
Me.Text)
Case 10065
MsgBox("No wireless connection?", _
MsgBoxStyle.Exclamation,
Me.Text)
Case Else
MsgBox("Unknown error: " & Ex.ErrorCode)
client.Close()
ShowOptionsForm()
End Select
ClientConnected = False 'zet vlag connection is uit
If IsDBNull(client) Then Exit Function

If Not IsNothing(client) Then
'Close stream so that our AsyncReader are closed
'01-01-05 even uitgezet
' client.GetStream.Close()

'Close tcpClient
client.Close()
End If
End Try
Return True
End Function

'['CLOSE' PART]

Private Sub MainForm_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Try
If ClientConnected = True Then
SendData("DISCONNECT")
End If

Threading.Thread.Sleep(MySleep)

' Send only if server is still running.
Call ResetSocket()

Threading.Thread.Sleep(MySleep)
Catch ex As Exception
End Try
End Sub

'[CLEAN UP]
Private Sub ResetSocket()
Try
If Not client.GetStream Is Nothing Then
client.GetStream.Close()
End If
client.Close()
streamRead.Close()
streamRead = Nothing
client = Nothing
Catch ex As Exception
End Try
End Sub

I saw some other 'similar' postings:
http://groups.google.nl/group/micro...854ab5?q=close+&rnum=4&hl=nl#e3480a4eeb854ab5

but I am unable / incapable to solve this myself...

Thanks in advance,

Mike Dole
 
M

Mike Dole

Paul G. Tobey said:
So, your network code is running in one or more separate threads? If so,
you *must* create some means for those threads to exit when it's time for
the application to leave. If you don't, the application actually continues
to run, although the main window may be closed and it may not have any other
user interface. In the case of threads which are using sockets, set an
'exit now' flag, close the sockets from the UI thread when you're about to
call Me.Close, and wait for each thread to exit before calling Me.Close.

Paul T.

Thanks for your help Paul,

I don't understand what triggers the start of a new thread and the
reason why it is started, if we look at:

client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE,
AddressOf DoRead, Nothing)

Does this mean that a new thread is started every time it receives
data from the server and if so that the endread command closes the
thread properly?

Could you give me some clues on where and how to close the sockets?

Much appreciated and sorry for my dumbness..

Michael
 
P

Paul G. Tobey [eMVP]

Yes, BeginRead() is going to create a thread. I wouldn't use that form of
socket I/O (begin/end stuff). The easiest way for us to suggest something
is if you tell us *what* you're trying to do, rather than *how* you're
trying to do it. Or, you might post the simplest application that
demonstrates the problem, allowing us to see the problem for ourselves by
building your code and trying it.

Paul T.
 
M

Mike Dole

Paul G. Tobey said:
Yes, BeginRead() is going to create a thread. I wouldn't use that form of
socket I/O (begin/end stuff). The easiest way for us to suggest something
is if you tell us *what* you're trying to do, rather than *how* you're
trying to do it. Or, you might post the simplest application that
demonstrates the problem, allowing us to see the problem for ourselves by
building your code and trying it.

Paul T.

Paul,

What I want to do is: after connecting to the server I want the PDA
client to receive data from the server with a list of products which
the PDA client can pick.
After receiving the data, the stream is saved to an xml file and read
into a dataset.
This dataset is the datasource of a treeview which shows the items
that the client can pick.
If the client has send the order to the server it receives a
confirmation from the server that everything went well..

[RECEIVE PART]

Private Sub DoRead(ByVal ar As IAsyncResult)
Dim BytesRead As Integer
Dim strMessage As String

Try

' Ensure that no other threads try to use the stream at
the same time.
SyncLock client.GetStream
'If client.GetStream.DataAvailable Then
BytesRead = client.GetStream.EndRead(ar)
'End If
End SyncLock
' Finish asynchronous read into readBuffer and return
number of bytes read.

If BytesRead < 1 Then
' If no bytes were read server has close. Disable
input window.
Exit Sub
End If

If BytesRead > 0 Then
MyByteCounter = MyByteCounter + BytesRead
streamRead.Write(readBuffer, 0, BytesRead)
If Network.CheckForTerminator(streamRead.ToArray()) =
True Then
Threading.Thread.Sleep(MySleep) 'hielp ook!
Call NotifyCallback(streamRead)
End If
End If

' Ensure that no other threads try to use the stream at
the same time.
SyncLock client.GetStream
' Start a new asynchronous read into readBuffer.
If client.GetStream.CanRead Then
' Start a new asynchronous read into readBuffer.
client.GetStream.BeginRead(readBuffer, 0,
READ_BUFFER_SIZE, AddressOf DoRead, Nothing)
End If
End SyncLock

Catch e As Exception
client.GetStream.EndRead(ar)
Log(e.ToString, LogWriter)
End Try
End Sub


Private Sub NotifyCallback(ByVal data As MemoryStream)
Try
' The .Net Compact Framework does not support
Control.Invoke
' that allows you to pass arguments to the delegate. So
save
' arguments to class fields and then invoke the delegate.
SyncLock Me
' save arguments to class fields
_notifyData = data

' execute the method on the GUI's thread, this method
' uses the _notifyCommand and _notifyData fields
Invoke(_processCommand)
End SyncLock
Catch
End Try
End Sub




Private Sub ProcessSocketCommand(ByVal sender As Object, ByVal args As
EventArgs)
Dim strMessage As String
Dim dataArray() As String
'sound.PlaySync() 'sync playing

streamRead = _notifyData

Try
' remove message terminator
streamRead.SetLength((streamRead.Length -
Network.Terminator.Length))
'En van de bytecounter ook de terminatorlengte afhalen
MyByteCounter -= Network.Terminator.Length

' get the command data
streamRead.Position = 0
Dim data As Byte() = streamRead.ToArray()

' Convert the byte array the message was saved into, minus
one for the
' Chr(13).

strMessage = System.Text.Encoding.ASCII.GetString(data, 0,
MyByteCounter)

'Maak streamreader leeg
streamRead.SetLength(0)
MyByteCounter = 0

Catch ex As Exception
MsgBox(ex.ToString)
End Try

Try

'Message parts are divided by "|" Break the string into an array
accordingly.
dataArray = strMessage.Split(Chr(124))

' dataArray(0) is the command.
Log(dataArray(0), LogWriter)
Select Case dataArray(0)
Case "JOIN"
' Server acknowledged login.
DisplayText("Connecting to server...")
Threading.Thread.Sleep(MySleep) 'hielp ook!
DisplayText("Fetching menu.")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.ready.wav"))
sound.Play() 'async playing
ClientConnected = True 'zet vlag connection is ok!
taborder.BackColor =
System.Drawing.Color.LightSteelBlue
'Nieuwe order aanmaken
Call NewOrder()
Case "QUIT"
DisplayText("Server's down, please try again
later")
taborder.BackColor = System.Drawing.Color.Red
ClientConnected = False 'zet vlag connection uit
treeMenu.Enabled = False
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
'client.Close()
Case "REFUSE" 'Er is al een user met dezelfde naam
Dim MyEmployee As String
MyEmployee = lblEmployee.Text
DisplayText("Employee already connected, select
another and reconnect!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
taborder.BackColor = System.Drawing.Color.Red
Application.DoEvents()
treeMenu.Enabled = False
'client.Close() 'Close the client!
If MyEmployee = lblEmployee.Text Then
Me.Invoke(New EventHandler(AddressOf
ShowEmplyeeForm))
lblEmployee.Text =
Global.Settings.GetString(SettingKeys.Employee)
End If
Case "ORDERACCEPTED"
DisplayText("Order's processed on the server!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.blip.wav"))
sound.Play() 'async playing
MsgBox("Order's processed on the server!",
MsgBoxStyle.Information, "WifiOrder PDA")
Case "REQCATALOG"
WriteXMLOrder(dataArray(1), "\assortiment.xml")
treeMenu.Enabled = True
FillTreeView()
DisplayText("The server's ready to process your
order...")
Case "REQORDER"
WriteXMLOrderStatus(dataArray(1),
"\lopendeorders.xml")
Call CreateTableOrdersDS()
TabControl1.SelectedIndex = 1
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.reminder.wav"))
sound.Play() 'async playing
Case Else
End Select
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub


[SEND PART]

Public Sub SendData(ByVal Data As String)
' Synclock ensure that no other threads try to use the stream
at the same time.
Try
Log("before client.getstream", LogWriter)
SyncLock client.GetStream
If client.GetStream.CanWrite Then
Dim myWriteBuffer As Byte() =
Encoding.ASCII.GetBytes(Data & "<data_end>")
client.GetStream.BeginWrite(myWriteBuffer, 0,
myWriteBuffer.Length, AddressOf MyStreamWriterCallBack, Nothing)
End If
End SyncLock
Log("after client.getstream", LogWriter)
Catch ex As Exception
MsgBox(ex.ToString)
DisplayText("Error connecting to server, restart ORDER")
End Try
End Sub


Kind regards and thanks again!

Michael
 
P

Paul G. Tobey [eMVP]

I would accomplish that by putting *all* of the network and file I/O work
into a separate thread which you create. When the thread completes, it can
notify the UI thread to load the file and create the data set. In the
thread, establish some means, as I mentioned, of getting out of the thread
when the application exits and the thread is still working (this could also
be used to Cancel the operation from the UI, even if the application isn't
exiting, giving you a better UI).

Paul T.

Mike Dole said:
Paul G. Tobey said:
Yes, BeginRead() is going to create a thread. I wouldn't use that form
of
socket I/O (begin/end stuff). The easiest way for us to suggest
something
is if you tell us *what* you're trying to do, rather than *how* you're
trying to do it. Or, you might post the simplest application that
demonstrates the problem, allowing us to see the problem for ourselves by
building your code and trying it.

Paul T.

Paul,

What I want to do is: after connecting to the server I want the PDA
client to receive data from the server with a list of products which
the PDA client can pick.
After receiving the data, the stream is saved to an xml file and read
into a dataset.
This dataset is the datasource of a treeview which shows the items
that the client can pick.
If the client has send the order to the server it receives a
confirmation from the server that everything went well..

[RECEIVE PART]

Private Sub DoRead(ByVal ar As IAsyncResult)
Dim BytesRead As Integer
Dim strMessage As String

Try

' Ensure that no other threads try to use the stream at
the same time.
SyncLock client.GetStream
'If client.GetStream.DataAvailable Then
BytesRead = client.GetStream.EndRead(ar)
'End If
End SyncLock
' Finish asynchronous read into readBuffer and return
number of bytes read.

If BytesRead < 1 Then
' If no bytes were read server has close. Disable
input window.
Exit Sub
End If

If BytesRead > 0 Then
MyByteCounter = MyByteCounter + BytesRead
streamRead.Write(readBuffer, 0, BytesRead)
If Network.CheckForTerminator(streamRead.ToArray()) =
True Then
Threading.Thread.Sleep(MySleep) 'hielp ook!
Call NotifyCallback(streamRead)
End If
End If

' Ensure that no other threads try to use the stream at
the same time.
SyncLock client.GetStream
' Start a new asynchronous read into readBuffer.
If client.GetStream.CanRead Then
' Start a new asynchronous read into readBuffer.
client.GetStream.BeginRead(readBuffer, 0,
READ_BUFFER_SIZE, AddressOf DoRead, Nothing)
End If
End SyncLock

Catch e As Exception
client.GetStream.EndRead(ar)
Log(e.ToString, LogWriter)
End Try
End Sub


Private Sub NotifyCallback(ByVal data As MemoryStream)
Try
' The .Net Compact Framework does not support
Control.Invoke
' that allows you to pass arguments to the delegate. So
save
' arguments to class fields and then invoke the delegate.
SyncLock Me
' save arguments to class fields
_notifyData = data

' execute the method on the GUI's thread, this method
' uses the _notifyCommand and _notifyData fields
Invoke(_processCommand)
End SyncLock
Catch
End Try
End Sub




Private Sub ProcessSocketCommand(ByVal sender As Object, ByVal args As
EventArgs)
Dim strMessage As String
Dim dataArray() As String
'sound.PlaySync() 'sync playing

streamRead = _notifyData

Try
' remove message terminator
streamRead.SetLength((streamRead.Length -
Network.Terminator.Length))
'En van de bytecounter ook de terminatorlengte afhalen
MyByteCounter -= Network.Terminator.Length

' get the command data
streamRead.Position = 0
Dim data As Byte() = streamRead.ToArray()

' Convert the byte array the message was saved into, minus
one for the
' Chr(13).

strMessage = System.Text.Encoding.ASCII.GetString(data, 0,
MyByteCounter)

'Maak streamreader leeg
streamRead.SetLength(0)
MyByteCounter = 0

Catch ex As Exception
MsgBox(ex.ToString)
End Try

Try

'Message parts are divided by "|" Break the string into an array
accordingly.
dataArray = strMessage.Split(Chr(124))

' dataArray(0) is the command.
Log(dataArray(0), LogWriter)
Select Case dataArray(0)
Case "JOIN"
' Server acknowledged login.
DisplayText("Connecting to server...")
Threading.Thread.Sleep(MySleep) 'hielp ook!
DisplayText("Fetching menu.")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.ready.wav"))
sound.Play() 'async playing
ClientConnected = True 'zet vlag connection is ok!
taborder.BackColor =
System.Drawing.Color.LightSteelBlue
'Nieuwe order aanmaken
Call NewOrder()
Case "QUIT"
DisplayText("Server's down, please try again
later")
taborder.BackColor = System.Drawing.Color.Red
ClientConnected = False 'zet vlag connection uit
treeMenu.Enabled = False
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
'client.Close()
Case "REFUSE" 'Er is al een user met dezelfde naam
Dim MyEmployee As String
MyEmployee = lblEmployee.Text
DisplayText("Employee already connected, select
another and reconnect!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
taborder.BackColor = System.Drawing.Color.Red
Application.DoEvents()
treeMenu.Enabled = False
'client.Close() 'Close the client!
If MyEmployee = lblEmployee.Text Then
Me.Invoke(New EventHandler(AddressOf
ShowEmplyeeForm))
lblEmployee.Text =
Global.Settings.GetString(SettingKeys.Employee)
End If
Case "ORDERACCEPTED"
DisplayText("Order's processed on the server!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.blip.wav"))
sound.Play() 'async playing
MsgBox("Order's processed on the server!",
MsgBoxStyle.Information, "WifiOrder PDA")
Case "REQCATALOG"
WriteXMLOrder(dataArray(1), "\assortiment.xml")
treeMenu.Enabled = True
FillTreeView()
DisplayText("The server's ready to process your
order...")
Case "REQORDER"
WriteXMLOrderStatus(dataArray(1),
"\lopendeorders.xml")
Call CreateTableOrdersDS()
TabControl1.SelectedIndex = 1
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.reminder.wav"))
sound.Play() 'async playing
Case Else
End Select
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub


[SEND PART]

Public Sub SendData(ByVal Data As String)
' Synclock ensure that no other threads try to use the stream
at the same time.
Try
Log("before client.getstream", LogWriter)
SyncLock client.GetStream
If client.GetStream.CanWrite Then
Dim myWriteBuffer As Byte() =
Encoding.ASCII.GetBytes(Data & "<data_end>")
client.GetStream.BeginWrite(myWriteBuffer, 0,
myWriteBuffer.Length, AddressOf MyStreamWriterCallBack, Nothing)
End If
End SyncLock
Log("after client.getstream", LogWriter)
Catch ex As Exception
MsgBox(ex.ToString)
DisplayText("Error connecting to server, restart ORDER")
End Try
End Sub


Kind regards and thanks again!

Michael
 
M

Mike Dole

Sorry for the delay Paul, just got back from holiday..

Can you shine your light on my theory:

I think the mistake I make is that I thought that by invoking the
_proccescommand delegate (ProcessSocketCommand method) all would be
well and I could safely 'touch' the controls on my UI.
However when I query the invokerequired property of the controls I
'touch' in the PSC method they all show TRUE..

I'm using a private variable (Private _notifyData As MemoryStream) for
storing the data inbetween threads (this doensn't sound good to me
either..?)

My dream scenario would be that the beginread / endread thread gives
back the memorystream (or Byte()) to the UI and I could safely do my
stuff with the data.

Please help me out once more because I'm not getting this threading
thing.
They remind me too much of my wife who always wants me to do 2 things
at the same time and I'm having trouble with that to (but I'll handle
that :cool: )

Kind regards,

Michael

Private Sub ProcessSocketCommand(ByVal sender As Object, ByVal args As
EventArgs)
Dim strMessage As String
Dim dataArray() As String
'sound.PlaySync() 'sync playing

streamRead = _notifyData

Try
' remove message terminator
streamRead.SetLength((streamRead.Length -
Network.Terminator.Length))
'En van de bytecounter ook de terminatorlengte afhalen
MyByteCounter -= Network.Terminator.Length

' get the command data
streamRead.Position = 0
Dim data As Byte() = streamRead.ToArray()

' Convert the byte array the message was saved into, minus
one for the
' Chr(13).

strMessage = System.Text.Encoding.ASCII.GetString(data, 0,
MyByteCounter)

'Maak streamreader leeg
streamRead.SetLength(0)
MyByteCounter = 0

Catch ex As Exception
MsgBox(ex.ToString)
End Try

Try

'Message parts are divided by "|" Break the string into an array
accordingly.
dataArray = strMessage.Split(Chr(124))

' dataArray(0) is the command.
Log(dataArray(0), LogWriter)
Select Case dataArray(0)
Case "JOIN"
' Server acknowledged login.
DisplayText("Connecting to server...")
Threading.Thread.Sleep(MySleep) 'hielp ook!
DisplayText("Fetching menu.")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.ready.wav"))
sound.Play() 'async playing
ClientConnected = True 'zet vlag connection is ok!
taborder.BackColor =
System.Drawing.Color.LightSteelBlue
'Nieuwe order aanmaken
Call NewOrder()
Case "QUIT"
DisplayText("Server's down, please try again
later")
taborder.BackColor = System.Drawing.Color.Red
ClientConnected = False 'zet vlag connection uit
treeMenu.Enabled = False
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
'client.Close()
Case "REFUSE" 'Er is al een user met dezelfde naam
Dim MyEmployee As String
MyEmployee = lblEmployee.Text
DisplayText("Employee already connected, select
another and reconnect!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
taborder.BackColor = System.Drawing.Color.Red
Application.DoEvents()
treeMenu.Enabled = False
'client.Close() 'Close the client!
If MyEmployee = lblEmployee.Text Then
Me.Invoke(New EventHandler(AddressOf
ShowEmplyeeForm))
lblEmployee.Text =
Global.Settings.GetString(SettingKeys.Employee)
End If
Case "ORDERACCEPTED"
DisplayText("Order's processed on the server!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.blip.wav"))
sound.Play() 'async playing
MsgBox("Order's processed on the server!",
MsgBoxStyle.Information, "WifiOrder PDA")
Case "REQCATALOG"
WriteXMLOrder(dataArray(1), "\assortiment.xml")
treeMenu.Enabled = True
FillTreeView()
DisplayText("The server's ready to process your
order...")
Case "REQORDER"
WriteXMLOrderStatus(dataArray(1),
"\lopendeorders.xml")
Call CreateTableOrdersDS()
TabControl1.SelectedIndex = 1
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.reminder.wav"))
sound.Play() 'async playing
Case Else
End Select
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
 
P

Paul G. Tobey [eMVP]

You just have to sit down and think about how things work. Take a look at
my last message. That's how I would do it and I know that it would work.
As I said, it also has advantages in user interface, where you can set up
things so that you can easily cancel the process.

There's nothing wrong with storing some data in private members of a class.
When threads are involved, you simply have to think about whether two
threads might be accessing the same piece of data at the same time and make
sure that, even if that happens, the data is always in a consistent state
when each thread gets to it. Mutexes are often used for this sort of
synchronization. However, in your case, I don't think that you need to go
that far. If you write a thread to do all of your file and network I/O and
simply, as I said, have it notify the UI thread when the file is done, the
actual network data is private to the network/file thread and there's no
need for the UI thread to access it at all.

Paul T.

Mike Dole said:
Sorry for the delay Paul, just got back from holiday..

Can you shine your light on my theory:

I think the mistake I make is that I thought that by invoking the
_proccescommand delegate (ProcessSocketCommand method) all would be
well and I could safely 'touch' the controls on my UI.
However when I query the invokerequired property of the controls I
'touch' in the PSC method they all show TRUE..

I'm using a private variable (Private _notifyData As MemoryStream) for
storing the data inbetween threads (this doensn't sound good to me
either..?)

My dream scenario would be that the beginread / endread thread gives
back the memorystream (or Byte()) to the UI and I could safely do my
stuff with the data.

Please help me out once more because I'm not getting this threading
thing.
They remind me too much of my wife who always wants me to do 2 things
at the same time and I'm having trouble with that to (but I'll handle
that :cool: )

Kind regards,

Michael

Private Sub ProcessSocketCommand(ByVal sender As Object, ByVal args As
EventArgs)
Dim strMessage As String
Dim dataArray() As String
'sound.PlaySync() 'sync playing

streamRead = _notifyData

Try
' remove message terminator
streamRead.SetLength((streamRead.Length -
Network.Terminator.Length))
'En van de bytecounter ook de terminatorlengte afhalen
MyByteCounter -= Network.Terminator.Length

' get the command data
streamRead.Position = 0
Dim data As Byte() = streamRead.ToArray()

' Convert the byte array the message was saved into, minus
one for the
' Chr(13).

strMessage = System.Text.Encoding.ASCII.GetString(data, 0,
MyByteCounter)

'Maak streamreader leeg
streamRead.SetLength(0)
MyByteCounter = 0

Catch ex As Exception
MsgBox(ex.ToString)
End Try

Try

'Message parts are divided by "|" Break the string into an array
accordingly.
dataArray = strMessage.Split(Chr(124))

' dataArray(0) is the command.
Log(dataArray(0), LogWriter)
Select Case dataArray(0)
Case "JOIN"
' Server acknowledged login.
DisplayText("Connecting to server...")
Threading.Thread.Sleep(MySleep) 'hielp ook!
DisplayText("Fetching menu.")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.ready.wav"))
sound.Play() 'async playing
ClientConnected = True 'zet vlag connection is ok!
taborder.BackColor =
System.Drawing.Color.LightSteelBlue
'Nieuwe order aanmaken
Call NewOrder()
Case "QUIT"
DisplayText("Server's down, please try again
later")
taborder.BackColor = System.Drawing.Color.Red
ClientConnected = False 'zet vlag connection uit
treeMenu.Enabled = False
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
'client.Close()
Case "REFUSE" 'Er is al een user met dezelfde naam
Dim MyEmployee As String
MyEmployee = lblEmployee.Text
DisplayText("Employee already connected, select
another and reconnect!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.error.wav"))
sound.Play() 'async playing
taborder.BackColor = System.Drawing.Color.Red
Application.DoEvents()
treeMenu.Enabled = False
'client.Close() 'Close the client!
If MyEmployee = lblEmployee.Text Then
Me.Invoke(New EventHandler(AddressOf
ShowEmplyeeForm))
lblEmployee.Text =
Global.Settings.GetString(SettingKeys.Employee)
End If
Case "ORDERACCEPTED"
DisplayText("Order's processed on the server!")
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.blip.wav"))
sound.Play() 'async playing
MsgBox("Order's processed on the server!",
MsgBoxStyle.Information, "WifiOrder PDA")
Case "REQCATALOG"
WriteXMLOrder(dataArray(1), "\assortiment.xml")
treeMenu.Enabled = True
FillTreeView()
DisplayText("The server's ready to process your
order...")
Case "REQORDER"
WriteXMLOrderStatus(dataArray(1),
"\lopendeorders.xml")
Call CreateTableOrdersDS()
TabControl1.SelectedIndex = 1
Dim sound As New
CFSound([Assembly].GetExecutingAssembly().GetManifestResourceStream("WifiOrder.reminder.wav"))
sound.Play() 'async playing
Case Else
End Select
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
 
M

Mike Dole

Ok Paul thanks for your help.
I'm gonna follow your advice.

Kind regards,

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top