Sign in to follow this  
Subotron

Sending an exe file over network using asynchronous c# sockets

Recommended Posts

I'm writing a client-server application using c# asynchronous sockets where the client receives the latest update from the server when logging on. Everything so far works great, but when I try to send the exe file something goes wrong. The data gets send, but on the other end it appears to be broken or something. This is what I do: Server side: Open file to be sended in binary mode, read the whole file (I am sure I read all the bytes in the file). Convert the read bytes to a string and send it in parts to the client (parts because my message struct has a fixed length for the data being sent). All parts seem to get sent, and they should arrive in order (I hold a message queue so messages are sent in order, because even though I use TCP they didn't seem to without the queue). When all parts are sent the server sends an 'update finished' message. Client side: Receive all the parts of the update (they all seem to arrive), translate the data string back to a byte array and append it to the file in binary mode (if file doesn't exist on first update message it is created). Everything SEEMS to work fine, but I sent a 20 kb file, and the file that is created is only 1 kb. Plus, the contents don't seem right, even though I know nothing of interpreting a binary file, the contents certainly don't match. Here is the relevant code. If other code is needed, please tell me. (A DataMessage is a sequential struct with header (string of size 128) and data (string of size 256) Server:
public void Send( State client, DataMessage msg )
{
	byte[] bytes = RawSerialize.ToBytes( msg );

	if( client.sendQueue.Count <= 0 )
	{
		client.sendQueue.Enqueue( msg );
		client.Socket.BeginSend( bytes, 0, bytes.Length, 0, new AsyncCallback( OnDataSend ), client );
	}
	else
	{
		if ( client.sendQueue.Peek().header == msg.header && client.sendQueue.Peek().data == msg.data )
		{
			client.Socket.BeginSend( bytes, 0, bytes.Length, 0, new AsyncCallback( OnDataSend ), client );
		}
		else
		{
			client.sendQueue.Enqueue( msg );
		}
	}
}

// Relevant sending part:

FileStream		fs		= File.OpenRead( "update.exe" );
BinaryReader	br		= new BinaryReader( fs );
byte[]			bytes	= br.ReadBytes( Convert.ToInt32( fs.Length ) );
String			data	= Encoding.UTF8.GetString( bytes ); // Tried UTF8 and ASCII here

for ( int i = 0; i < fs.Length; i += 256 )
{
	Send( state, new DataMessage( "Update", data.Substring( 0, 256 ) ) );
}

br.Close();
fs.Close();

Send( state, new DataMessage( "Update finished", "" ) );

Client:
// Relevant receiving part:

case "Update":
	using ( FileStream fs = new FileStream( "Data/update.exe", FileMode.Append ) )
	{
		using ( BinaryWriter bw = new BinaryWriter( fs ) )
		{
			bw.Write( Encoding.UTF8.GetBytes( msg.data ) ); // Encoding always matches the one the server used
		}
	}
	break;

case "Update finished":
	Process.Start( "ClientUpdater.exe" ); // Not really relevant anymore
	break;

Any guess what's going wrong? Or maybe there's a better alternative?

Share this post


Link to post
Share on other sites
Its been a while since I read my autoupdate code, but I think the translation of the data into string format is what your problem is.
You should just be able to read the binary data into a byte array, then pass and send the byte array without any translation. You can either preappend the size of the data packet or use an end of file tag to read the file full tcp data stream. Also keep in mind you will not be able to overwrite the currently running exe.

Here is a link to a code project sample of file transfers using sockets.

http://www.codeproject.com/KB/cs/SocketApplication.aspx

Share this post


Link to post
Share on other sites
thanks for the amazingly fast response :)

you might very well be right, I do the translation because most messages should in fact be strings, but I guess I will have to alter my whole 'DataMessage' approach. I will definetly check out that article! Thanks a lot, ++rating obviously :)

Share this post


Link to post
Share on other sites
There are ways to encode binary data in strings, but you have to encode them in such a way that the binary data is properly preserved.

I'm not an expert in this area, so I don't know what solution is best for this, but I believe
Base 64 Encoding is one method of doing this.

I think this is the method that was, or is used when sending binary files through e-mail.

Share this post


Link to post
Share on other sites
I agree with the suggestion to send data as binary data. You shouldn't translate it to string.

You can download a tool like MinSys or Cygwin which gives you command-line tools for Windows. Then you can use tools like "cmp" to compare the source and destination files, to figure out where the difference is. Use a hex editor to inspect the before- and after-files, to try to figure out where things are going wrong.

Share this post


Link to post
Share on other sites
Quote:
Original post by keshtath
I think you can use windiff to compare also.
WinDiff can only display diffs of text files. But it can tell you if binary files differ or not.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this