How to properly separate packets using Sockets stream? C# - c#

I'm building a server / client application and I'm looking through options for separating packets. I've read that the most proper one would be creating a header that contains information on how big the payload is and then read until it ends.
How does that programmatically works?
Also separating those by using "\n" newline. A proper example would be nice.
I'm async receiving data this way:
private void AsyncReceive(IAsyncResult result)
{
int bytesTransfered;
try
{
bytesTransfered = _handle.EndReceive(result);
if(bytesTransfered <= 0)
{
throw new Exception("No bytes transfered");
}
}
catch(NullReferenceException)
{
return;
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
return;
}
byte[] received = new byte[bytesTransfered];
try
{
Array.Copy(_readBuffer, received, received.Length);
}
catch(Exception)
{
Disconnect();
return;
}
// How should I process the received data now?
try
{
_handle.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, AsyncReceive, null);
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
}
}

First you need to distinguish between different types of messages. You can use single byte for that, which will allow for up to 255 different message types. Make an enum for that, and an attribute to mark your messages (see below):
enum MessageType : byte {
FirstMessage,
SecondMessage
}
class MessageAttribute : Attribute {
public MessageAttribute(MessageType type) {
Type = type;
}
public MessageType Type { get; private set; }
}
Second, you need compact serializer for your messages. One good option is protobuf - it it's very compact (does not serialize property names, only values and so on) while still easy to use.
[Message(MessageType.FirstMessage)]
[ProtoContract]
class MyFirstMessage {
[ProtoMember(1)]
public string Value { get; set; }
[ProtoMember(2)]
public int AnotherValue { get; set; }
}
[Message(MessageType.SecondMessage)]
[ProtoContract]
class MySecondMessage {
[ProtoMember(1)]
public decimal Stuff { get; set; }
}
Third you need to know the length of a message, as caller says you. Use 2 or 4 bytes for that (size of Int16 and Int32 types respectively).
So our format would be: 1 byte - message type. 2-5 bytes - message size, 5-5+size bytes - protobuf serialized message. Then read your stream in three steps, as defined below:
class MessageReader {
static readonly Dictionary<byte, Type> _typesMap = new Dictionary<byte, Type>();
static MessageReader() {
// initialize your map
// this is executed only once per lifetime of your app
foreach (var type in Assembly.GetExecutingAssembly().GetTypes().Where(c => c.GetCustomAttribute<MessageAttribute>() != null)) {
var message = type.GetCustomAttribute<MessageAttribute>();
_typesMap.Add((byte)message.Type, type);
}
}
public async Task<object> Read(Stream stream) {
// this is your network or any other stream you have
// read first byte - that is message type
var firstBuf = new byte[1];
if (await stream.ReadAsync(firstBuf, 0, 1) != 1) {
// failed to read - end of stream
return null;
}
var type = firstBuf[0];
if (!_typesMap.ContainsKey(type)) {
// unknown message, handle somehow
return null;
}
// read next 4 bytes - length of a message
var lengthBuf = new byte[4];
if (await stream.ReadAsync(lengthBuf, 0, 4) != 4) {
// read less than expected - EOF
return null;
}
var length = BitConverter.ToInt32(lengthBuf, 0);
// check if length is not too big here! or use 2 bytes for length if your messages allow that
if (length > 1*1024*1024) {
// for example - adjust to your needs
return null;
}
var messageBuf = new byte[length];
if (await stream.ReadAsync(messageBuf, 0, length) != length) {
// didn't read full message - EOF
return null;
}
try {
return ProtoBuf.Serializer.NonGeneric.Deserialize(_typesMap[type], new MemoryStream(messageBuf));
}
catch {
// handle invalid message somehow
return null;
}
}
}
After you read one message from stream - continue in the same way to read next message. Read calls will block until new data arrives. If there is any violation of protocol - drop connection.

Have you not considered using a TCPClient and TCPListener, and then a NetworkStream? Sockets are pretty low level and probably not needed in the majority of cases.
See this post:
How reading messages from server?(TCP)
Also, do not catch exceptions that you cannot recover from, unless you log and rethrow them. This will cause very hard to debug behaviors when exceptions get silently swallowed up.

Related

C# Stream Pipe (Stream Spy) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have an input stream and a stream reader component. This works fine but now I want to log all the traffic (save a copy in a file).
So I need to spy on a stream. A solution I am thinking of is a stream pipe (pipeline) or a stream wrapper that takes a stream as input and then gives me a first look at the traffic. Something like this:
void Init(System.Net.Sockets.NetworkStream stream)
{
System.IO.Stream wrappedStream = new MyWrapper(stream);
wrappedStream.ReadSpy = MyMethod;
XmlReader reader = XmlReader.Create(wrappedStream);
}
// This will get called after some bytes have been read from a stream,
// but before they get passed to the XmlReader
byte[] MyMethod(byte[] buffer)
{
m_Writer.Write(buffer); // write to a file
return buffer; // Give to XmlReader
}
What you want is called the Decorator Pattern. It's a technique for dynamically adding/modifying behavior:
http://sourcemaking.com/design_patterns/decorator
http://www.oodesign.com/decorator-pattern.html
To do this, you want to implement the abstract class Stream, with a constructor of factory that accepts another Stream instance. You provide an implementation for every method/overload of the abstract class that invokes the same method/overload on the decorated Stream, plus doing whatever additional work your needs require.
Once you've done that and decorated a Stream with your new decorator, It can be used interchangeably by anything else that accepts a Stream, including other similar decorators: decorators can even be nested, like layers of an onion to compose the behaviors you need.
Something like this:
class StreamInterceptor : Stream
{
public Stream DecoratedInstance { get; set; }
public event Action<byte[]> BytesRead;
public event Action<byte[]> BytesWritten;
public StreamInterceptor( Stream instance )
{
if ( instance == null ) throw new ArgumentNullException("instance");
this.DecoratedInstance = instance ;
return ;
}
public override bool CanRead
{
get { return DecoratedInstance.CanRead; }
}
public override bool CanSeek
{
get { return DecoratedInstance.CanSeek; }
}
public override bool CanWrite
{
get { return DecoratedInstance.CanWrite; }
}
public override void Flush()
{
DecoratedInstance.Flush();
return;
}
public override long Length
{
get { return DecoratedInstance.Length; }
}
public override long Position
{
get { return DecoratedInstance.Position; }
set { DecoratedInstance.Position = value; }
}
public override int Read( byte[] buffer , int offset , int count )
{
int bytesRead = DecoratedInstance.Read(buffer, offset, count);
// raise the bytes read event
byte[] temp = new byte[bytesRead];
Array.Copy(buffer,offset,temp,0,bytesRead);
BytesRead(temp);
return bytesRead;
}
public override long Seek( long offset , SeekOrigin origin )
{
return DecoratedInstance.Seek(offset, origin);
}
public override void SetLength( long value )
{
DecoratedInstance.SetLength(value);
return;
}
public override void Write( byte[] buffer , int offset , int count )
{
// raise the bytes written event
byte[] temp = new byte[count];
Array.Copy(buffer,offset,temp,0,count);
BytesWritten(temp);
DecoratedInstance.Write(buffer, offset, count);
return;
}
}
Once you have that, you can say something like this:
static void Main()
{
StreamInterceptor si = new StreamInterceptor(File.Open("foo.bar.txt",FileMode.Open,FileAccess.ReadWrite,FileShare.Read));
si.BytesRead += (bytes) => { Console.WriteLine("{0} bytes read", bytes.Length); } ;
si.BytesWritten += (bytes) => { Console.WriteLine("{0} bytes written", bytes.Length); } ;
Stream s = (Stream) si ;
DoSomethingUseful(s);
}
And your event handler will be invoked whenever somebody reads or writes from the stream.

how to serialize a custom object including Tcpclient (for chatroom userlist)

I've created a simple chatroom program .
Basic message sending and receiving works well on the client, and server,too.
But I want to broadcast the connection list to all users when any user leave.
I use a thread to handle this task.
private void monitorProc()
{
while(true)
{
try
{
int bytereads = 0;
byte[] buffer = new byte[4096];
bytereads = clientStream.Read(buffer, 0, buffer.Length);
updateMonitor(encoder.GetString(buffer), monitor);
}
catch
{
}
}
}
And I use this thread like this ...
monitorThread = new Thread(new ThreadStart(monitorProc));
monitorThread.Start();
And server is ...
private void broadcast(string message)
{
foreach (User user in userlist)
{
NetworkStream clientStream;
clientStream = user.Userclient.GetStream();
clientStream.Write(encoder.GetBytes(message), 0, 4096);
clientStream.Flush();
}
}
When server received message from client , it call this function , and then all user will
In that way , client will put the message when receive message from server.
I define a User class . It contain the following info...
[Serializable]
public class User
{
public enum stat
{
ALIVE,
DEAD
}
private string username;
private IPEndPoint userEP;
private TcpClient userclient;
private stat userstat;
public string Username { get; set; }
public IPEndPoint UserEP { get { return userEP; } }
public TcpClient Userclient { get { return userclient; } }
public stat Userstat { get; set; }
public User(TcpClient _userclient)
{
userclient = _userclient;
userstat = stat.ALIVE;
}
}
I use a list to store every user in server .
Question1: how to send the list to every client ?
(I know that serialization can help . But an error occurred when I use the following code to serialize the list...
foreach (User user in userlist) {
Stream statBroadcast = user.Userclient.GetStream();
var bin = new BinaryFormatter();
bin.Serialize(statBroadcast , userlist);
connlist.Items.Add(user.Username);
}
It said that I didn't mark TcpClient as serializable.
Question 2: If I can send custom object to client . How to send connection list and message at the same time ?
(If I define a function in client called "updateList" and it receive the data through stream . How to distinct from the data (whether message of connectionlist))

C# TCP Sending Generic Objects

Ok so I'm working on a simple data entry software for work, using a 3-tier architecture. What I'm doing is basically using a common dll file to store classes with fields that are filled out when a request to the server is initialized. I have various user controls set up to take care of different ui forms, this works just fine if I open a connection and send the object directly from the form itself, but that creates a lot of redundant code. So I thought, lets make a MasterControl and create a public Connect_To_Server method to send objects over and then process the information sent back. Only problem is it keeps freezing my server.
Here is the code for my MasterControl:
public void Connect_To_Server(object obj)
{
using (TcpClient tcpClient = new TcpClient())
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("10.20.51.251"), 57657);
try
{
tcpClient.Connect(endPoint);
NetworkStream clientStream = tcpClient.GetStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(clientStream, obj);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " - " + ex.StackTrace);
}
}
}
Of course it's going to be a bit more complex later on but just for testing I've made it simple. Then from one of my ControlForms I create an object from one of the classes listed in the Common.dll, assign it it's values and then pass it to the Connect_To_Server method.
For instance a couple classes from my Common.dll
[Serializable]
public class Switch_Request // Switch class contains an integer describing a boolean request
{
public int switchID { get; set; }
}
[Serializable]
public class Send_String_List // Returns a list of strings
{
public int switchID { get; set; }
public List<string> stringsList { get; set; }
}
On my Server's side:
private void bt_StartServer_Click(object sender, EventArgs e) // Starts the server listening for clients
{
Set_String("System: Starting Services.");
tm_ActiveTime.Start();
serverListener = new TcpListener(IPAddress.Any, port);
serverThread = new Thread(new ThreadStart(Listen_For_Clients));
serverThread.Start();
}
private void Listen_For_Clients() // Listens for incoming client connections then redirects
{
serverListener.Start();
Set_String("System: Listening for connections...");
while (true)
{
tcpClient = serverListener.AcceptTcpClient();
clientThread = new Thread(new ParameterizedThreadStart(Handle_Client_Communication));
clientThread.Start(tcpClient);
}
}
private void Handle_Client_Communication(object client) // Handles incoming client communications
{
TcpClient tempClient = (TcpClient)client;
clientStream = tempClient.GetStream();
object sentObjet = formatter.Deserialize(clientStream);
Type objectType = sentObjet.GetType();
else if(objectType == typeof(Switch_Request)) // Handle - Switch Request
{
Switch_Request switchRequest = (Switch_Request)sentObjet;
object obj = new object();
if (switchRequest.switchID == 1)
{
}
else if (switchRequest.switchID == 2)
{
}
else if (switchRequest.switchID == 3)
{
}
else if (switchRequest.switchID == 4)
{
}
else if (switchRequest.switchID == 5)
{
}
else if (switchRequest.switchID == 6)
{
Send_String_List sendStringList = new Send_String_List();
sendStringList.switchID = 6;
sendStringList.stringsList = Get_Users();
obj = sendStringList;
}
else if (switchRequest.switchID == 7)
{
}
else if (switchRequest.switchID == 8)
{
}
else if (switchRequest.switchID == 9)
{
}
else if (switchRequest.switchID == 10)
{
}
formatter.Serialize(clientStream, obj);
Now I know that the object is being sent and received on the other end, as I set a little text display to popup when the object arrives on the other end, and it displays the correct object and it's type just before the server freezes. I'm just not sure why it keeps seizing up....

Wait until i get the complete message i am using reactive library to get the data

I am using reactive library I observe the bytes and when I get them I publish them. I am unable to find out where I should wait to collect all the bytes. and then process them.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
obj.SignatureAvailable.ObserveOn(SynchronizationContext.Current).Subscribe(HandlePinsAvailable);
}
void HandlePinsAvailable(byte[] signBytes)
{
//here I will collect byte blocks.
//MessageBox.Show(Encoding.ASCII.GetString(signBytes));
}
}
public class SignatureListener
{
private Subject<byte[]> SignaturesAvailable = new Subject<byte[]>();
public IObservable<byte[]> SignatureAvailable { get { return SignaturesAvailable.AsObservable(); } }
private IDisposable SignatureSubscription;
public SignatureListener()
{
SignatureSubscription = HidUtility.Messages.Subscribe(HandlePinMessageBytes);
}
public void HandlePinMessageBytes(byte[] signatureBytes)
{
SignaturesAvailable.OnNext(sobj.RawData.ToArray());
}
public class data
{
public void get data()
{
private static Subject<byte[]> subject = new Subject<byte[]>();
public static IObservable<byte[]> Messages { get { return subject.AsObservable(); } }
subject.OnNext(bytes);//I have have the actuall blocks here.
}
I don't fully understand your question, so apologies if my answer is inappropriate.
I assume that what you have is a stream of Bytes that you are observing. This steam will 'chunk' bytes to you until you hit the end of the stream (like a FileStream).
If this is the case then you can just keep processing the bytes until the observable sequence completes.
var allBytes = new List<byte>();
org.SignatureAvailable.Subscribe(
chunk=>{allBytes.AddRange(chunk);}, //OnNext
()=>{/*Do something with allBytes list*/} //OnCompleted
);
The problem with this is that we have leaked this list out side of our asynchronous sequence. A better option maybe to use the Aggregate function
org.SignatureAvailable
.Aggregate(new List<byte>(), (acc, chunk)=>acc.AddRange(chunk))
This will now return you a single List<bytes> contianing all the bytes once the SignatureAvailable sequence OnCompletes. To keep the format consistent, you probably want to return bytes. I think your solution would look something like the following:
org.SignatureAvailable
.Aggregate(new List<byte>(), (acc, chunk)=>acc.AddRange(chunk))
.Select(list=>list.ToArray())
.ObserveOn(SynchronizationContext.Current)
.Subscribe(HandlePinsAvailable); //Will only get called once when the sequence completes will all bytes.
These links from my book may help:
Iterating over files:
http://introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html#CreatingYourOwnIterator
Aggregating :
http://introtorx.com/Content/v1.0.10621.0/07_Aggregation.html#BuildYourOwn

Passing object messages in Azure Queue Storage

I'm trying to find a way to pass objects to the Azure Queue. I couldn't find a way to do this.
As I've seen I can pass string or byte array, which is not very comfortable for passing objects.
Is there anyway to pass custom objects to the Queue?
Thanks!
You can use the following classes as example:
[Serializable]
public abstract class BaseMessage
{
public byte[] ToBinary()
{
BinaryFormatter bf = new BinaryFormatter();
byte[] output = null;
using (MemoryStream ms = new MemoryStream())
{
ms.Position = 0;
bf.Serialize(ms, this);
output = ms.GetBuffer();
}
return output;
}
public static T FromMessage<T>(CloudQueueMessage m)
{
byte[] buffer = m.AsBytes;
T returnValue = default(T);
using (MemoryStream ms = new MemoryStream(buffer))
{
ms.Position = 0;
BinaryFormatter bf = new BinaryFormatter();
returnValue = (T)bf.Deserialize(ms);
}
return returnValue;
}
}
Then a StdQueue (a Queue that is strongly typed):
public class StdQueue<T> where T : BaseMessage, new()
{
protected CloudQueue queue;
public StdQueue(CloudQueue queue)
{
this.queue = queue;
}
public void AddMessage(T message)
{
CloudQueueMessage msg =
new CloudQueueMessage(message.ToBinary());
queue.AddMessage(msg);
}
public void DeleteMessage(CloudQueueMessage msg)
{
queue.DeleteMessage(msg);
}
public CloudQueueMessage GetMessage()
{
return queue.GetMessage(TimeSpan.FromSeconds(120));
}
}
Then, all you have to do is to inherit the BaseMessage:
[Serializable]
public class ParseTaskMessage : BaseMessage
{
public Guid TaskId { get; set; }
public string BlobReferenceString { get; set; }
public DateTime TimeRequested { get; set; }
}
And make a queue that works with that message:
CloudStorageAccount acc;
if (!CloudStorageAccount.TryParse(connectionString, out acc))
{
throw new ArgumentOutOfRangeException("connectionString", "Invalid connection string was introduced!");
}
CloudQueueClient clnt = acc.CreateCloudQueueClient();
CloudQueue queue = clnt.GetQueueReference(processQueue);
queue.CreateIfNotExist();
this._queue = new StdQueue<ParseTaskMessage>(queue);
Hope this helps!
Extension method that uses Newtonsoft.Json and async
public static async Task AddMessageAsJsonAsync<T>(this CloudQueue cloudQueue, T objectToAdd)
{
var messageAsJson = JsonConvert.SerializeObject(objectToAdd);
var cloudQueueMessage = new CloudQueueMessage(messageAsJson);
await cloudQueue.AddMessageAsync(cloudQueueMessage);
}
I like this generalization approach but I don't like having to put Serialize attribute on all the classes I might want to put in a message and derived them from a base (I might already have a base class too) so I used...
using System;
using System.Text;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
namespace Example.Queue
{
public static class CloudQueueMessageExtensions
{
public static CloudQueueMessage Serialize(Object o)
{
var stringBuilder = new StringBuilder();
stringBuilder.Append(o.GetType().FullName);
stringBuilder.Append(':');
stringBuilder.Append(JsonConvert.SerializeObject(o));
return new CloudQueueMessage(stringBuilder.ToString());
}
public static T Deserialize<T>(this CloudQueueMessage m)
{
int indexOf = m.AsString.IndexOf(':');
if (indexOf <= 0)
throw new Exception(string.Format("Cannot deserialize into object of type {0}",
typeof (T).FullName));
string typeName = m.AsString.Substring(0, indexOf);
string json = m.AsString.Substring(indexOf + 1);
if (typeName != typeof (T).FullName)
{
throw new Exception(string.Format("Cannot deserialize object of type {0} into one of type {1}",
typeName,
typeof (T).FullName));
}
return JsonConvert.DeserializeObject<T>(json);
}
}
}
e.g.
var myobject = new MyObject();
_queue.AddMessage( CloudQueueMessageExtensions.Serialize(myobject));
var myobject = _queue.GetMessage().Deserialize<MyObject>();
In case the storage queue is used with WebJob or Azure function (quite common scenario) then the current Azure SDK allows to use POCO object directly. See examples here:
https://learn.microsoft.com/en-us/sandbox/functions-recipes/queue-storage
https://github.com/Azure/azure-webjobs-sdk/wiki/Queues#trigger
Note: The SDK will automatically use Newtonsoft.Json for serialization/deserialization under the hood.
I liked #Akodo_Shado's approach to serialize with Newtonsoft.Json. I updated it for Azure.Storage.Queues and also added a "Retrieve and Delete" method that deserializes the object from the queue.
public static class CloudQueueExtensions
{
public static async Task AddMessageAsJsonAsync<T>(this QueueClient queueClient, T objectToAdd) where T : class
{
string messageAsJson = JsonConvert.SerializeObject(objectToAdd);
BinaryData cloudQueueMessage = new BinaryData(messageAsJson);
await queueClient.SendMessageAsync(cloudQueueMessage);
}
public static async Task<T> RetreiveAndDeleteMessageAsObjectAsync<T>(this QueueClient queueClient) where T : class
{
QueueMessage[] retrievedMessage = await queueClient.ReceiveMessagesAsync(1);
if (retrievedMessage.Length == 0) return null;
string theMessage = retrievedMessage[0].MessageText;
T instanceOfT = JsonConvert.DeserializeObject<T>(theMessage);
await queueClient.DeleteMessageAsync(retrievedMessage[0].MessageId, retrievedMessage[0].PopReceipt);
return instanceOfT;
}
}
The RetreiveAndDeleteMessageAsObjectAsync is designed to process 1 message at time, but you could obviously rewrite to deserialize the full array of messages and return a ICollection<T> or similar.
That is not right way to do it. queues are not ment for storing object. you need to put object in blob or table (serialized).
I believe queue messgae body has 64kb size limit with sdk1.5 and 8kb wih lower versions.
Messgae body is ment to transfer crutial data for workera that pick it up only.

Categories

Resources