Search code examples
c#actionscript-3apache-flexsocketsair

Send file from C# Server to AS3 AIR Clients using Sockets in a Local Network - with sample


I want to send a file from a C# server to a AS3 Flash Client. My C# server code for sending the file is something like this:

IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 5656);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
sock.Bind(ipEnd);
sock.Listen(100);
//clientSock is the socket object of client, so we can use it now to transfer data to client
Socket clientSock = sock.Accept();

// This part gets the file and send the data in bytearray
byte[] fileData = File.ReadAllBytes("send/mypicture.jpg");
clientSock.Send(fileData);

Now I need a as3 client. I found this: http://flasharp.blogspot.pt/2010/03/socket-serverclient-chat.html and I constructed something like this:

public function Main():void {
    ...
    socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
    ...
}

function onResponse(e:ProgressEvent):void {
    var file:File;
    var fs:FileStream;
    var fileData:ByteArray = new ByteArray();

    // Check if socket has data
    if(socket.bytesAvailable > 0) {
        while(socket.bytesAvailable) {
            // read the socket data into the fileData
            socket.readBytes(fileData,0,0);
        }
    }
    file = File.documentsDirectory.resolvePath("teste.jpg");
    fs = new FileStream();
    fs.open(file, FileMode.WRITE);
    // Writing the file
    fs.writeBytes(fileData);
    fs.close();
}

I've managed to send and receive a file, but it only saves up to 50kbs, anything bigger and you just gest a file with that size.

Any thoughts on how to transfer a file with any size?


Solution

  • I managed to solve this and updated this post with a sample.

    UPDATED & SOLVED: I wanted to send files from a C# server to AS3 Clients using sockets in a Local Network. I had some trouble finding out how to do it, but I managed to do so.

    Server (C#):
    1 - I create a TcpListener that listens for new clients with any IP in that network to the specified port number;
    2 - When a new client connects I create a Thread to handle it;
    3 - In that Thread I send the data I want to. In this case that data is divided in two parts, the first is a 4 bytearray that contains the size of the file I want to send, and the second is a bytearray of the file itself;
    4 - After the data is sent I close that client connection;

    Client (AS3):
    1 - First of all I convert my bytearrays to LITTLE_ENDIAN, since AIR is by default BIG_ENDIAN and the data I get from the server is LITTLE_ENDIAN;
    2 - Add the events to the socket connection and conect to the server;
    3 - On the onResponse function I receive the socket packages to a bytearray;
    4 - Save that bytearray into a file;

    The last part on the client was the trickiest one, because it took me some time to figure out that AIR is BIG_ENDIAN by default, and how to read the packages. So basically, what I do is, on the first package that comes in I read the first 4 bytes to a bytearray and then convert that to an int, which gives me my total file size. I use this to know when there are no more packages to receive and therefore finish the connection and save the file. The rest of the first package and subsequent packages are added to a bytearray that will store that file data itself. The workaround here is to start writing on the beggining the first time a package is received and then add the subsequent packages where the last one left off, i.e., first time I write from the 0 to 65321, second one I'll have to write from the 65321 to XXXX, and so on.

    The file is being saved to the MyDocuments folder.

    I'm unsure if this is the best method to do this, since I'm rather new to socket connection, however this works for me and I tested with files up to 165MB and it works. It supports multiple client connections and is pretty basic, but this is a starting point, not a finish line.

    I hope this can help others as it helped me, since I did not find anything like it on the web (regarding file transfer not C# -> AS3 connection).

    If someone wants to input some info or needs clarification on something, please feel free to ask.

    Last but no least, sample can be downloaded here: http://sdrv.ms/W5mSs9 (Server in C# Express 2010 and Client in Flash Builder 4.6 with Flex SDK 4.6.0)

    In case the sample in the link above ever dies out here is the

    ActionScript 3 Source Code:

    package
    {
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.events.ProgressEvent;
        import flash.events.SecurityErrorEvent;
        import flash.filesystem.File;
        import flash.filesystem.FileMode;
        import flash.filesystem.FileStream;
        import flash.net.Socket;
        import flash.system.Security;
        import flash.utils.ByteArray;
        import flash.utils.Endian;
        import flash.text.TextField;
    
        public class FileTransferLocal extends Sprite
        {
            private var socket:Socket = new Socket();
            private var file:File;
            private var fs:FileStream = new FileStream();
            private var fileData:ByteArray = new ByteArray();
            private var fileSize:ByteArray = new ByteArray();
    
            private var fileDataPosition:int = new int();
            private var fileDataFlag:int = new int();
            private var fileSizeFlag:int = new int();
            private var fileSizeCounter:int = new int();
    
            private var fileDataPreviousPosition:int = new int();
    
            private var myText:TextField = new TextField();
    
    
            public function FileTransferLocal()
            {           
                try {Security.allowDomain("*");}catch (e) { };
    
                // Convert bytearray to Little Endian
                fileSize.endian = Endian.LITTLE_ENDIAN;
                fileData.endian = Endian.LITTLE_ENDIAN;
                socket.endian = Endian.LITTLE_ENDIAN;
    
                fileSizeFlag = 0;
                fileDataFlag = 0;
    
                myText.width = 150;
                myText.height = 150;
                myText.x = 200;
                myText.y = 200;
    
                socket.addEventListener(Event.CONNECT, onConnect);
                socket.addEventListener(Event.CLOSE, onClose);
                socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
                socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
                socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecError);
    
                // Put the IP and port of the server
                socket.connect("10.1.1.211", 5656);
            }
    
            private function onConnect(e:Event):void {
                trace("onConnect\n");
            }
    
            private function onClose(e:Event):void {
                trace("onClose");
                socket.close();
            }
    
            private function onError(e:IOErrorEvent):void {
                trace("IO Error: "+e);
            }
    
            private function onSecError(e:SecurityErrorEvent):void {
                trace("Security Error: "+e);
            }
    
            private function onResponse(e:ProgressEvent):void {         
    
                if(!fileSizeFlag) {
                    socket.readBytes(fileSize, 0, 4);
                    fileSize.position = 0;
                    fileSizeFlag = 1;
                    fileSizeCounter = fileSize.readInt();
                    trace("fileSizeCounter -> " + fileSizeCounter);
                }
    
                trace("---- New package ----> " + socket.bytesAvailable);
    
                if(fileSizeCounter > 0) {
                    fileSizeCounter -= socket.bytesAvailable;
    
                    if(fileDataPosition != 0) {
                        fileDataPreviousPosition += fileDataPosition;
                    }
    
                    if(fileData.length == 0) {
                        fileDataPreviousPosition = socket.bytesAvailable;
                        socket.readBytes(fileData, 0, socket.bytesAvailable);
                    } else {
                        fileDataPosition = socket.bytesAvailable;
                        socket.readBytes(fileData, fileDataPreviousPosition, socket.bytesAvailable);
                    }
                }
    
                // Saves the file
                if(fileSizeCounter == 0) {
                    trace("File total size" + fileData.length);
                    file = File.documentsDirectory.resolvePath("test.mp3");
                    fs.open(file, FileMode.WRITE);
                    fs.writeBytes(fileData);
                    fs.close();
    
                    myText.text = "File successefully\nreceived!";
                    addChild(myText);
    
                }
                // Is still receiving packages
                else {
                    myText.text = "Receiving file...";
                    addChild(myText);
                }
    
            }
        }
    }
    

    In C# create a new Windows Application
    add a
    ListBox call it statusList
    Label call it port
    Label call it status

    C# Source code in Sample Above:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Net.Sockets;
    using System.Threading;
    using System.Net;
    using System.IO;
    using System.Reflection;
    
    namespace ServerThread
    {
        public partial class ServerThread : Form
        {
            private TcpListener tcpListener;
            private Thread listenThread;
    
            public ServerThread()
            {
                InitializeComponent();
    
                // Port number
                int portNumber = 5656;
                port.Text = portNumber.ToString();
    
                // Create a TcpListener to cover all existent IP addresses with that port
                this.tcpListener = new TcpListener(IPAddress.Any, portNumber);
                // Create a Thread to listen to clients
                this.listenThread = new Thread(new ThreadStart(ListenForClients));
                this.listenThread.Start();
    
            }
    
            private void ListenForClients()
            {
                this.tcpListener.Start();
    
                while (true)
                {
                    // Blocks until a client has conected to the server
                    TcpClient client = this.tcpListener.AcceptTcpClient();
    
                    // Create a Thread to handle the conected client communication
                    Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                    clientThread.Start(client);
                }
            }
    
            private void HandleClientComm(object client)
            {
                // Receive data
                TcpClient tcpClient = (TcpClient)client;
                NetworkStream clientStream = tcpClient.GetStream();
    
                while (true)
                {
                    try
                    {
                        // Sending data
                        string filePath = "send/mysong.mp3"; // Your File Path;
                        byte[] fileData = File.ReadAllBytes(filePath); // The size of your file
                        byte[] fileSize = BitConverter.GetBytes(fileData.Length); // The size of yout file converted to a 4 byte array
                        byte[] clientData = new byte[fileSize.Length + fileData.Length]; // The total byte size of the data to be sent
    
                        fileSize.CopyTo(clientData, 0); // Copy to the file size byte array to the sending array (clientData) beginning the in the 0 index
                        fileData.CopyTo(clientData, 4); // Copy to the file data byte array to the sending array (clientData) beginning the in the 4 index
    
                        // Send the data to the client
                        clientStream.Write(clientData, 0, clientData.Length);
                        clientStream.Flush();
    
    
                        // Debug for the ListBox
                        if (statusList.InvokeRequired)
                        {
                            statusList.Invoke(new MethodInvoker(delegate {
                                statusList.Items.Add("Client IP: " + tcpClient.Client.RemoteEndPoint.ToString());
                                statusList.Items.Add("Client Data size: " + clientData.Length);
                            }));
                        }
    
                    }
                    catch
                    {
                        // 
                        break;
                    }
    
                    if (statusList.InvokeRequired)
                    {
                        statusList.Invoke(new MethodInvoker(delegate
                        {
                            statusList.Items.Add("File successefully sent!");
                        }));
                    }
    
                    // Close the client
                    tcpClient.Close();
                }
    
            }
        }
    }