Issue with socket chat not being able to send full messages - vb.net

I am having a little issue with this socket chat, if I send little messages like "hello world" it works perfectly fine but if I try to send huge messages with about 10,000 characters it just crashes, i've been trying to fix this for the past 3 days with no luck, what should I be doing?
Server source:
Imports System.Text
Imports System.Net
Imports System.Net.Sockets
Enum Command
Login
'Log into the server
Logout
'Logout of the server
Message
'Send a text message to all the chat clients
List
'Get a list of users in the chat room from the server
Null
'No command
End Enum
Public Class Form1
'The ClientInfo structure holds the required information about every
'client connected to the server
Private Structure ClientInfo
Public socket As Socket
'Socket of the client
Public strName As String
'Name by which the user logged into the chat room
End Structure
'The collection of all clients logged into the room (an array of type ClientInfo)
Private clientList As ArrayList
'The main socket on which the server listens to the clients
Private serverSocket As Socket
Private byteData As Byte() = New Byte(1023) {}
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
clientList = New ArrayList()
'We are using TCP sockets
serverSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
'Assign the any IP of the machine and listen on port number 1000
Dim ipEndPoint As New IPEndPoint(IPAddress.Any, 2277)
'Bind and listen on the given address
serverSocket.Bind(ipEndPoint)
serverSocket.Listen(4)
'Accept the incoming clients
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
Catch ex As Exception
MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.[Error])
End Try
End Sub
Private Sub OnAccept(ar As IAsyncResult)
Try
Dim clientSocket As Socket = serverSocket.EndAccept(ar)
'Start listening for more clients
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
'Once the client connects then start receiving the commands from her
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), clientSocket)
Catch ex As Exception
MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.[Error])
End Try
End Sub
Private Sub OnReceive(ar As IAsyncResult)
Try
Dim clientSocket As Socket = DirectCast(ar.AsyncState, Socket)
clientSocket.EndReceive(ar)
'Transform the array of bytes received from the user into an
'intelligent form of object Data
Dim msgReceived As New Data(byteData)
'We will send this object in response the users request
Dim msgToSend As New Data()
Dim message As Byte()
'If the message is to login, logout, or simple text message
'then when send to others the type of the message remains the same
msgToSend.cmdCommand = msgReceived.cmdCommand
msgToSend.strName = msgReceived.strName
Select Case msgReceived.cmdCommand
Case Command.Login
'When a user logs in to the server then we add her to our
'list of clients
Dim clientInfo As New ClientInfo()
clientInfo.socket = clientSocket
clientInfo.strName = msgReceived.strName
clientList.Add(clientInfo)
'Set the text of the message that we will broadcast to all users
msgToSend.strMessage = "<<<" & msgReceived.strName & " has joined the room>>>"
Exit Select
Case Command.Logout
'When a user wants to log out of the server then we search for her
'in the list of clients and close the corresponding connection
Dim nIndex As Integer = 0
For Each client As ClientInfo In clientList
If client.socket Is clientSocket Then
clientList.RemoveAt(nIndex)
Exit For
End If
nIndex += 1
Next
clientSocket.Close()
msgToSend.strMessage = "<<<" & msgReceived.strName & " has left the room>>>"
Exit Select
Case Command.Message
'Set the text of the message that we will broadcast to all users
msgToSend.strMessage = msgReceived.strName & ": " & msgReceived.strMessage
Exit Select
Case Command.List
'Send the names of all users in the chat room to the new user
msgToSend.cmdCommand = Command.List
msgToSend.strName = Nothing
msgToSend.strMessage = Nothing
'Collect the names of the user in the chat room
For Each client As ClientInfo In clientList
'To keep things simple we use asterisk as the marker to separate the user names
msgToSend.strMessage += client.strName & "*"
Next
message = msgToSend.ToByte()
'Send the name of the users in the chat room
clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, New AsyncCallback(AddressOf OnSend), clientSocket)
Exit Select
End Select
If msgToSend.cmdCommand <> Command.List Then
'List messages are not broadcasted
message = msgToSend.ToByte()
For Each clientInfo As ClientInfo In clientList
If clientInfo.socket IsNot clientSocket OrElse msgToSend.cmdCommand <> Command.Login Then
'Send the message to all users
clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None, New AsyncCallback(AddressOf OnSend), clientInfo.socket)
End If
Next
Debug.Print(msgToSend.strMessage)
End If
'If the user is logging out then we need not listen from her
If msgReceived.cmdCommand <> Command.Logout Then
'Start listening to the message send by the user
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, New AsyncCallback(AddressOf OnReceive), clientSocket)
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.[Error])
End Try
End Sub
Public Sub OnSend(ar As IAsyncResult)
Try
Dim client As Socket = DirectCast(ar.AsyncState, Socket)
client.EndSend(ar)
Catch ex As Exception
MessageBox.Show(ex.Message, "SGSserverTCP", MessageBoxButtons.OK, MessageBoxIcon.[Error])
End Try
End Sub
End Class
'The data structure by which the server and the client interact with
'each other
Class Data
Public strName As String
'Name by which the client logs into the room
Public strMessage As String
'Message text
Public cmdCommand As Command
'Command type (login, logout, send message, etcetera)
'Default constructor
Public Sub New()
cmdCommand = Command.Null
strMessage = Nothing
strName = Nothing
End Sub
'Converts the bytes into an object of type Data
Public Sub New(data__1 As Byte())
'The first four bytes are for the Command
cmdCommand = CType(BitConverter.ToInt32(data__1, 0), Command)
'The next four store the length of the name
Dim nameLen As Integer = BitConverter.ToInt32(data__1, 4)
'The next four store the length of the message
Dim msgLen As Integer = BitConverter.ToInt32(data__1, 8)
'This check makes sure that strName has been passed in the array of bytes
If nameLen > 0 Then
Me.strName = Encoding.UTF8.GetString(data__1, 12, nameLen)
Else
Me.strName = Nothing
End If
'This checks for a null message field
If msgLen > 0 Then
Me.strMessage = Encoding.UTF8.GetString(data__1, 12 + nameLen, msgLen)
Else
Me.strMessage = Nothing
End If
End Sub
'Converts the Data structure into an array of bytes
Public Function ToByte() As Byte()
Dim result As New List(Of Byte)()
'First four are for the Command
result.AddRange(BitConverter.GetBytes(CInt(cmdCommand)))
'Add the length of the name
If strName IsNot Nothing Then
result.AddRange(BitConverter.GetBytes(strName.Length))
Else
result.AddRange(BitConverter.GetBytes(0))
End If
'Length of the message
If strMessage IsNot Nothing Then
result.AddRange(BitConverter.GetBytes(strMessage.Length))
Else
result.AddRange(BitConverter.GetBytes(0))
End If
'Add the name
If strName IsNot Nothing Then
result.AddRange(Encoding.UTF8.GetBytes(strName))
End If
'And, lastly we add the message text to our array of bytes
If strMessage IsNot Nothing Then
result.AddRange(Encoding.UTF8.GetBytes(strMessage))
End If
Return result.ToArray()
End Function
End Class
Client source:
Enum Command
Login '0 Log into the server
Logout '1 Logout of the server
Message '2 Send a text message to all the chat clients
List '3 Get a list of users in the chat room from the server
Null '4 No command
End Enum
Public Class frmMain
Public clientSocket As System.Net.Sockets.Socket
'The main client socket
Public strName As String
'Name by which the user logs into the room
Private byteData As Byte() = New Byte(1023) {}
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call StartChat()
End Sub
Private Sub StartChat()
clientSocket = New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)
Dim ipAddress As System.Net.IPAddress = System.Net.IPAddress.Parse("127.0.0.1")
Dim ipEndPoint As New System.Net.IPEndPoint(ipAddress, 2277)
clientSocket.BeginConnect(ipEndPoint, New AsyncCallback(AddressOf OnLoginConnect), Nothing)
End Sub
Private Sub OnLoginConnect(ar As IAsyncResult)
clientSocket.EndConnect(ar)
'We are connected so we login into the server
Dim msgToSend As New Data()
msgToSend.cmdCommand = Command.Login
msgToSend.strName = txtUser.Text
msgToSend.strMessage = Nothing
Dim b As Byte() = msgToSend.ToByte()
'Send the message to the server
clientSocket.BeginSend(b, 0, b.Length, System.Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnLoginSend), Nothing)
End Sub
Private Sub OnLoginSend(ar As IAsyncResult)
clientSocket.EndSend(ar)
strName = txtUser.Text
Call LoggedIn()
End Sub
'***************
Private Sub LoggedIn()
'The user has logged into the system so we now request the server to send
'the names of all users who are in the chat room
Dim msgToSend As New Data()
msgToSend.cmdCommand = Command.List
msgToSend.strName = strName
msgToSend.strMessage = Nothing
byteData = msgToSend.ToByte()
clientSocket.BeginSend(byteData, 0, byteData.Length, System.Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnSend), Nothing)
byteData = New Byte(1023) {}
'Start listening to the data asynchronously
clientSocket.BeginReceive(byteData, 0, byteData.Length, System.Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnReceive), Nothing)
End Sub
'Broadcast the message typed by the user to everyone
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
'Fill the info for the message to be send
Dim msgToSend As New Data()
'.ToString("M/d/yyyy h:mm:ss tt")
msgToSend.strName = "[" & Date.Now.ToString("h:mm:ss tt") & "] <" & strName & ">"
msgToSend.strMessage = txtMessage.Text
msgToSend.cmdCommand = Command.Message
Dim byteData As Byte() = msgToSend.ToByte()
'Send it to the server
clientSocket.BeginSend(byteData, 0, byteData.Length, System.Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnSend), Nothing)
txtMessage.Text = Nothing
End Sub
Private Sub OnSend(ar As IAsyncResult)
clientSocket.EndSend(ar)
End Sub
Private Sub OnReceive(ar As IAsyncResult)
'clientSocket.EndReceive(ar)
Dim bytesReceived As Long = clientSocket.EndReceive(ar)
If (bytesReceived > 0) Then
Me.Invoke(New iThreadSafe(AddressOf iThreadSafeFinish), New Object() {byteData})
End If
byteData = New Byte(1023) {}
clientSocket.BeginReceive(byteData, 0, byteData.Length, System.Net.Sockets.SocketFlags.None, New AsyncCallback(AddressOf OnReceive), Nothing)
End Sub
Private Delegate Sub iThreadSafe(ByVal ibyteData As Byte())
Private Sub iThreadSafeFinish(ByVal ibyteData As Byte())
Dim msgReceived As New Data(ibyteData)
'Accordingly process the message received
Debug.Print(msgReceived.cmdCommand)
Select Case msgReceived.cmdCommand
Case 0 'login
lstChatters.Items.Add(msgReceived.strName)
Exit Select
Case 1 'log out
lstChatters.Items.Remove(msgReceived.strName)
Exit Select
Case 2 'msg
Exit Select
Case 3 'List
lstChatters.Items.AddRange(msgReceived.strMessage.Split("*"c))
lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1)
txtChatBox.Text += "<<<" & strName & " has joined the room>>>" & vbCr & vbLf
Exit Select
End Select
If msgReceived.strMessage IsNot Nothing AndAlso msgReceived.cmdCommand <> Command.List Then
txtChatBox.Text += msgReceived.strMessage & vbCr & vbLf
End If
End Sub
Private Sub txtMessage_TextChanged(sender As Object, e As KeyEventArgs) Handles txtMessage.KeyDown
If e.KeyCode = Keys.Enter Then
btnSend_Click(sender, Nothing)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
strName = txtUser.Text
End Sub
End Class
'The data structure by which the server and the client interact with
'each other
Class Data
Public strName As String
'Name by which the client logs into the room
Public strMessage As String
'Message text
Public cmdCommand As Command
'Command type (login, logout, send message, etcetera)
'Default constructor
Public Sub New()
cmdCommand = Command.Null
strMessage = Nothing
strName = Nothing
End Sub
'Converts the bytes into an object of type Data
Public Sub New(data__1 As Byte())
'The first four bytes are for the Command
cmdCommand = CType(BitConverter.ToInt32(data__1, 0), Command)
'The next four store the length of the name
Dim nameLen As Integer = BitConverter.ToInt32(data__1, 4)
'The next four store the length of the message
Dim msgLen As Integer = BitConverter.ToInt32(data__1, 8)
'This check makes sure that strName has been passed in the array of bytes
If nameLen > 0 Then
strName = System.Text.Encoding.UTF8.GetString(data__1, 12, nameLen)
Else
strName = Nothing
End If
'This checks for a null message field
If msgLen > 0 Then
strMessage = System.Text.Encoding.UTF8.GetString(data__1, 12 + nameLen, msgLen)
Else
strMessage = Nothing
End If
End Sub
'Converts the Data structure into an array of bytes
Public Function ToByte() As Byte()
Dim result As New List(Of Byte)()
'First four are for the Command
result.AddRange(BitConverter.GetBytes(CInt(cmdCommand)))
'Add the length of the name
If strName IsNot Nothing Then
result.AddRange(BitConverter.GetBytes(strName.Length))
Else
result.AddRange(BitConverter.GetBytes(0))
End If
'Length of the message
If strMessage IsNot Nothing Then
result.AddRange(BitConverter.GetBytes(strMessage.Length))
Else
result.AddRange(BitConverter.GetBytes(0))
End If
'Add the name
If strName IsNot Nothing Then
result.AddRange(System.Text.Encoding.UTF8.GetBytes(strName))
End If
'And, lastly we add the message text to our array of bytes
If strMessage IsNot Nothing Then
result.AddRange(System.Text.Encoding.UTF8.GetBytes(strMessage))
End If
Return result.ToArray()
End Function
End Class

You are assuming that you will receive an entire message at a time. TCP does not guarantee to preserve the chunks that you wrote. Use the return value bytesReceived to determine how many bytes are actually in the buffer.
Your code must be able to deal with the possibility of receiving all outstanding data one byte at a time.

Related

How to get ipv4 addresses of all computers on a network in VB.NET

I have a Windows Forms app in Visual basic that is currently sending messages back and forth between two computers. Currently, the user has to manually enter the ipv4 address of the receiver of the message. what I would like to do is put the ipv4 addresses of all the computers on the network into a combo box so the user has a list to pick from.
I have searched a whole bunch of different forums and am unable to find a working solution.
Public Class Form1
Dim strHostName As String
Dim strIPAddress As String
Dim running As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
strHostName = System.Net.Dns.GetHostName()
strIPAddress = System.Net.Dns.GetHostByName(strHostName).AddressList(0).ToString()
Me.Text = strIPAddress
txtIP.Text = strIPAddress
running = True
'run listener on separate thread
Dim listenTrd As Thread
listenTrd = New Thread(AddressOf StartServer)
listenTrd.IsBackground = True
listenTrd.Start()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As EventArgs) Handles MyBase.FormClosing
running = False
End Sub
Sub StartServer()
Dim serverSocket As New TcpListener(CInt(txtPort.Text))
Dim requestCount As Integer
Dim clientSocket As TcpClient
Dim messageReceived As Boolean = False
While running
messageReceived = False
serverSocket.Start()
msg("Server Started")
clientSocket = serverSocket.AcceptTcpClient()
msg("Accept connection from client")
requestCount = 0
While (Not (messageReceived))
Try
requestCount = requestCount + 1
Dim networkStream As NetworkStream = clientSocket.GetStream()
Dim bytesFrom(10024) As Byte
networkStream.Read(bytesFrom, 0, bytesFrom.Length)
Dim dataFromClient As String = System.Text.Encoding.ASCII.GetString(bytesFrom)
dataFromClient = dataFromClient.Substring(0, dataFromClient.Length)
'invoke into other thread
txtOut.Invoke(Sub()
txtOut.Text += dataFromClient
txtOut.Text += vbNewLine
End Sub)
messageReceived = True
Dim serverResponse As String = "Server response " + Convert.ToString(requestCount)
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(serverResponse)
networkStream.Write(sendBytes, 0, sendBytes.Length)
networkStream.Flush()
Catch ex As Exception
End
End Try
End While
clientSocket.Close()
serverSocket.Stop()
msg("exit")
Console.ReadLine()
End While
End Sub
Sub msg(ByVal mesg As String)
mesg.Trim()
Console.WriteLine(" >> " + mesg)
End Sub
Public Sub WriteData(ByVal data As String, ByRef IP As String)
Try
txtOut.Text += data.PadRight(1)
txtOut.Text += vbNewLine
txtMsg.Clear()
Console.WriteLine("Sending message """ & data & """ to " & IP)
Dim client As TcpClient = New TcpClient()
client.Connect(New IPEndPoint(IPAddress.Parse(IP), CInt(txtPort.Text)))
Dim stream As NetworkStream = client.GetStream()
Dim sendBytes As Byte() = Encoding.ASCII.GetBytes(data)
stream.Write(sendBytes, 0, sendBytes.Length)
Catch ex As Exception
msg(ex.ToString)
End Try
End Sub
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
If Not (txtMsg.Text = vbNullString) AndAlso Not (txtIP.Text = vbNullString) Then
WriteData(txtMsg.Text, txtIP.Text)
End If
End Sub
Private Sub txtMsg_KeyDown(sender As Object, e As KeyEventArgs) Handles txtMsg.KeyDown
If e.KeyCode = Keys.Enter Then
If Not (txtMsg.Text = vbNullString) AndAlso Not (txtIP.Text = vbNullString) Then
WriteData(txtMsg.Text, txtIP.Text)
End If
End If
End Sub
Private Sub BtnFind_Click(sender As Object, e As EventArgs) Handles btnFind.Click
'find all local addresses and put in combobox (button will be removed later)
End Sub
End Class
For PC names "as you suggested in your comments", I used this at work to get pc names i was on domain, try it:
AFAIK it works on domains...
Make sure you have a listbox on your form, or change listbox and populate in your combobox directly, play with that as you like :)
Private Delegate Sub UpdateDelegate(ByVal s As String)
Dim t As New Threading.Thread(AddressOf GetNetworkComputers)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
t.IsBackground = True
t.Start()
End Sub
Private Sub AddListBoxItem(ByVal s As String)
ListBox1.Items.Add(s)
End Sub
Private Sub GetNetworkComputers()
Try
Dim alWorkGroups As New ArrayList
Dim de As New DirectoryEntry
de.Path = "WinNT:"
For Each d As DirectoryEntry In de.Children
If d.SchemaClassName = "Domain" Then alWorkGroups.Add(d.Name)
d.Dispose()
Next
For Each workgroup As String In alWorkGroups
de.Path = "WinNT://" & workgroup
For Each d As DirectoryEntry In de.Children
If d.SchemaClassName = "Computer" Then
Dim del As UpdateDelegate = AddressOf AddListBoxItem
Me.Invoke(del, d.Name)
End If
d.Dispose()
Next
Next
Catch ex As Exception
'MsgBox(Ex.Message)
End Try
End Sub
POC:

Sending an receiving two types of data across TCP connection

On the Client I want to -
I want to send a screenimage from the client and receive a string with cursor coordinates in.
On the server I want to receive and display the screenimage on Form2
and then send back my cursor coordinates to the client.
I can successfully send text messages from the client and receive them on the server using this code -
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
senddata("CHAT|" & TextBox3.Text) 'send the data with CHAT| as header
TextBox4.Text &= "You: " & " " & TextBox3.Text.Split("|")(0) & vbNewLine
End Sub
Sub senddata(ByVal message As String)
Dim sw As New StreamWriter(t.GetStream) 'declare a new streamwriter
sw.WriteLine(message) 'write the message
sw.Flush()
End Sub
and receive it on the server with this code -
Imports System.IO
Imports System.Net.Sockets
Public Class ConnectedClient
Private cli As TcpClient 'decleare a tcp client which will be the client that we assign to an instance of this class
Private uniqueid As String 'this will be used for the name property
Public Property name ''This will be the name of the ID containing its Unique ID
Get
Return uniqueid 'when we want to get it, it will return the Unique ID
End Get
Set(ByVal value)
uniqueid = value 'Used for setting the name
End Set
End Property
Sub New(ByVal client As TcpClient)
Dim r As New Random 'create a new random to serve as way to create our unique ID
Dim x As String = String.Empty 'declare a new variable to hold the ID
For i = 0 To 7 'we are goign to have an ID of 7 randomly generated characters
x &= Chr(r.Next(65, 89)) 'create a generate dnumber between 65 and 89 and get the letter that has the same ascii value (A-Z)
' and add it onto the ID string
Next
Me.name = client.Client.RemoteEndPoint.ToString().Remove(client.Client.RemoteEndPoint.ToString().LastIndexOf(":")) & " - " & x 'set the name to the Unique ID
cli = client 'assign the client specified to the TCP client variable to we can operate with it
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'start reading using the read subroutine
End Sub
Public Event gotmessage(ByVal message As String, ByVal client As ConnectedClient) 'this is raised when we get a message from the client
Public Event disconnected(ByVal client As ConnectedClient) 'this is raised when we get the client disconnects
Sub read(ByVal ar As IAsyncResult) 'this will process all messages being recieved
Try
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ex As Exception
Try 'if an error occurs in the reading purpose, we will try to read again to see if we still can read
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ' IF WE STILL CANNOT READ
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
End Try
End Try
End Sub
Sub senddata(ByVal message As String) 'this is used to deal with sending out messages
Dim sw As New StreamWriter(cli.GetStream) 'declare a new streamwrite to write to the stream between the client and the server
sw.WriteLine(message) 'write the message to the stream
sw.Flush()
End Sub
Sub listen(ByVal port As Integer)
Try
Dim t As New TcpListener(IPAddress.Any, port) 'declare a new tcplistener
t.Start() 'start the listener
Do
Dim client As New ConnectedClient(t.AcceptTcpClient) 'initialize a new connected client
AddHandler client.gotmessage, AddressOf recieved 'add the handler which will raise an event when a message is recieved
AddHandler client.disconnected, AddressOf disconnected 'add the handler which will raise an event when the client disconnects
Loop Until False
Catch
End Try
End Sub
In a totally different application I can successfully send the screen image from the client using this code
Imports System.Net.Sockets
Imports System.Threading
Imports System.Drawing
Imports System.Runtime.Serialization.Formatters.Binary
Public Class Form1
Dim client As New TcpClient
Dim ns As NetworkStream
Dim port As Integer
Dim server As TcpListener
Dim listening As New Thread(AddressOf Listen)
Dim GetImage As New Thread(AddressOf ReceiveCursor)
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles btnConnect.Click
port = CInt(txtPort.Text)
Try
If btnConnect.Text = "Connect" Then
client.Connect(txtIP.Text, port)
'MsgBox("Client connected !")
Timer1.Start()
btnConnect.Text = "Disconnect"
Else
btnConnect.Text = "Connect"
Timer1.Stop()
End If
Catch ex As Exception
MsgBox("Failed to connect..." + ex.Message)
End Try
End Sub
Public Function Desktop() As Image
Dim bounds As Rectangle = Nothing
Dim screenshot As System.Drawing.Bitmap = Nothing
Dim graph As Graphics = Nothing
bounds = Screen.PrimaryScreen.Bounds
screenshot = New Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
Return screenshot
End Function
Private Sub SendDesktop()
Dim bf As New BinaryFormatter
ns = client.GetStream
bf.Serialize(ns, Desktop())
End Sub
Private Sub BtnShare_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShare.Click
If btnShare.Text.StartsWith("Share") Then
Timer1.Start()
'port = Integer.Parse(Me.txtPort.Text)
'server = New TcpListener(port)
'listening.Start()
btnShare.Text = "Stop Sharing"
Else
Timer1.Stop()
btnShare.Text = "Share Desktop"
End If
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
SendDesktop()
' SetCursorPosition()
End Sub
Private Sub ReceiveCursor()
Dim bf As New BinaryFormatter
While client.Connected = True
ns = client.GetStream
txtCursorPosition.Text = bf.Deserialize(ns)
End While
End Sub
Private Sub Listen()
While client.Connected = False
server.Start()
client = server.AcceptTcpClient
End While
GetImage.Start()
End Sub
Public Sub StopListening()
GetImage.Abort()
server.Stop()
client = Nothing
If listening.IsAlive Then
listening.Abort()
End If
End Sub
End Class
and receive it on the server using this code -
Imports System.Net.Sockets
Imports System.Threading
Imports System.Drawing
Imports System.Runtime.Serialization.Formatters.Binary
Public Class Form2
Dim port As Integer
Dim client As New TcpClient
Dim ns As NetworkStream
Dim server As TcpListener
Dim listening As New Thread(AddressOf Listen)
Dim GetImage As New Thread(AddressOf ReceiveImage)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Start the timer, obtain the port and start listening
Timer1.Start()
port = Integer.Parse(Form1.txtPort.Text)
server = New TcpListener(port)
listening.Start()
End Sub
Private Sub ReceiveImage()
Dim bf As New BinaryFormatter
While client.Connected = True
ns = client.GetStream
PictureBox1.Image = bf.Deserialize(ns)
End While
End Sub
Private Sub Listen()
While client.Connected = False
server.Start()
client = server.AcceptTcpClient
End While
GetImage.Start()
End Sub
Public Sub StopListening()
GetImage.Abort()
server.Stop()
client = Nothing
If listening.IsAlive Then
listening.Abort()
End If
End Sub
End Class
Is there a way of doing both using the same connection and somehow detecting which is text and which is the screenimage?

Simultaneously receive message from clients using sockets (with Async)

i have a CyberCafe Software Program with a code that sends a message by the client(socket) and received by the server(also a socket) using Network Stream. (i'm somewhat new about sockets and network stream)
Server Side:
'receive msg from client
Private Sub OnRecieve(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
ns.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf OnRecieve), ns)
Dim bytesRec As Byte() = byteData
Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytesRec)
Invoke(New _Read(AddressOf Read), message)
ns.Flush()
ns.Close()
Catch ex As Exception
'check for Disconnection or Force Disconnection
Invoke(New _dc(AddressOf dc))
End Try
End Sub
Client Side:
'send msg to server
Private Sub Send(ByVal msg As String, ByVal client As Socket)
Try
Dim sendBytes As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(msg)
NetStream = New NetworkStream(client)
NetStream.BeginWrite(sendBytes, 0, sendBytes.Length, New AsyncCallback(AddressOf OnSend), NetStream)
Catch ex As Exception
If Not clientSocket.Connected Then 'if connection was forcibly disconnected
'reconnecting to the server
Invoke(New _status(AddressOf status), clientSocket)
Connect()
End If
End Try
End Sub
The scenario is, there are 2 clients waiting to connect to the server(the other one is a Virtual Machine), and when i finally run the server, simultaneous connection had no problems, but receiving a message simultaneously didn't worked out. Sometimes it received one message only. Sometimes the message is wrong. Maybe a deadlock.
So, how can i implement this kind of situation? i asked Brother Google :P and he told me about AsyncTask, but i dunno how to do it :(
Any help would be obliged ^_^ Apologies for any bad english.
Update:
Sorry for my incomplete question.
I've added the EndRead/EndWrite method, but i'm not sure if i used the EndRead method right... I just inserted the EndRead before the BeginRead, but it still works though.
Thank you for the help Visual Vincent ^_^.
Also, my sockets are stored in the ListView as tag after they connect. And their IPAddress and HostName are stored in the database (MSAccess). And i don't have any TCP used in this code. Just Sockets and NetworkStreams. IDK if that is ok, but it works.
Server Side(Full):
Imports System.Net, System.Net.Sockets
Imports System.Data.OleDb
Public Class Server
Dim serverSocket As Socket
Dim clientSocket As Socket
Dim netstream As NetworkStream
Dim byteData(1023) As Byte
Dim ipEndPoint As IPEndPoint
Dim myList As New List(Of String)
Dim myList2 As New List(Of String)
Dim txt As String
'listening to clients from port 8800
Private Sub frmServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Invoke(New _AddExistingClient(AddressOf AddExistingClient))
Listen()
End Sub
Delegate Sub _AddExistingClient()
Private Sub AddExistingClient()
Try
If conn.State = ConnectionState.Open Then conn.Close()
conn.Open()
query = "select * from Clients_tbl"
comm = New OleDbCommand(query, conn)
reader = comm.ExecuteReader
While reader.Read
Dim lvi As New ListViewItem(reader("HostName").ToString)
lvi.Text = reader("HostName")
lvi.SubItems.Add("P00.00") 'price 1
lvi.SubItems.Add("00:00:00") 'time 2
lvi.ImageKey = "Grey.ico"
lsvClients.Items.Add(lvi)
End While
lsvClients.Sort()
conn.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub Listen()
Try
serverSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
ipEndPoint = New IPEndPoint(IPAddress.Any, 8800)
serverSocket.Bind(ipEndPoint)
serverSocket.Listen(1)
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub OnAccept(ByVal ar As IAsyncResult)
Try
clientSocket = serverSocket.EndAccept(ar)
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
CheckIfExist(clientSocket)
netstream = New NetworkStream(clientSocket)
netstream.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf OnRecieve), netstream)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _CheckIfExist(ByVal client As Socket)
Private Sub CheckIfExist(ByVal client As Socket)
Try
If InvokeRequired Then
Invoke(New _CheckIfExist(AddressOf CheckIfExist), client)
Exit Sub
End If
Dim RemoteIP As String = IPAddress.Parse(CType(client.RemoteEndPoint, IPEndPoint).Address.ToString).ToString
Dim host As String = Dns.GetHostEntry(RemoteIP).HostName.ToString
If conn.State = ConnectionState.Open Then conn.Close()
conn.Open()
query = "select * from Clients_tbl where HostName = '" + host + "'"
comm = New OleDbCommand(query, conn)
reader = comm.ExecuteReader
While reader.Read
If reader("IPAddress").ToString <> RemoteIP Then 'if socket do exist in the database but IPAddress was changed
ChangeIP(RemoteIP, host)
End If
count += 1
End While
If count = 0 Then 'if socket do not exist in the database
Add2DB(RemoteIP, host)
AddNewClient(client)
ElseIf count = 1 Then 'if socket do exist in the database and in the listview
For Each item As ListViewItem In lsvClients.Items
If item.Text = host Then
item.Tag = client
item.ImageKey = "Red.ico"
End If
Next
ElseIf count > 1 Then
MsgBox("Duplicate found")
End If
count = 0
conn.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _ChangeIP(ByVal RemoteIP As String, ByVal host As String)
Private Sub ChangeIP(ByVal RemoteIP As String, ByVal host As String) 'connection is still opened
Try
If InvokeRequired Then
Invoke(New _ChangeIP(AddressOf ChangeIP), RemoteIP, host)
Exit Sub
End If
query = "update Clients_tbl set IPAddress = '" + RemoteIP + "' where HostName = '" + host + "'"
comm = New OleDbCommand(query, conn)
reader = comm.ExecuteReader
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _Add2DB(ByVal RemoteIP As String, ByVal host As String)
Private Sub Add2DB(ByVal RemoteIP As String, ByVal host As String) 'connection is still opened
Try
If InvokeRequired Then
Invoke(New _Add2DB(AddressOf Add2DB), RemoteIP, host)
Exit Sub
End If
query = "insert into Clients_tbl values('" + RemoteIP + "', '" + host + "')"
comm = New OleDbCommand(query, conn)
reader = comm.ExecuteReader
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
'add client to ListView
Delegate Sub _AddNewClient(ByVal client As Socket)
Private Sub AddNewClient(ByVal client As Socket)
Try
If InvokeRequired Then
Invoke(New _AddNewClient(AddressOf AddNewClient), client)
Exit Sub
End If
Dim lvi As New ListViewItem(client.LocalEndPoint.ToString)
Dim RemoteIP As String = IPAddress.Parse(CType(client.RemoteEndPoint, IPEndPoint).Address.ToString).ToString
Dim host As String = Dns.GetHostEntry(RemoteIP).HostName.ToString
lvi.Text = host
lvi.Tag = client
lvi.SubItems.Add("P00.00") 'price 1
lvi.SubItems.Add("00:00:00") 'time 2
lvi.ImageKey = "Red.ico"
lsvClients.Items.Add(lvi)
lsvClients.Sort()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
'Send msg to specific client
Private Sub Send(ByVal msg As String, ByVal client As Socket)
Try
netstream = New NetworkStream(client)
Dim sendBytes As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(msg)
netstream.BeginWrite(sendBytes, 0, sendBytes.Length, New AsyncCallback(AddressOf OnSend), netstream)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub OnSend(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
ns.EndWrite(ar)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _dc()
Private Sub dc()
For Each lvi As ListViewItem In lsvClients.Items
If Not lvi.Tag Is Nothing Then
Dim S As Socket = lvi.Tag
If Not S.Connected Then lvi.ImageKey = "Grey.ico"
End If
Next
End Sub
'receive msg from client
Private Sub OnRecieve(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
ns.EndRead(ar)
ns.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf OnRecieve), ns)
Dim bytesRec As Byte() = byteData
Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytesRec)
Invoke(New _Read(AddressOf Read), message)
ns.Flush()
ns.Close()
Catch ex As Exception
'check for Disconnection or Force Disconnection
Invoke(New _dc(AddressOf dc))
End Try
End Sub
Delegate Sub _Read(ByVal msg As String)
Private Sub Read(ByVal msg As String)
Try
myList2 = msg.Split("~").ToList
'mylist.Add("0") 'command number
'mylist.Add(host) 'host name of this client
'mylist.Add(lblState.Text)
'mylist.Add(lblTime.Tag.ToString)
Select Case Integer.Parse(myList2(0))
Case 0
For Each lvi As ListViewItem In lsvClients.Items
If lvi.Text = myList2(1) Then
If myList2(2) = "Timed" Then
lvi.ImageKey = "Green.ico"
ElseIf myList2(2) = "Open"
lvi.ImageKey = "Blue.ico"
End If
lvi.SubItems(2).Tag = Integer.Parse(myList2(3))
End If
Next
End Select
myList2.Clear()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
Invoke(New _Counter(AddressOf Counter))
End Sub
Delegate Sub _Counter()
Private Sub Counter()
Try
If lsvClients.Items.Count > 0 Then
For Each time As ListViewItem In lsvClients.Items
'//////////////
If time.ImageKey = "Green.ico" Then
time.SubItems(2).Tag -= 1
time.SubItems(2).Text = GetTime(time.SubItems(2).Tag)
If time.SubItems(2).Tag = 0 Then time.ImageKey = "Red.ico"
ElseIf time.ImageKey = "Blue.ico" Then
time.SubItems(2).Tag += 1
time.SubItems(2).Text = GetTime(time.SubItems(2).Tag)
End If
'//////////////
Next
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Function GetTime(ByVal time As Integer) As String
Dim Hrs As Integer 'number of hours '
Dim Min As Integer 'number of Minutes '
Dim Sec As Integer 'number of Sec '
'Seconds'
Sec = time Mod 60
'Minutes'
Min = ((time - Sec) / 60) Mod 60
'Hours'
Hrs = ((time - (Sec + (Min * 60))) / 3600) Mod 60
Return Format(Hrs, "00") & ":" & Format(Min, "00") & ":" & Format(Sec, "00")
End Function
Private Sub btnStartTime_Click(sender As Object, e As EventArgs) Handles btnStartTime.Click
Try
If lsvClients.SelectedItems.Count <> 0 Then
myList.Add("0")
myList.Add("10") 'time
myList.Add("15") 'price
txt = String.Join("~", myList)
Send(txt, lsvClients.SelectedItems(0).Tag)
lsvClients.SelectedItems(0).SubItems(2).Tag = myList(1)
lsvClients.SelectedItems(0).ImageKey = "Green.ico"
myList.Clear()
Else
MsgBox("Select first")
End If
Catch ex As Exception
Dim client As Socket = lsvClients.SelectedItems(0).Tag
If Not client.Connected Then
MsgBox("Disconnected")
End If
End Try
End Sub
Private Sub btnOpenTime_Click(sender As Object, e As EventArgs) Handles btnOpenTime.Click
Try
If lsvClients.SelectedItems.Count <> 0 Then
myList.Add("2")
myList.Add("0") 'time
myList.Add("0") 'price
txt = String.Join("~", myList)
Send(txt, lsvClients.SelectedItems(0).Tag)
lsvClients.SelectedItems(0).SubItems(2).Tag = myList(1)
lsvClients.SelectedItems(0).ImageKey = "Blue.ico"
myList.Clear()
Else
MsgBox("Select first")
End If
Catch ex As Exception
Dim client As Socket = lsvClients.SelectedItems(0).Tag
If Not client.Connected Then
MsgBox("Disconnected")
End If
End Try
End Sub
Private Sub btnExtendTime_Click(sender As Object, e As EventArgs) Handles btnExtendTime.Click
Try
If lsvClients.SelectedItems.Count <> 0 Then
myList.Add("1")
myList.Add("10") 'time
myList.Add("15") 'price
txt = String.Join("~", myList)
Send(txt, lsvClients.SelectedItems(0).Tag)
lsvClients.SelectedItems(0).SubItems(2).Tag += myList(1)
lsvClients.SelectedItems(0).ImageKey = "Green.ico"
myList.Clear()
Else
MsgBox("Select first")
End If
Catch ex As Exception
Dim client As Socket = lsvClients.SelectedItems(0).Tag
If Not client.Connected Then
MsgBox("Disconnected")
End If
End Try
End Sub
Private Sub btnPauseTime_Click(sender As Object, e As EventArgs) Handles btnPauseTime.Click
Try
If lsvClients.SelectedItems.Count <> 0 Then
myList.Add("3")
myList.Add("00:00:00") 'time
myList.Add("0") 'price
txt = String.Join("~", myList)
Send(txt, lsvClients.SelectedItems(0).Tag)
If lsvClients.SelectedItems(0).ImageKey = "Green.ico" Then
lsvClients.SelectedItems(0).ImageKey = "Green2Yellow.ico"
ElseIf lsvClients.SelectedItems(0).ImageKey = "Blue.ico"
lsvClients.SelectedItems(0).ImageKey = "Blue2Yellow.ico"
End If
myList.Clear()
Else
MsgBox("Select first")
End If
Catch ex As Exception
Dim client As Socket = lsvClients.SelectedItems(0).Tag
If Not client.Connected Then
MsgBox("Disconnected")
End If
End Try
End Sub
Private Sub btnResumeTime_Click(sender As Object, e As EventArgs) Handles btnResumeTime.Click
Try
If lsvClients.SelectedItems.Count <> 0 Then
myList.Add("4")
myList.Add("00:00:00") 'time
myList.Add("0") 'price
txt = String.Join("~", myList)
Send(txt, lsvClients.SelectedItems(0).Tag)
If lsvClients.SelectedItems(0).ImageKey = "Green2Yellow.ico" Then
lsvClients.SelectedItems(0).ImageKey = "Green.ico"
ElseIf lsvClients.SelectedItems(0).ImageKey = "Blue2Yellow.ico"
lsvClients.SelectedItems(0).ImageKey = "Blue.ico"
End If
myList.Clear()
Else
MsgBox("Select first")
End If
Catch ex As Exception
Dim client As Socket = lsvClients.SelectedItems(0).Tag
If Not client.Connected Then
MsgBox("Disconnected")
End If
End Try
End Sub
End Class
Client Side(full):
Imports System.Net, System.Net.Sockets, System.IO
Public Class Client
Dim clientSocket As Socket
Dim NetStream As NetworkStream
Dim byteData(1023) As Byte
Dim ipEndpoint As IPEndPoint
Dim host As String = Dns.GetHostName
Dim ip As IPAddress = IPAddress.Parse("192.168.56.1") 'Dns.GetHostEntry(host).AddressList(0)
Dim AppPath As String = Application.StartupPath
Dim writer As StreamWriter
Dim reader As StreamReader
Dim mylist As New List(Of String)
Dim txt As String
'/////////////////////connecting to server at port 8800
Private Sub Client_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Try
Invoke(New _readtext(AddressOf readtext))
Connect()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub Connect()
Try
clientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
ipEndpoint = New IPEndPoint(ip, 8800)
clientSocket.BeginConnect(ipEndpoint, New AsyncCallback(AddressOf OnConnect), Nothing)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub OnConnect(ByVal ar As IAsyncResult)
Try
Invoke(New _status(AddressOf status), clientSocket)
clientSocket.EndConnect(ar)
'Invoke(New _SendTimeState(AddressOf SendTimeState))
NetStream = New NetworkStream(clientSocket)
NetStream.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf Recieve), NetStream)
'Invoke(New _SendTimeState(AddressOf SendTimeState))
Catch ex As Exception
If Not clientSocket.Connected Then
Invoke(New _status(AddressOf status), clientSocket)
Connect()
End If
End Try
End Sub
Delegate Sub _SendTimeState()
Private Sub SendTimeState()
Try
mylist.Add("0") 'command number
mylist.Add(host) 'host name of this client
mylist.Add(lblState.Text)
mylist.Add(lblTime.Tag.ToString)
txt = String.Join("~", mylist)
Send(txt, clientSocket)
txt = ""
mylist.Clear()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _readtext()
Private Sub readtext()
Try
reader = New StreamReader(AppPath & "\time.txt")
Dim x As Integer = reader.ReadLine
reader.Close()
If x <> 0 Then
lblTime.Tag = x
reader = New StreamReader(AppPath & "\state.txt")
Dim state As String = reader.ReadLine
reader.Close()
lblState.Text = state
Timer1.Start()
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _writetext(ByVal file As String, ByVal txt As String)
Private Sub writetext(ByVal file As String, ByVal txt As String)
Try
If InvokeRequired Then
Invoke(New _writetext(AddressOf writetext), file, txt)
Exit Sub
End If
writer = New StreamWriter(AppPath & file, False)
writer.WriteLine(txt)
writer.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Delegate Sub _status(ByVal client As Socket)
Private Sub status(ByVal client As Socket)
lblConnection.Text = client.Connected.ToString
End Sub
'receive msg from server
Private Sub Recieve(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
ns.EndRead(ar)
ns.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf Recieve), ns)
Dim bytesRec As Byte() = byteData
Dim message As String = System.Text.ASCIIEncoding.ASCII.GetString(bytesRec)
Invoke(New _Read(AddressOf Read), message)
Catch ex As Exception
If Not clientSocket.Connected Then 'if connection was forcibly disconnected
'reconnecting to the server
Invoke(New _status(AddressOf status), clientSocket)
Connect()
End If
End Try
End Sub
Delegate Sub _Read(ByVal msg As String)
Private Sub Read(ByVal msg As String)
Try
mylist = msg.Split("~").ToList
'mylist(0) is command
'mylist(1) is time
'mylist(2) price
Select Case Integer.Parse(mylist(0))
Case 0 'timed
lblState.Text = "Timed"
lblTime.Tag = Integer.Parse(mylist(1))
lblTime.Text = GetTime(lblTime.Tag)
lblPrice.Text = Integer.Parse(lblPrice.Text) + Integer.Parse(mylist(2))
lblState.Tag = lblState.Text
writetext("\time.txt", lblTime.Tag.ToString)
writetext("\state.txt", "Timed")
Timer1.Start()
Case 1 'extend time
lblTime.Tag += Integer.Parse(mylist(1))
lblTime.Text = GetTime(lblTime.Tag)
lblPrice.Text = Integer.Parse(lblPrice.Text) + Integer.Parse(mylist(2))
If Not Timer1.Enabled Then Timer1.Start()
Case 2 'open time
lblState.Text = "Open"
lblTime.Tag = Integer.Parse(mylist(1))
lblTime.Text = GetTime(lblTime.Tag)
lblPrice.Text = mylist(2)
lblState.Tag = lblState.Text
writetext("\time.txt", lblTime.Tag.ToString)
writetext("\state.txt", "Open")
Timer1.Start()
Case 3 'pause time
lblState.Text = "Paused"
Timer1.Stop()
Case 4 'resume time
lblState.Text = lblState.Tag
Timer1.Start()
Case 5 'stop time
lblState.Text = "Stop"
writetext("\time.txt", "0")
writetext("\state.txt", "Stop")
Timer1.Stop()
Case 6 'shutdown
Case 7 'reset
Case 8 'send msg
End Select
mylist.Clear()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
'send msg to server
Private Sub Send(ByVal msg As String, ByVal client As Socket)
Try
Dim sendBytes As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(msg)
NetStream = New NetworkStream(client)
NetStream.BeginWrite(sendBytes, 0, sendBytes.Length, New AsyncCallback(AddressOf OnSend), NetStream)
Catch ex As Exception
If Not clientSocket.Connected Then 'if connection was forcibly disconnected
'reconnecting to the server
Invoke(New _status(AddressOf status), clientSocket)
Connect()
End If
End Try
End Sub
Private Sub OnSend(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
ns.EndWrite(ar)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
Try
Select Case lblState.Text
Case "Timed"
lblTime.Tag -= 1
lblTime.Text = GetTime(lblTime.Tag)
writetext("\time.txt", lblTime.Tag.ToString)
If lblTime.Tag = 0 Then Timer1.Stop()
Case "Open"
lblTime.Tag += 1
lblTime.Text = GetTime(lblTime.Tag)
writetext("\time.txt", lblTime.Tag.ToString)
End Select
Catch ex As Exception
If Not clientSocket.Connected Then 'if connection was forcibly disconnected
'reconnecting to the server
Invoke(New _status(AddressOf status), clientSocket)
Connect()
End If
MsgBox(ex.ToString)
End Try
End Sub
Private Function GetTime(ByVal time As Integer) As String
Dim Hrs As Integer 'number of hours '
Dim Min As Integer 'number of Minutes '
Dim Sec As Integer 'number of Sec '
'Seconds'
Sec = time Mod 60
'Minutes'
Min = ((time - Sec) / 60) Mod 60
'Hours'
Hrs = ((time - (Sec + (Min * 60))) / 3600) Mod 60
Return Format(Hrs, "00") & ":" & Format(Min, "00") & ":" & Format(Sec, "00")
End Function
End Class
OleDb Module:
Imports System.Data.OleDb
Module oledb
Dim AppPath As String = Application.StartupPath
Public conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + AppPath + "\ServerDatabase.mdb;User Id=Admin;Password=")
Public comm As OleDbCommand
Public reader As OleDbDataReader
Public query As String
Public count As Integer
End Module
(Can't add this post on my first post because it reached it's max capacity :P)
Here's the slightly changed Received function:
'receive msg from client
Private Sub Recieve(ByVal ar As IAsyncResult)
Try
Dim ns As NetworkStream = CType(ar.AsyncState, NetworkStream)
Dim message As String = ""
ByteSize = ns.EndRead(ar)
message = String.Concat(message, System.Text.ASCIIEncoding.ASCII.GetString(byteData, 0, ByteSize))
ns.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf Recieve), ns)
'if there are still data left in the network stream
While ns.DataAvailable
ns.BeginRead(byteData, 0, byteData.Length, New AsyncCallback(AddressOf Recieve), ns)
End While
Invoke(New _Read(AddressOf Read), message)
Catch ex As Exception
'check for Disconnection or Force Disconnection
Invoke(New _dc(AddressOf dc))
End Try
End Sub
I saw on the MS Documentation about NetworkStream.EndRead that the EndRead comes first before BeginRead. Maybe it is only applicable on Read.
NetworkStream.EndRead Method (IAsyncResult)
But the problem still persist :(

Tcp Client/Server - Client messages issue

I have client and server application.
I have the client disconnect from the server with client.close via a disconnect button.
I send a message, shows on server. ok works great.
I disconnect and then reconnect. I send a message. It shows the message two times.
I disconnect another time then reconnect. I send a message. It then shows the message three times.
It is incrementing the message and sending it multiple times after the disconnect and then reconnect.
Help? Been trying to figure this out for a while
[SERVER]
Public Class Server
Dim Listener As TcpListener
Dim Client As TcpClient
Dim ListenerThread As System.Threading.Thread
Dim ClientID As String
Dim ClientIP As String
Dim ClientIPandID As String
Dim ClientIPandPort As String
Dim TotalItemCount As String
Dim clientcount As Integer = 0
Private Sub Server_Load(sender As Object, e As EventArgs) Handles Me.Load
CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub ButtonStart_Click(sender As System.Object, e As System.EventArgs) Handles ButtonStart.Click
If TextBoxPort.Text = "" Then
MsgBox("Please Enter Port To Run On.")
Else
ListenerThread = New System.Threading.Thread(AddressOf Listening)
ListenerThread.IsBackground = True
ListenerThread.Start(TextBoxPort.Text)
ButtonStart.Enabled = False
ButtonStop.Enabled = True
ListBox1.Items.Add("[SERVER] Running on Port " + TextBoxPort.Text)
ListBox1.Items.Add("[SERVER] Waiting For A Connection...")
End If
End Sub
Private Sub Listening(ByVal Port As Integer)
Try
Listener = New TcpListener(IPAddress.Any, Port)
Listener.Start()
Do
Client = Listener.AcceptTcpClient 'Accepts Client Trying To Connect
If Client.Connected Then
MsgBox("Client Connected")
End If
clientcount += 1
GetClientInfo() 'Retrieves The Clients Info
AddHandler ReceivedMessage, AddressOf ReceivedMessage1
Loop Until False
Catch ex As Exception
End Try
End Sub
'Events
Public Event ReceivedMessage(ByVal Command As String)
Private Sub GenerateClientSessionNumber()
Dim r As New Random
Dim x As String = String.Empty
For i = 0 To 7
x &= Chr(r.Next(65, 89))
Next
ClientID = x
End Sub
Private Sub GetClientInfo()
GenerateClientSessionNumber()
ClientIPandID = Client.Client.RemoteEndPoint.ToString().Remove(Client.Client.RemoteEndPoint.ToString().LastIndexOf(":")) & " - " & ClientID
ClientIP = Client.Client.RemoteEndPoint.ToString().Remove(Client.Client.RemoteEndPoint.ToString().LastIndexOf(":"))
ClientIPandPort = Client.Client.RemoteEndPoint.ToString()
MsgBox(ClientIPandPort)
ListBox2.Items.Add(ClientIPandID)
Client.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
End Sub
Private Sub ButtonStop_Click(sender As System.Object, e As System.EventArgs) Handles ButtonStop.Click
Listener.Stop()
Client.Close()
ButtonStop.Enabled = False
ButtonStart.Enabled = True
ListBox1.Items.Add("[SERVER] Server Stopped")
End Sub
Private Sub Reading()
Try
Dim Reader As New StreamReader(Client.GetStream)
Dim Command As String = Reader.ReadLine
Client.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
RaiseEvent ReceivedMessage(command)
Catch ex As Exception
End Try
End Sub
Private Sub ReceivedMessage1(ByVal Command As String)
Dim Message() As String = Command.Split("|")
If Message(0) = "MESSAGE" Then
MsgBox("Message Received From Client " + ">" + Message(1))
End If
end sub
[CLIENT]
Public Class Client
Dim Client As New TcpClient
Sub Connect(ByVal ServerIP As String, ByVal Port As Integer)
'Try To Make Connection With Server
If Client.Connected = True Then
MsgBox("Already Connected")
MsgBox("Connected To " + Client.Client.RemoteEndPoint.ToString)
Else
MsgBox("Currently Not Connected. Trying To Connect...")
Try
Client.Connect(ServerIP, Port)
MsgBox("Connected")
Client.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
Catch ex As Exception
MsgBox("Could Not Connect To Server. Check Server." + ex.Message.ToString)
End Try
End If
End Sub
Private Sub SendData(ByVal Message As String) 'Sends Data to Server
TextBox1.Text = Message
Try
If Client.Connected = True Then
Dim Writer As New StreamWriter(Client.GetStream)
Writer.WriteLine(Message)
Writer.Flush()
Else
MsgBox("Cannot Send Message. Connection To Server Is Not Active.")
End If
Catch ex As Exception
MsgBox("You Are Not Connected To The Server." + vbCrLf + ex.Message.ToString)
End Try
End Sub
Private Sub ButtonConnect_Click(sender As Object, e As EventArgs) Handles ButtonConnect.Click
Connect(TextBoxIPAddress.Text, TextBoxPort.Text)
End Sub
Private Sub ButtonSendMessage_Click(sender As Object, e As EventArgs) Handles ButtonSendMessage.Click
SendData("MESSAGE|" & TextBoxMessage.Text)
End Sub
Private Sub Client_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
SendData("DISCONNECT|")
Client.Close()
Client = New TcpClient
End Sub
End Class
i am not sure about the problem but i can give you some hypothesizes, firstly you add handler on every client you connect on server side and that means multiple pointer to the same place, secondly when you connect to server and reconnect you actually don't tell the server that the two clients are the same so he make two channels between the client and the server, the first is the old one that didn't close and he still have handler on it, the server don't recognize that the first is disconnected because he is connected! even if its another object at client. so when client disconnects , disconnect him from server too, or at every loop test if clients are connected before accepting do this test .
Since I have a class Called "ConnectedClient". I was able to make a call to that specific client or all clients and Close/Destroy the connection.

How do I close the tcp client (client.close) with a button?

I have a client server application.
if the client has disconnected the server can detect it automatically and remove it from the connected clients list.
I am going to focus on the server now.
I would like to have a Stop Server button. To stop the Listener and Tcp Client Connections.
I can easily stop the listener, but I am having a hard time trying to figure out how to stop the tcp client ( or issue a Client.Close )
[SERVER]
Public Class Server
Dim ClientList As New Hashtable
Dim Listener As TcpListener
Dim ListenerThread As System.Threading.Thread
Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
ListenerThread = New System.Threading.Thread(AddressOf Listen)
ListenerThread.IsBackground = True
ListenerThread.Start(TextBoxPort.Text)
ButtonStart.Enabled = False
ButtonStop.Enabled = True
ListBox1.Items.Add("[SERVER] Waiting For A Connection...")
End Sub
Sub ClientDisconnected(ByVal Client As ConnectedClient)
ClientList.Remove(Client) 'remove the client from the hashtable
ListBox2.Items.Remove(Client.Name) 'remove it from our listbox
End Sub
Sub Listen(ByVal Port As Integer)
Try
Listener = New TcpListener(IPAddress.Any, Port)
Listener.Start()
Do
Dim Client As New ConnectedClient(Listener.AcceptTcpClient)
AddHandler Client.ReceivedMessage, AddressOf ReceivedMessage
AddHandler Client.ClientDisconnected, AddressOf ClientDisconnected
Loop Until False
Catch
End Try
End Sub
Dim TotalItemCount As String
Sub ReceivedMessage(ByVal Msg As String, ByVal Client As ConnectedClient)
Dim Message() As String = Msg.Split("|")
Select Case Message(0)
Case "CHAT" 'if it's CHAT
ListBox1.Items.Add(Client.Name & " Says: " & " " & Message(1))
Case "SAVETRAN"
ListBox1.Items.Add("Transaction Number: " + Message(1) + vbCrLf + "Customer Number: " + Message(2))
Case "TRANDETAIL"
ListBox1.Items.Add("Barcode: " + Message(1) + vbCrLf + "Quantity: " + Message(2) + vbCrLf + "Price Sold: " + Message(3))
ProgressBar1.Value += 1
Label1.Text = ProgressBar1.Value
If Label1.Text = ProgressBar1.Maximum Then
ProgressBar1.Value = 0
End If
Case "ITEMCOUNT"
ListBox1.Items.Add("SERVER IS EXPECTED TO RECEIVE " + Message(1) + " ITEMS.")
TotalItemCount = Message(1)
ProgressBar1.Maximum = TotalItemCount
Case "LOGIN" 'A client has connected
ClientList.Add(Client, Client.Name)
ListBox2.Items.Add(Client.Name)
End Select
End Sub
Private Sub ButtonStop_Click(sender As Object, e As EventArgs) Handles ButtonStop.Click
Listener.Stop()
ListBox1.Items.Add("Server Stopped")
ButtonStop.Enabled = False
ButtonStart.Enabled = True
End Sub
Private Sub Server_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListBox1.Items.Clear()
End Sub
End Class
In the Server Application there is a class call ConnectedClient
[Connected Client]
Public Class ConnectedClient
Public Cli As TcpClient
Private UniqueID As String
Public Property Name
Get
Return UniqueID
End Get
Set(ByVal Value)
UniqueID = Value
End Set
End Property
Public Sub New(Client As TcpClient)
Dim r As New Random
Dim x As String = String.Empty
For i = 0 To 7
x &= Chr(r.Next(65, 89))
Next
Me.Name = Client.Client.RemoteEndPoint.ToString().Remove(Client.Client.RemoteEndPoint.ToString().LastIndexOf(":")) & " - " & x
Cli = Client
Cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
End Sub
Public Event ReceivedMessage(ByVal Message As String, ByVal Client As ConnectedClient)
Public Event ClientDisconnected(ByVal Client As ConnectedClient)
Sub Reading(ByVal AR As IAsyncResult)
Try
Dim Reader As New StreamReader(Cli.GetStream)
Dim Msg As String = Reader.ReadLine()
RaiseEvent ReceivedMessage(Msg, Me)
Cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
Catch ex As Exception
'Try and read again
Try
Dim Reader As New StreamReader(Cli.GetStream)
Dim Msg As String = Reader.ReadLine()
RaiseEvent ReceivedMessage(Msg, Me)
Cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Reading, Nothing)
Catch
RaiseEvent ClientDisconnected(Me)
End Try
End Try
End Sub
Sub SendData(ByVal Message As String)
Dim Writer As New StreamWriter(Cli.GetStream)
Writer.WriteLine(Message)
Writer.Flush()
End Sub
End Class
I was trying somehow to link to the connected client class and get the Client.Close, but I cannot
figure it out.