Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# send structure objects through socket

Tags:

c#

tcp

sockets

i have done a bit of reading in client/server programming in c#. i am familiar enough with this process to ask the following question:

how do i transmit structure objects through tcp/ip instead of just strings?

my app is a networked game with chat capabilities. so instead of just transmitting text, i would like to imploy a data structure or class structure that will have two fields: i. packet type ii. the data for the packet type

and i would transmit this when needed during the execution of the application, and decode the data object at the receiving end and place it where it belongs.

im not looking for code, just some ideas and search statements i can feed to google so i will; have a better understanding.

ive read about serialisation/de serialisation, is that he way to go?

thanks.


i have checked the posts that showed up as related topics but would still like further guidence.


like image 689
iTEgg Avatar asked Dec 18 '09 17:12

iTEgg


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

Ultimately yes: you are talking about serialization. This can take many forms, especially in .NET, but ultimately you need to pick between:

  • text vs binary; direct binary tends to be smaller than text, as it usually involves less parsing etc; text (xml, json, etc) is usually represented in the stream as UTF8 (although any encoding is possible). They are broadly human-readable, and despite being more verbose can usually be compressed pretty well.
  • contract vs metadata; contract-based serializers focus on representing data - it is assumed that the other end of the pipe understands the structure, but it is not assumed that they share an implementation. This has limitations in that you can't suddenly introduce some completely unexpected subclass, but makes it platform-independent. By contrast, metadata-based serializers send the type information on the stream (i.e. "this is a My.Namespace.FooBar instance). This makes it really easy to get working, but rarely works between different platforms (and often not between versions) - and all that type information can be verbose
  • manual vs automatic; fact: manual serializers can often be the most efficient in terms of bandwidth, since you can hand-customise the heck out of the stream - but it takes lots of effort and you need to understand serialization lots. Automatic serializers are much better for general purpose uses (in reality: most scenarios). Avoid manual unless you have no choice. Automatic serializers handle all the complexities of worrying about different types of data, etc.

Manual serializer approaches include (just mentioning the "serializer" keyword): TextWriter, XmlWriter, IXmlSerializable, BinaryWriter, ISerializable. You don't want to do that...

Focusing more on the automatic serializers:

               | Contract               | Metadata
===============+========================+===========================
  Text         | XmlSerializer          | SoapFormatter
               | DataContractSerializer | NetDataContractSerializer
               | Json.NET               |
---------------+------------------------+---------------------------
  Binary       | protobuf-net           | BinaryFormatter

Since you are talking raw streams, my preference would be a binary contract-based serializer - but then, I wrote protobuf-net, so I may be biased ;-p

For comparison with common RPC stacks:

  • "remoting" uses BinaryFormatter
  • "asmx" web-services (including WSE*) use XmlSerializer
  • WCF can use many, most commonly DataContractSerializer or NetDataContractSerializer, and sometimes XmlSerializer (it can also be configured to use, for example, protobuf-net)

I can happily write an example of using protobuf-net on a stream to represent different messages of different types, but a simple example of socket processing using protobuf-net is in one of the sample projects (here, in fact)

like image 150
Marc Gravell Avatar answered Sep 28 '22 03:09

Marc Gravell


If you don't need the richness of serialization - if you just wanna write a structure to a byte array, consider the Marshal class.

For example, consider a tar app in C#. The tar format is based on 512-byte blocks, and the first block in a series has a regular structure. Ideally the app wants to just blitt the data from the disk file, right into a structure. The Marshal.PtrToStructure method does this. Here's the structure.

    [StructLayout(LayoutKind.Sequential, Size=512)]
    internal struct HeaderBlock
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        public byte[]   name;    // name of file. 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   mode;    // file mode

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   uid;     // owner user ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   gid;     // owner group ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   size;    // length of file in bytes

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   mtime;   // modify time of file

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   chksum;  // checksum for header

        // ... more like that... up to 512 bytes. 

Then here's a generic class that does the blitting.

internal class RawSerializer<T>
{
    public T RawDeserialize( byte[] rawData )
    {
        return RawDeserialize( rawData , 0 );
    }    

    public T RawDeserialize( byte[] rawData , int position )
    {
        int rawsize = Marshal.SizeOf( typeof(T) );
        if( rawsize > rawData.Length )
            return default(T);

        IntPtr buffer = Marshal.AllocHGlobal( rawsize );
        Marshal.Copy( rawData, position, buffer, rawsize );
        T obj = (T) Marshal.PtrToStructure( buffer, typeof(T) );
        Marshal.FreeHGlobal( buffer );
        return obj;
    }

    public byte[] RawSerialize( T item )
    {
        int rawSize = Marshal.SizeOf( typeof(T) );
        IntPtr buffer = Marshal.AllocHGlobal( rawSize );
        Marshal.StructureToPtr( item, buffer, false );
        byte[] rawData = new byte[ rawSize ];
        Marshal.Copy( buffer, rawData, 0, rawSize );
        Marshal.FreeHGlobal( buffer );
        return rawData;
    }
}

You can use that class with any structure. You have to use LayoutKind.Sequential and restrict yourself to blittable types (basically primitives and arrays of same) to use this approach. It's fast and efficient, in terms of code and performance and memory, but it's a little restricted in how it can be used.

Once you have the byte array, you can transmit it over a NetworkStream or etc, and then de-serialize using the same class on the other end.

like image 33
Cheeso Avatar answered Sep 28 '22 01:09

Cheeso