Chinese (People's Republic of China)  English  Français


Supinfo-Projects.com
Supinfo Students' projects



Projects
  Last project
  Top projects
  All projects

101 User's online
3168 Projects


My Supinfo-Projects

   Login
   Create account


Synopsis

   7 Hits
   Visitors Score : 19
    (2 Voter)
   1 Comments

   Read the article

Evaluate this article

20
18
16
14
12
10
8
6
4
2
0


Comment this article

Author :

Email :

Your comment :



 
2006 - Pérennisation
TCP Client Server programming using TCP with C# .NET2
[20 mn of reading - published 6/3/2006 6:29:38 PM - Target : Confirmé]

Author

THGThomas BONNET
Student-Engineer Supinfo Paris
SUPINFO graduate year  2007

   Write to the person
   All projects of the same author
   Mini-CV of the author

2. Coding the client

2.1. Architecture

For our project, we will create the following classes:

  • 1 Windows Form
  • 1 static connection class (since we only need 1 connection for the client)

The project consists in writing a chat client and server (non standard).

Development Steps

  1. Create the static connection class
  2. Send the different events to the user interface
  3. Create the Connect method which will launch the thread that will connect.
  4. Create a function that will loop within the thread while the connection is alive.
  5. Create the methods that will send and receive data
  6. Code the events that will be sent to the client
  7. Then, create the methods called by the client to send commands.

There are links to download the full project source code at the end of this article.

2.2. Connection to a server

This code is for the first part of the project (The connection, the event creation and the Thread launch execution)

Connection code and global structure (cleaned):

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Diagnostics;

namespace ChatClient
{
    //Event content class
    public class ConnectEventArgs:EventArgs
    {
        string message;
        public ConnectEventArgs(string message)
        {
            this.message = message;
        }
    }

    public static class Connexion
    {
        //Global Variable declaration
        private const int MAX_PACKET_SIZE = 80;
        private const char TERMINATION_STRING = '\0';

        //Our Local Thread
        private static Thread thread;

        //Delegates & Events
public delegate void ConnectionEstablishedEventArgs(ConnectEventArgs e); public delegate void ConnectFailedEventHandler(ConnectEventArgs e); public static event ConnectFailedEventHandler ConnectFailed; public static event ConnectionEstablishedEventArgs ConnectionEstablished; //Methods to throw events private static void OnConnectionEstablished(string message) { ConnectionEstablished(new ConnectEventArgs(message)); } private static void OnConnectFailed(string message) { ConnectFailed(new ConnectEventArgs(message)); } //Method used to connect
public static void Connect() { //In case we had a previous connection. if (thread != null ) if (thread.IsAlive) { try { if (thread != null) { thread.Join(400);//Sync. Threads } } catch (Exception e) { //Exception if thread failed to unload in 400ms Debug.WriteLine("Thread était lancé: "e.Message); } } //Launch Thread thread = new Thread(new ThreadStart(ManageConnection)); } //Method executed by the new thread public static void ManageConnection() { TcpClient client; NetworkStream ns; try { client = new TcpClient("localhost", 22); } catch (Exception ex) { Debug.WriteLine("Error : "+ex.Message); OnConnectFailed("Connection failed: "+ex.Message); return;//Exit thread. } //Connection Established. OnConnectionEstablished("Connection Established"); ns = client.GetStream(); while(client.Connected) { //... } }

At this time, the TCP connection remains open. Inside the loop structure we can use the Thread.Sleep(50) method to limit processor use. It will not interfere with data reception.

Once events are declared, you can use them by using methods like OnConnectionEstablished().

2.3. Receiving and sending data

2.3.1. Receiving data method

The SocketRead(NetworkStream ns) method on the bottom returns a string of what has been received by the TcpClient.GetStream() object.

Please note that these methods are common to our client and server and could be reused in every socket project.

        /// 
        /// Read NetWorkStream to retrieve data
        /// 
        /// 
        public static string SocketRead(NetworkStream ns)
        {
            int iterator = 0;
            int srb = 0;
            int numBytesRead = 0;
            string buffer;

            buffer = String.Empty;
            while (ns.CanRead)
            {
                try
                {
                    byte[] b = new byte[MAX_PACKET_SIZE];
                    srb = ns.Read(b, 0, MAX_PACKET_SIZE);

                    buffer += Encoding.Default.GetString(
                        b, 0, srb).Substring(0, srb);

                    numBytesRead += srb;
                    if (srb == -1 || numBytesRead >= 64 * 1024) break;

                    //Quit loop when all understandable data have been received
                    //TERMINATION_STRING: end of message character
                    //This method is used to prevent packet fragmentation.
                    //We receive all the data arriving at the same time. 
                    //You will have to separate received messages later
                    if (buffer.Length > 1)
                        if (buffer[buffer.Length - 1] == TERMINATION_STRING) 
                            break;

                    if (iterator > 10000)
                        throw (new Exception("Connection Problem: Receive"));
                }
                catch (Exception ex)
                {
                    throw (ex);
                }
            }
            return buffer;
        }

Messages received are commonly fragmented and could be difficult to reassemble for the messages to be understood. Especially if we don't delimit them perfectly.

Here, we use a termination string (a char) to delimit messages.
Check that at no moment you have used the termination string inside a message, otherwise you will have no possibilities to reassemble the message correctly.

Fragmented messages are received all together to make sure we reach at last the end of a message (Otherwise we will still have to wait for data).

We can encode messages in different ways in order to remove some termination string existence from messages.
I used base64 supported by the framework.

To encode a message:

System.Convert.ToBase64String(Encoding.UTF8.GetBytes(str))+CST_PARAM_TERMINATION;

To decode the message: Convert.FromBase64String().

2.3.2. Sending data

The next code we'll present: the _send() method, allows to send data converted in byte[] to a NetworkStream.

Returns false when data have not been sent, plus the ConnectionFailed event (not necessary).

Returns true when data have been sent.

        /// 
        /// Sending data
        /// 
        /// NetWork Stream
        /// message to be sent, byte[]
        /// true if success / Exception then
        public static bool _send(byte[] values,NetworkStream ns)
        {
            //Use: 
            //send(Encoding.ASCII.GetBytes("fsdofbsqgsfg"+TERMINATION_STRING));
            int nextBuf, totalSent = 0;
            if (ns.CanWrite)
            {
                for (int indx = 0; indx < (values.GetLength(0)); 
indx += MAX_PACKET_SIZE) { try {
//Writing data
ns.Write(values, indx, nextBuf = indx
+ MAX_PACKET_SIZE < values.GetLength(0) ?
MAX_PACKET_SIZE : values.GetLength(0) - indx);
totalSent += nextBuf; } catch (Exception ex) { OnConnectFailed(ex.Message); return false; } }; } else { OnConnectFailed("Cannot write"); return false; } return true; }

2.4. Stop the Thread and Socket

Forcing a Thread to stop is not advised (Abort method) because the Thread location in the method is unknown. But you should use this method if the thread cannot exit by itself.

You have to create a method that will make this Thread stop (shared variable set to a different value) and that will execute a Thread.Join(int_time_in_ms).

Eventually, don't forget to close both communication objects tcpClient.Close() and ns.Close() (for the NetworkStream of our examples).



Articles de la même catégorie

 Pages : Top


7 Hits
0 Comments
JMX
[20 mn of reading - published 6/3/2006 6:19:21 PM - Target : Expert]

More


12 Hits
0 Comments
What is Web 2.0?
[30 mn of reading - published 6/3/2006 5:43:53 PM - Target : Confirmé]

More


20 Hits
0 Comments
Web 2.0
[30 mn of reading - published 6/3/2006 5:42:02 PM - Target : Confirmé]

More

Powered by Campus-Booster Technology
Conditions d'utilisation & Copyright | Respect de la vie privée
© Copyright 1965-2006 Supinfo Paris, Paris Academy of Computer Science
Supinfo, Ecole Supérieure d'Informatique et Paris Academy Of Computer Science are trade marks.
23, rue de Château LANDON - 75010 PARIS - Phone : +33 (0) 153359 700 Fax : +33 (0) 153359 701

Web site autided by :