Related
I'm trying to make a client-server connection using sockets.
It basically works pretty well; only one problem is when I close and re-open my server on server computer the clients won't reconnect
This is my client code :
Imports System.Net.Sockets
Imports System.Threading
Imports System.IO
Public Class Form1
Public Delegate Sub MessageReceivedEventHandler(ByVal sender As Object, ByVal e As MessageReceivedEventArgs)
Public Delegate Sub ClientConnectedEventHandler(ByVal sender As Object, ByVal e As ClientConnectedEventArgs)
Public Event MessageReceived As MessageReceivedEventHandler
Public Event ClientConnected As ClientConnectedEventHandler
Public Buffer As Byte()
Public Shared Client As TcpClient
Dim Port As Integer = 5050
Dim host As String = "computer name"
Dim KEY As String = "mykey"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim T As New Thread(AddressOf run)
T.Start()
End Sub
Private Sub run()
' Connect to the server'
Client = New TcpClient(host, Port)
Dim T As New Thread(AddressOf Receiver, 10)
T.Start()
End Sub
Public Shared Function StringToByte(ByVal STR As String) As Byte()
Return System.Text.Encoding.Default.GetBytes(STR)
End Function
Public Shared Function ByteToString(ByVal BYS As Byte()) As String
Return System.Text.Encoding.Default.GetString(BYS)
End Function
Public Sub Data(ByVal Sender As Object, ByVal Data As MessageReceivedEventArgs) Handles Me.MessageReceived
Dim info As Byte() = Data.Message
Dim Client As Socket = Data.clientSocket
Dim ID As String = Data.Sender
Dim Arr As String() = Split(System.Text.Encoding.Default.GetString(info), "mykey")
Try
Select Case Arr(0)
Case "MSG"
MsgBox(Arr(1))
End Select
Catch ex As Exception
MsgBox("Error Detected in Data Client :" & ex.Message)
End Try
End Sub
Sub Receiver()
Dim M As New MemoryStream
Try
If Client.Available > 0 Then
ReDim Buffer(Client.Available - 1)
Client.Client.Receive(Buffer, 0, Buffer.Length, SocketFlags.None)
M.Write(Buffer, 0, Buffer.Length)
If System.Text.Encoding.Default.GetString(M.ToArray).Contains("EOF") Then
Dim Data As Byte() = (M.ToArray).Remove(ConfigTcp.ENDOFPACKET)
Dim Msg As New MessageReceivedEventArgs
Msg.Message = Data
Msg.clientSocket = Client.Client
Msg.Sender = Client.Client.Handle.ToString()
RaiseEvent MessageReceived(Me, Msg)
M.Dispose()
M = New MemoryStream
End If
End If
Thread.Sleep(1)
Catch ex As Exception
MsgBox("Error Detected :" & ex.Message)
End Try
End Sub
Public Shared Sub Send(ByVal sock As Socket, ByVal s As String)
Send(sock, System.Text.Encoding.UTF8.GetBytes(s))
End Sub
Private Shared Sub Send(ByVal sock As Socket, ByVal b As Byte())
Try
Dim Memory As MemoryStream = New MemoryStream
Dim CB As Byte() = b
Memory.Write(CB, 0, CB.Length)
Memory.Write(ConfigTcp.ENDOFPACKET, 0, ConfigTcp.ENDOFPACKET.Length)
sock.Send(Memory.ToArray, 0, Memory.Length, SocketFlags.None)
Memory.Dispose()
Catch x As Exception
End Try
End Sub
End Class
Public Class MessageReceivedEventArgs
Inherits EventArgs
Public Sender As String
Public clientSocket As Socket
Public Message As Byte()
End Class
Public Class ClientConnectedEventArgs
Inherits EventArgs
Public clientID As String
Public clientSocket As Socket
End Class
Your client needs to handle disconnects and reconnect if needed.
To accomplish this, you can catch a SocketException and see why the socket was closed.
Depending on the exception you can run a method to have your client reconnect.
Public Sub DoReconnect()
Dim SecondsToWait as Integer=1
Do
Try
Client = New TcpClient(host, Port)
Exit Do
Catch SockEx as SocketException
'TODO: decide whether to attempt reconnection or exit
Catch Ex as Exception
'TODO: Most likely should terminate the program here
Console.WriteLine(Ex.ToString())
Exit Do
End Try
System.Threading.Thread.Sleep(SecondsToWait*1000)
SecondsToWait <<=1 ' Exponential Back Off Time
Loop
End Sub
#Alexander Higgins
I tried something like this but seems that SocketException happens only before opening the server for the first time.If I close the server it and re-open it, it doesn't catch SocketException
Public Sub DoReconnect()
re:
Thread.Sleep(1000)
Try
Client = New TcpClient(host, Port)
Dim T As New Thread(AddressOf Receiver, 10)
T.IsBackground = True
T.Start()
Catch SockEx As SocketException
MsgBox("SocketException " + SockEx.Message)
GoTo re
Catch Ex As Exception
MsgBox("Exception " + Ex.Message)
End Try
End Sub
Private Sub run()
DoReconnect()
End Sub
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 :(
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.
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.
I am looking for help with writing a server application to serve an updating text stream to clients. My requirements are as follows:
I need to be able to have a client request information on server port 7878 and receive back an initial set of values, the changed values would then be reported every 5 seconds. The hanging point for me has been connecting another client. I need to be able to connect a 2nd (or 3rd or 4th) client while the first is still running. The second client would receive the initial values and then begin updating as well. I need the two streams to be completely independent of each other. Is this possible with VB.Net and TCP sockets?
Edit to add: I have pasted some of my code below of what I can share. WriteLog is a separate sub that isn't really relevant to my problem. This code will allow for a client to connect and then allow for another client to connect, but all transmissions to the 1st client stop on a new connection.
Public Class ServerApp
Dim serverSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Dim clientSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Private Sub ServerApp_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
WriteLog(String.Format("Start of form load.."))
Dim listener As New Thread(New ThreadStart(AddressOf ListenForRequests))
listener.IsBackground = True
listener.Start()
End Sub
Private Sub ListenForRequests()
Dim CONNECT_QUEUE_LENGTH As Integer = 4
serverSocket.Bind(New IPEndPoint(IPAddress.Any, 7878))
serverSocket.Listen(CONNECT_QUEUE_LENGTH)
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
End Sub
Private Sub OnAccept(ByVal ar As IAsyncResult)
clientSocket = serverSocket.EndAccept(ar)
serverSocket.BeginAccept(New AsyncCallback(AddressOf OnAccept), Nothing)
WriteLog("just accepted new client")
Try
clientSocket.Send(Encoding.UTF8.GetBytes("first response on connect"), SocketFlags.None)
While True
clientSocket.Send(Encoding.UTF8.GetBytes("string of updates"), SocketFlags.None)
Thread.Sleep(5000)
End While
Catch ex As Exception
WriteLog(ex.Message)
WriteLog("Remote host has disconnected")
End Try
End Sub
End Class
I recommend trying out the UdpClient class, i find it easier to use and understand.
Now for some code...
Imports System.Net.Sockets
Imports System.Threading
Imports System.Text
Imports System.Net
Public Class Form1
Private port As Integer = 7878
Private Const broadcastAddress As String = "255.255.255.255"
Private receivingClient As UdpClient
Private sendingClient As UdpClient
Private myTextStream As String = "Blah blah blah"
Private busy As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
InitializeSender()
InitializeReceiver()
End Sub
Private Sub InitializeSender()
Try
sendingClient = New UdpClient(broadcastAddress, port)
sendingClient.EnableBroadcast = True
Catch ex As Exception
MsgBox("Error, unable to setup sender client on port " & port & "." & vbNewLine & vbNewLine & ex.ToString)
End Try
End Sub
Private Sub InitializeReceiver()
Try
receivingClient = New UdpClient(port)
ThreadPool.QueueUserWorkItem(AddressOf Receiver)
Catch ex As Exception
MsgBox("Error, unable to setup receiver on port " & port & "." & vbNewLine & vbNewLine & ex.ToString)
End
End Try
End Sub
Private Sub sendStream()
busy = True
Dim i% = 0
Do While i < 4
If myTextStream <> "" Then
Dim data() As Byte = Encoding.ASCII.GetBytes(myTextStream)
Try
sendingClient.Send(data, data.Length)
Catch ex As Exception
MsgBox("Error, unable to send stream." & vbNewLine & vbNewLine & ex.ToString)
End
End Try
End If
Thread.Sleep(5000)
i += 1
Loop
busy = False
End Sub
Private Sub Receiver()
Dim endPoint As IPEndPoint = New IPEndPoint(IPAddress.Any, port)
While True
Dim data() As Byte
data = receivingClient.Receive(endPoint)
Dim incomingMessage As String = Encoding.ASCII.GetString(data)
If incomingMessage = "what ever the client is requesting, for example," & "GET_VALUES" Then
If busy = False Then Call sendStream()
End If
End While
End Sub
End Class
A few links that may help: Here,
here,
here and
here.