Click to See Complete Forum and Search --> : TCP server-multiclients problem
ancientrd
Apr 10th, 2009, 08:34 AM
From Atheist example and msdn examples i managed to do this small application : i can send and receive text from a client to a server and back.
The problem is i got stuck on : making multiple client connexions , identify the clients and can send msg to a certain client .:afrog: any help pls ?:afrog:
i use vb 2009
The server source code :
---------------------------
Imports System.Net.Sockets
Imports System.Net.Sockets
Public Class Form1
Dim server As TcpListener
Dim port As Int32 = 13000
' Dim localAddr As IPAddress = IPAddress.Parse("127.0.0.1")
Dim bytes(1024) As Byte
Dim data As String = Nothing
Dim stream As NetworkStream
Dim client As TcpClient
Dim listenThread As System.Threading.Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
server = New TcpListener(System.Net.IPAddress.Any, port)
server.Start()
Label1.Text = "server up"
listenThread = New System.Threading.Thread(AddressOf doListen)
listenThread.IsBackground = True
listenThread.Start()
Catch ex As Exception
Label1.Text = "server down"
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text)
stream = client.GetStream()
stream.Write(msg, 0, msg.Length)
TextBox1.Text = ""
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
server.Stop()
client.Close()
End Sub
Private Delegate Sub StringDelegate(ByVal text As String)
Private Sub SetConnectionLabelText(ByVal text As String)
If Me.TextBox2.InvokeRequired Then
Me.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), text)
Else
Me.TextBox2.Text = text
End If
End Sub
Private Sub doListen()
client = server.AcceptTcpClient()
Do
data = Nothing
stream = client.GetStream()
Dim iq As Int32
iq = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq)
SetConnectionLabelText(data)
Loop
End Sub
End Class
-------------------------------------------------------------------
the client source code:
-----------------------
Imports System.Net.Sockets
Public Class Form1
Dim port As Integer = 13000
Dim server As String
Dim client As TcpClient
Dim stream As NetworkStream
Dim listenThread As System.Threading.Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
server = TextBox3.Text
client = New TcpClient(server, port)
stream = client.GetStream()
Label1.Text = "connected"
listenThread = New System.Threading.Thread(AddressOf doListen)
listenThread.IsBackground = True
listenThread.Start()
Catch ex As Exception
Label1.Text = "not connected"
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text)
stream.Write(data, 0, data.Length)
TextBox1.Text = ""
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
client.Close()
End Sub
Private Delegate Sub StringDelegate(ByVal text As String)
Private Sub SetConnectionLabelText(ByVal text As String)
If Me.TextBox2.InvokeRequired Then
Me.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), text)
Else
Me.TextBox2.Text = text
End If
End Sub
Private Sub doListen()
Do
Dim data As [Byte]() = New [Byte](256) {}
Dim responseData As [String] = [String].Empty
Dim bytes As Int32 = stream.Read(data, 0, data.Length)
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
SetConnectionLabelText(responseData)
Loop
End Sub
End Class
Atheist
Apr 10th, 2009, 09:01 AM
Could you please wrap your code in code tags? IT makes it alot easier to read. code goes here
ancientrd
Apr 10th, 2009, 09:08 AM
done ... i edited it :D thx a lot for that info :D, indeed i guess is much better
Atheist
Apr 10th, 2009, 09:22 AM
Your AcceptTcpClient call is outside of the loop in the doListen method, and so the server will only accept one connection and attempt to read from this connection endlessly. You need to repeatedly call AcceptTcpClient in order to always accept new connections. Furthermore, you really need to read from each connection on a separate thread, or else your chat application will be quite useless.
ancientrd
Apr 10th, 2009, 09:33 AM
like this ?
Private Sub doListen()
Do
client = server.AcceptTcpClient()
data = Nothing
stream = client.GetStream()
Dim iq As Int32
iq = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq)
SetConnectionLabelText(data)
Loop
End Sub
ok so if this solve the multiple clients how can i identify them now ?
for example by ip (client(1).ip = .... or start working with the client class ?
i saw u made that connected client but i wasn;t able to understand how it works ....
can u help me create one connected property for my case ?
i saw u used a streamwriter and a streamreader ...i used only the stream for both read and write...( that was in the msdn example) .... the thread system i took from you wich was great.... i still have a little problem with the write in the textbox too since in u;re example u have to define a write for each textbox or label ... how can i make that for general ?
Private Delegate Sub StringDelegate(ByVal text As String)
Private Sub SetConnectionLabelText(ByVal text As String)
If Me.TextBox2.InvokeRequired Then
Me.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), text)
Else
Me.TextBox2.Text = text
End If
End Sub
and when i see the client that connects how can i see it;s properties ? the ip , mac or other identifyers? to can start use them becouse the next step is to add a ssl connect maybe a credential certificate .... not sure but something to encrypt and secure the data on the stream , not to be intercepted or to protect the server from other clients (make the user/pass)
i saw in u;re example u did a string split by the "|" wich is good but how can i put the server read and compare the stream i get from the client with a database with the clients usernames and passwords ?
ancientrd
Apr 10th, 2009, 10:00 AM
oh i saw 1 more thing ....
when u write in a textbox i saw u use that invoke request... .now the problem is how can i make it read from the textbox .... like a chat channel ?
to add the new string received to the existing one ?
Atheist
Apr 11th, 2009, 06:32 AM
like this ?
Private Sub doListen()
Do
client = server.AcceptTcpClient()
data = Nothing
stream = client.GetStream()
Dim iq As Int32
iq = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq)
SetConnectionLabelText(data)
Loop
End Sub
Yes, but you still need to do more modifications. Currently the server will accept connections one by one, and as soon as a host has connected it'll read all available data from it, then accepting the next connection. etc. This is why you need to do some threading. You must be able to handle communication with multiple hosts at the same time.
ok so if this solve the multiple clients how can i identify them now ?
for example by ip (client(1).ip = .... or start working with the client class ?
i saw u made that connected client but i wasn;t able to understand how it works ....
You can choose any type of identification you see fit. A common and simple way is just to let each client identify himself with a username as soon as he connects, this username will be the clients unique identifier in this distributed system.
It is a very good idea to create a class that contains all logic for a connected client, as I showed in my example.
i saw u used a streamwriter and a streamreader ...i used only the stream for both read and write...( that was in the msdn example) ....
The StreamReader/StreamWriter just provides a simpler interface to reading and writing to streams, but there's nothing you can do with a StreamReader/StreamWriter that you can not directly do with the Stream object. So you can choose to use them, or you can choose not to, any way is fine.
There is also the BinaryReader/BinaryWriter, which can be good for some occasions.
i still have a little problem with the write in the textbox too since in u;re example u have to define a write for each textbox or label ... how can i make that for general ?
Private Delegate Sub StringDelegate(ByVal text As String)
Private Sub SetConnectionLabelText(ByVal text As String)
If Me.TextBox2.InvokeRequired Then
Me.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), text)
Else
Me.TextBox2.Text = text
End If
End Sub
I'm not entirely sure I understand what you mean, but are you talking about something like this?
Private Delegate Sub SetTextDelegate(ByVal ctrl As Control, ByVal text As String)
Private Sub SetText(ByVal ctrl As Control, ByVal text As String)
If ctrl.InvokeRequired Then
ctrl.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), ctrl, text)
Else
ctrl.Text = text
End If
End Sub
and when i see the client that connects how can i see it;s properties ? the ip , mac or other identifyers? to can start use them becouse the next step is to add a ssl connect maybe a credential certificate .... not sure but something to encrypt and secure the data on the stream , not to be intercepted or to protect the server from other clients (make the user/pass)
To find the IP of the host, you'll have to use the TcpClients Client property to get a reference to the underlying socket. The Socket class has a RemoteEndPoint property that'll give you the remote IP and port.
Read up on the System.Net.Security.SslStream class if you want to use SSL, you can find some good information on it on MSDN.
i saw in u;re example u did a string split by the "|" wich is good but how can i put the server read and compare the stream i get from the client with a database with the clients usernames and passwords ?
My example isnt really optimal in that sense that it uses a delimiter character, but.. never mind that for now.
I'm not sure I know what you're asking. If you get the username and the password (or MD5 hash of password!), you can simply perform an SQL query to see if they exist and match.
ancientrd
Apr 11th, 2009, 09:10 AM
1. i need the get text function , u added in your example how to write text in a control from other thread , ineed to know how you can get the text from a control in other thread
control or variable
thank you
atm i am trying to make the client class
i will post as soon as i finish to make it or broke it :d
ancientrd
Apr 12th, 2009, 10:02 AM
i couldn;t make the client class ... (the server to work with a lot of clients) ... all i did was to can see if a client is allowed to connect or not ...
Private Sub doListen()
client = server.AcceptTcpClient()
data = Nothing
stream = client.GetStream()
Dim iq2 As Int32
iq2 = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq2)
Dim verclient() As String = Split(data, "~")
If verclient(1) = "Client1" Then 'add query to ceck the client if is allowed to connect or not by pwd,user,ip
SetText(TextBox2, data)
Do
data = Nothing
stream = client.GetStream()
Dim iq As Int32
iq = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq)
SetText(TextBox2, data)
Loop
Else
client.Close()
End If
End Sub
Atheist
Apr 13th, 2009, 05:51 AM
1. i need the get text function , u added in your example how to write text in a control from other thread , ineed to know how you can get the text from a control in other thread
control or variable
thank you
atm i am trying to make the client class
i will post as soon as i finish to make it or broke it :d
I believe it is thread safe to get values from properties, but not setting them. So just do like you'd normally do if you want the text value from a TextBox.
ancientrd
Apr 13th, 2009, 10:19 AM
Atheist i am not sure if u got any msg but i will say here too :
I managed to make the server,class and client
I have 1 problem when i connect more clients ( from same comp i tested) the server send msg to only the 1st client that connected not to all. to receive i can receive from all clients
i will post the code here :
SERVER :
Imports System.Net.Sockets
Imports System.Net.Security
Public Class Form1
Dim server As TcpListener
Dim port As Int32 = 13000
' Dim localAddr As IPAddress = IPAddress.Parse("127.0.0.1")
Dim stream As NetworkStream
Dim listenThread As System.Threading.Thread
Private clients As New List(Of connected)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
server = New TcpListener(System.Net.IPAddress.Any, port)
server.Start()
Label1.Text = "server up"
listenThread = New System.Threading.Thread(AddressOf doListen)
listenThread.IsBackground = True
listenThread.Start()
Catch ex As Exception
Label1.Text = "server down"
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
For Each cc As connected In clients
cc.sendmsg(TextBox1)
Next
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
server.Stop()
End Sub
Private Sub doListen()
Dim incomingClient As System.Net.Sockets.TcpClient
Do
incomingClient = server.AcceptTcpClient 'Accept the incoming connection. This is a blocking method so execution will halt here until someone tries to connect.
Dim connClient As New connected(incomingClient, Me, TextBox2) 'Create a new instance of ConnectedClient (check its constructor to see whats happening now).
clients.Add(connClient) 'Adds the connected client to the list of connected clients.
Loop
End Sub
End Class
CLASS ;
Public Class connected
Private mClient As System.Net.Sockets.TcpClient
Private mParentForm As Form
Private readThread As System.Threading.Thread
Private mctrltxt As Control
Private bytes(1024) As Byte
Private data As String = Nothing
Private stream As System.Net.Sockets.NetworkStream
Public ip As String
Sub New(ByVal client As System.Net.Sockets.TcpClient, ByVal parentForm As Form, ByVal ctrltxt As Control)
mParentForm = parentForm
mClient = client
mctrltxt = ctrltxt
readThread = New System.Threading.Thread(AddressOf doread)
readThread.IsBackground = True
readThread.Start()
End Sub
Private Delegate Sub StringDelegate(ByRef ctrl As Control, ByVal text As String)
Private Sub SetText(ByRef ctrl As Control, ByVal text As String)
If ctrl.InvokeRequired Then
ctrl.BeginInvoke(New StringDelegate(AddressOf SetText), ctrl, text)
Else
ctrl.Text = text
End If
End Sub
Private Function gettext(ByRef ctrl As Control)
Return (ctrl.Text)
End Function
Private Sub doread()
data = Nothing
stream = mClient.GetStream()
Dim iq2 As Int32
iq2 = stream.Read(bytes, 0, bytes.Length)
data = System.Text.Encoding.ASCII.GetString(bytes, 0, iq2)
Dim verclient() As String = Split(data, "~")
ip = verclient(0)
Dim squad As String = Nothing
squad = gettext(mctrltxt) + vbCrLf + data
If verclient(1) <> "Client1" Then 'add query to ceck the client if is allowed to connect or not by pwd,user,ip
SetText(mctrltxt, squad)
Do
data = Nothing
stream = mClient.GetStream()
Dim iq As Int32
iq = stream.Read(bytes, 0, bytes.Length)
data = verclient(1) + " " + System.Text.Encoding.ASCII.GetString(bytes, 0, iq)
Dim squad2 As String = Nothing
squad2 = gettext(mctrltxt) + vbCrLf + data
SetText(mctrltxt, squad2)
Loop
Else
MsgBox(data)
mClient.Close()
End If
End Sub
Public Sub sendmsg(ByVal ctrl As TextBox)
Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(ctrl.Text)
SyncLock mClient.GetStream
stream = mClient.GetStream()
stream.Write(msg, 0, msg.Length)
End SyncLock
ctrl.Text = ""
End Sub
End Class
CLIENT :
Imports System.Net.Sockets
Imports System.Net.Security
Public Class Form1
Dim port As Integer = 13000
Dim server As String
Dim client As TcpClient
Dim stream As NetworkStream
Dim listenThread As System.Threading.Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
server = TextBox3.Text
client = New TcpClient(server, port)
stream = client.GetStream()
Label1.Text = "connected"
Dim identification As String = client.Client.LocalEndPoint.ToString + "~" + TextBox4.Text + "~" + "Password1"
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(identification)
stream.Write(data, 0, data.Length)
TextBox1.Text = ""
listenThread = New System.Threading.Thread(AddressOf doListen)
listenThread.IsBackground = True
listenThread.Start()
Catch ex As Exception
Label1.Text = "not connected"
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text)
stream.Write(data, 0, data.Length)
TextBox1.Text = ""
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
client.Close()
End Sub
Private Delegate Sub StringDelegate(ByVal ctrl As Control, ByVal text As String)
Private Sub SetText(ByVal ctrl As Control, ByVal text As String)
If ctrl.InvokeRequired Then
ctrl.Invoke(New StringDelegate(AddressOf SetText), ctrl, text)
Else
ctrl.Text = text
End If
End Sub
Private Function gettext(ByRef ctrl As Control)
Return (ctrl.Text)
End Function
Private Sub doListen()
Do
Dim data As [Byte]() = New [Byte](1024) {}
Dim responseData As [String] = [String].Empty
Dim bytes As Int32 = stream.Read(data, 0, data.Length)
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
Dim squad As String = Nothing
squad = gettext(TextBox2) + vbCrLf + responseData
SetText(TextBox2, squad)
Loop
End Sub
End Class
I will need help with the following please :
1. add ssl conection
2. add encripted connection
3. add certificate to the connection (client and server)
4. when a client got disconected how can i see ? and event or something like that ... to ceck connected clients when they disconect so can trace them .... and remove them from the conencted list
5. help for any improvment of the actual code :D
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.