How to write a Framed Messaging Server and Client in C#

 
The example shows how to write your own framed messaging server and client based on the basic TcpServer and TcpClient components.
 
 

Server:

public class FramedConnection : UserConnection
{
    protected override void Dispose(bool disposing)
    {
       if (disposing)
       {
           Frame?.Close();
           Frame = null;
       }
       base.Dispose(disposing);
    }

    public FramedConnection() : base()
    {
       Frame = new MemoryStream();
    }

   public byte[] ReceiveFramedData()
   {
      ReadData(Frame);

      if (!IsFrameData)
      {
           if (Frame.Length >= 4)
           {
              Frame.Position = 0;
              byte[] buffer = new byte[4];
              Frame.Read(buffer, 0, buffer.Length);
              int index = 0;
              Size = Utils.ByteArrayReadDWord(buffer, ref index);
              IsFrameData = true;
           }
      }

      if (Size <= Frame.Length - 4)
      {
          Frame.Position = 4;
          byte[] buffer = new byte[Size];
          Frame.Read(buffer, 0, (int)Size);
          Frame.SetLength(0);
          IsFrameData = false;
          Size = 0;
          return buffer;
      }

      return null;
   }

   public void SendFramedData(byte[] data)
   {
       if (data == null) return;

       using (var frame = new MemoryStream())
       {
           byte[] buffer = new byte[4];
           int index = 0;
           Utils.ByteArrayWriteDWord((uint)data.Length, buffer, ref index);
           frame.Write(buffer, 0, buffer.Length);

           frame.Write(data, 0, data.Length);

           frame.Position = 0;
           WriteData(frame);
       }
   }


   public Stream Frame { get; private set; }

   public bool IsFrameData { get; private set; }

   public uint Size { get; private set; }
}
 
    public delegate void ConnectionFramedDataEventHandler(object sender,
    ConnectionFramedDataEventArgs e);

    public class ConnectionFramedDataEventArgs : ConnectionEventArgs
    {
        public ConnectionFramedDataEventArgs(UserConnection connection, byte[] data) :
        base(connection)
        {
            Data = data;
        }

        public byte[] Data { get; }

        new public FramedConnection Connection
        {
            get { return (FramedConnection)base.Connection; }
        }
    }

    public class FramedServer : TcpServer
    {
        static readonly object frameReceived = new object();

        protected override UserConnection CreateDefaultConnection()
        {
            return new FramedConnection();
        }

        protected override void ReadConnection(UserConnection connection)
        {
            try
            {
                byte[] data = ((FramedConnection)connection).ReceiveFramedData();
                if (data != null)
                {
                    OnFrameReceived(new ConnectionFramedDataEventArgs(connection, data));
                }
            }
            finally
            {
                BeginRead(connection);
            }
        }

        protected internal virtual void OnFrameReceived(ConnectionFramedDataEventArgs e)
        {
            ((ConnectionFramedDataEventHandler)Events[frameReceived])?.Invoke(this, e);
        }

        public event ConnectionFramedDataEventHandler FrameReceived
        {
            add
            {
                Events.AddHandler(frameReceived, value);
            }
            remove
            {
                Events.RemoveHandler(frameReceived, value);
            }
        }
    }
 
	public MainFormServer()
	{
		InitializeComponent();
		server = new FramedServer();

		server.FrameReceived += Server_FrameReceived;
	}

	delegate void PutMessageDelegate(string message);

	private void PutMessageToLog(string message)
	{
		if (this.IsDisposed) return;

		if (this.InvokeRequired)
		{
			this.Invoke(new PutMessageDelegate(PutMessageToLog), new object[] 
			{ message });
		}
		else
		{
			txtMessages.Text += message + "\r\n";
			txtMessages.Select(txtMessages.Text.Length, 0);
			txtMessages.ScrollToCaret();
		}
	}

	private void Server_FrameReceived(object sender, ConnectionFramedDataEventArgs e)
	{
		string message = Translator.GetString(e.Data, "utf-8");
		PutMessageToLog(message);

		byte[] reply = Translator.GetBytes(message, "utf-8");
		e.Connection.SendFramedData(reply);
	}

	private void btnStart_Click(object sender, EventArgs e)
	{
		if (server.Active)
		{
			MessageBox.Show("Already strated.");
			return;
		}

		server.Port = Convert.ToInt32(txtPort.Text);
		server.Start();

		Text = "Framed Server - Strated.";
	}

	private void btnStop_Click(object sender, EventArgs e)
	{
		server.Stop();
		Text = "Framed Server";
	}

Client:

	public class FramedClient : TcpClient
	{
		protected override int GetDefaultPort()
		{
			return 2110;
		}
		
		public void SendMessage(string message)
		{
			byte[] data = Translator.GetBytes(message, "utf-8");
			SendFramedData(data);
		}
		public void SendFramedData(byte[] data)
		{
			if (data == null) throw new Exception("No data to send.");

			Connection.InitProgress(0, 0);
			Connection.BytesToProceed = -1;
			byte[] buffer = new byte[4];
			int index = 0;
			Utils.ByteArrayWriteDWord((uint)data.Length, buffer, ref index);
			Connection.WriteBytes(buffer, 0, buffer.Length);

			Connection.WriteBytes(data, 0, data.Length);
		}
		
		public string ReceiveReply()
		{
			byte[] buffer = ReceiveFramedData();
			return Translator.GetString(buffer, "utf-8");
		}
		public byte[] ReceiveFramedData()
		{
			using (var frame = new MemoryStream())
			{
				Connection.InitProgress(0, 0);
				Connection.BytesToProceed = 4;
				do
				{
					Connection.ReadData(frame);
				}
				while (frame.Length < 4);

				frame.Position = 0;
				byte[] buffer = new byte[4];
				frame.Read(buffer, 0, buffer.Length);
				int index = 0;
				uint size = Utils.ByteArrayReadDWord(buffer, ref index);

				Connection.BytesToProceed += size;
				while (size > frame.Length - 4)
				{
					Connection.ReadData(frame);
				}

				frame.Position = 4;
				buffer = new byte[size];
				frame.Read(buffer, 0, (int)size);
				return buffer;
			}
		}
	}
 
	public MainForm()
	{
		InitializeComponent();
		client = new FramedClient();
	}

	private void btnConnect_Click(object sender, EventArgs e)
	{
		if (client.Active)
		{
			MessageBox.Show("Already connected.");
			return;
		}

		client.Server = txtHost.Text;
		client.Port = Convert.ToInt32(txtPort.Text);
		client.TimeOut = 5000;
		client.Open();
		this.Text = "Framed Client - Connected.";
	}

	private void btnDisconnect_Click(object sender, EventArgs e)
	{
		client.Close();
		this.Text = "Framed Client";
	}

	private void btnSend_Click(object sender, EventArgs e)
	{
		if (!client.Active)
		{
			MessageBox.Show("Not connected.");
			return;
		}

			client.SendMessage(txtMessage.Text);
			string reply = client.ReceiveReply();

			txtReplice.Text += reply + "\r\n";
			txtReplice.Select(txtReplice.Text.Length, 0);
			txtReplice.ScrollToCaret();
		}
	}

	public class ExceptionHandler
	{
		public void OnThreadException(object sender, 
		System.Threading.ThreadExceptionEventArgs t)
		{
			MessageBox.Show(t.Exception.Message);
		}
	}
 
Have questions?
Join us Facebook   YouTube   Twitter   Telegram   Newsletter
 
Kind regards
Clever Components team
www.CleverComponents.com

Add Feedback