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?