Archive

Posts Tagged ‘Code’

C# and Serializing Structs to byte arrays

July 2nd, 2009 10 comments

So I have a application in C# that is communicating to something else via UDP messages. The messages are byte packed arrays of data. There are several bytes of header and then N bytes of data whos format is described in the header. I might send several Ints, or a string, or whatever.

This is pretty easy to handle in C/C++ as you can get raw pointers to everything. So if each message type is a struct, I can get a char* to the address of the struct and just read N bytes and send that out.

The problem on the C# end is this isnt so easy. If I want to pull messages apart and put them back into structs I have to do this manually each multi byte field at a time. So I was left with a function call for each message type to serialize it, and then another to deserialize it, each one having to know exactly what was in each message, so if I changed a message I’d have to edit all the handling functions. What I needed was a way to jsut get the raw bytes the in the received array into a struct of the right type, and vice versa. Fortunately there are some tricky ways to make this super easy.

First, we have to make sure the structs we declare in C# and packed. Here is an example:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct msg1{
     int a;
     int b
     short c;
}

This will ensure there are no gaps between elements in the struct.

Next, we need a way to take an array of Bytes and copy it directly into the struct:

public static T DeserializeMsg< T >(Byte[] data) where T : struct
        {
            int objsize = Marshal.SizeOf(typeof(T));
            IntPtr buff = Marshal.AllocHGlobal(objsize);

            Marshal.Copy(data, 0, buff, objsize);

            T retStruct = (T)Marshal.PtrToStructure(buff, typeof(T));

            Marshal.FreeHGlobal(buff);

            return retStruct;
        }

Lets say we have a msg1 struct populated and we want to send that out over UDP. We need to serialize it back to raw bytes. This function will do just that:

public static Byte[] SerializeMessage< T >(T msg) where T : struct
        {
            int objsize = Marshal.SizeOf(typeof(T));
            Byte[] ret = new Byte[objsize];

            IntPtr buff = Marshal.AllocHGlobal(objsize);

            Marshal.StructureToPtr(msg, buff, true);

            Marshal.Copy(buff, ret, 0, objsize);

            Marshal.FreeHGlobal(buff);

            return ret;
        }

Thats it!

qrcode

Simple UDP

June 23rd, 2009 No comments

There are many reasons why you might need to send data or messages between devices on your network. Maybe you want to control a remote box, or you have a small linux setup running somewhere remotely and you want to sent and receive data. There are obviously several ways to do this, and one is using sockets and UDP.

This code came about when I needed to talk to an embeded CPU in a Xilinx FPGA. I have ethernet on the card as well, and the CPU is setup to handle it. I wanted to send control commands to the CPU from my Linux workstation to verify some functionality. To do this, I have two pieces of code: (1) a “server” that spins on the FPGA and receives the incoming messages, and a “client” app that can send a command to the “server”. This is a trvial example and the code is basic, but you can see how easy it would be to expand as needed.

The Client:

#include 
#include 
#include 
#include 
#include 

void die(char* msg) { perror(msg); exit(1); }

int main(int argc, char *argv[]) {
	int sock;
	struct sockaddr_in server;
	unsigned short int serverPort = 9999;

	sock= socket(AF_INET, SOCK_DGRAM, 0);
	if(sock < 0 ) die("failed to create socket");

	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr("127.0.0.1");
	server.sin_port = serverPort; .

	char msg[] = "Hello World. ";
	printf("We will send the message: \"%s\" to the server. \n", msg);

	if (sendto(socketDescriptor, msg, strlen(msg), 0, (struct sockaddr *) &server, sizeof(server)) < 0) {
                   die("failed to send message");
	}

	return 0;
}

And now the Server:

#include 
#include 
#include 
#include 
#include 
#include 

#define BUFFSIZE 255
void Die(char* msg) { perror(msg); exit(1); }

int main(int argc, char* argv[]){
	int sock;
	struct sockaddr_in echoserver;
	struct sockaddr_in echoclient;

	char buffer[BUFFSIZE];
	unsigned int echolen, serverlen, clientlen;
	int rec = 0;

	if(argc != 2){
		fprintf(stderr, "USAGE: %s
\n", argv[0]);
		exit(1);
	}

	/* create UDP socket */
	if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
		Die("failed to create socket");
	}

	memset(&echoserver, 0, sizeof(echoserver));
	echoserver.sin_family = AF_INET;
	echoserver.sin_addr.s_addr = htonl(INADDR_ANY);
	echoserver.sin_port = htons(atoi(argv[1]));

	serverlen = sizeof(echoserver);
	if(bind(sock, (struct sockaddr *) &echoserver, serverlen) < 0) {
		Die("failed to bind.");
	}

	while(1){

		clientlen = sizeof(echoclient);
		if((rec = recvfrom(sock, buffer, BUFFSIZE, 0, (struct sockaddr*)&echoclient, &clientlen)) < 0){
			Die("failed to rec mesg");
		}
		printf("client connected: %s\nData: %s\n\n", inet_ntoa(echoclient.sin_addr),buffer);

	}
}
Categories: C, Code, Embedded, Uncategorized, Xilinx Tags: , , , ,