Put Sockets in seperate thread...

lidds

Well-known member
Joined
Oct 19, 2004
Messages
122
Programming Experience
Beginner
I am trying to create an application, one on a server and the other on a networked PC. What I want to do is send information from the PC app. to the server app.

I have the following code which allow information to be sent when the applications are launched, so they are able to talk to each other. The only problem I have is that the applications both freeze. What I want to do is have the sockets running in a different thread so that PC app. can send information from the main form to the server app. and that information can then be displayed on the server main form e.g. information entered in a text field.

Below is the code that creates the socket, and this passes information successfully, but as I said it freezes the applications.

VB.NET:
Imports System.Net.Sockets
Imports System.Text

Public Class Form1
    Dim tcpClient As New System.Net.Sockets.TcpClient()


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub runClient(ByVal message As String)
        Dim networkStream As NetworkStream = tcpClient.GetStream()
        If networkStream.CanWrite And networkStream.CanRead Then
            ' Do a simple write. 
            Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(message)
            networkStream.Write(sendBytes, 0, sendBytes.Length)
            ' Read the NetworkStream into a byte buffer. 
            Dim bytes(tcpClient.ReceiveBufferSize) As Byte
            networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
            ' Output the data received from the host to the console. 
            Dim returndata As String = Encoding.ASCII.GetString(bytes)
            Console.WriteLine("Host returned: " + returndata)
        Else
            If Not networkStream.CanRead Then
                Console.WriteLine("cannot not write data to this stream")
                tcpClient.Close()
            Else
                If Not networkStream.CanWrite Then
                    Console.WriteLine("cannot read data from this stream")
                    tcpClient.Close()
                End If
            End If
        End If
        ' pause so user can view the console output 
        Console.ReadLine()
    End Sub

    Private Sub runServer()
        ' Must listen on correct port- must be same as port client wants to connect on. 
        Const portNumber As Integer = 8000
        Dim IP As System.Net.IPAddress
        IP = System.Net.IPAddress.Parse(Me.txtIP.Text)

        Dim tcpListener As New TcpListener(IP, portNumber)
        tcpListener.Start()
        Console.WriteLine("Waiting for connection...")
        Try
            'Accept the pending client connection and return             'a TcpClient initialized for communication. 
            Dim tcpClient As TcpClient = tcpListener.AcceptTcpClient()
            Console.WriteLine("Connection accepted.")
            ' Get the stream 
            Dim networkStream As NetworkStream = tcpClient.GetStream()
            ' Read the stream into a byte array 
            Dim bytes(tcpClient.ReceiveBufferSize) As Byte
            networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
            ' Return the data received from the client to the console. 
            Dim clientdata As String = Encoding.ASCII.GetString(bytes)
            Console.WriteLine("Client sent: " + clientdata)
            Dim responseString As String = "Connected to server."
            Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(responseString)
            networkStream.Write(sendBytes, 0, sendBytes.Length)
            Console.WriteLine("Message Sent /> : " + responseString)
            'Any communication with the remote client using the TcpClient can go here. 
            'Close TcpListener and TcpClient. 
            tcpClient.Close()
            tcpListener.Stop()
            Console.WriteLine("exit")
            Console.ReadLine()
        Catch e As Exception
            Console.WriteLine(e.ToString())
            Console.ReadLine()
        End Try
    End Sub

    Private Sub Panel1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
        Me.txtStatus.Text = "X: " & e.X.ToString & " Y: " & e.Y.ToString

        If Me.radClient.Checked = True Then
            runClient("X: " & e.X.ToString & " Y: " & e.Y.ToString)
        End If
    End Sub

    Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
        If Me.radClient.Checked = True Then
            tcpClient.Connect(Me.txtIP.Text, 8000)
            runClient("Connect from machine with IP address " & Me.txtIP.Text)
        Else
            runServer()
        End If
    End Sub

    Private Sub btnDisconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisconnect.Click
        If Me.radClient.Checked = True Then
            tcpClient.Close()
        End If
    End Sub
End Class

Any help would be appreshiated

Thanks

Simon
 
You should check out an asyncronous IO tutorial.. Async IO is better performance multithreading than managing the threads yourself..

You will have a BeginXXX method on your tcp connectors.. I think it's BeginConnect on a client and BeginAccept on a listener

To the BeginXXX call you will have to provide an IAsyncResult object that is a generic delegate (a way of attaching an object reference to a "method/function/sub" so it can be passed round and called without knowing its name). When a client connects, .NET will start another thread and use it to call the method you specified in the IAsyncResult.
The first thing you must do in that method, is call EndXXX which will return you something you can work with to read and write data, and then immediately after you should call BeginXXX again, so that the listener starts listening again (and .NET prepares to make another thread to handle other data).
Also remember not to use global variables when working async, because you cannot predict the number or sequence of threads and you dont want multithreading issues

From the client point of view, Begin and End cause some network data to move round, and if not enough data moved, you should repeatedly call Begin/End until you got all the data youre expecting.


Sometimes it is easier to program a client to be synchronous and a server to be asyncronous just because its easier to think about..
 
Back
Top