As3 Socket通信

最近研究了下as3 Socket 跟Java服务器的通信,一些心得分享下。

客户端的代码如下:

package com
{
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.utils.Endian;
    import flash.utils.setTimeout;
    /**
     * ...
     * @author me
     */
    public class connection
    {
        private static const SERVER_URL:String = "localhost";
        private static const PORT:int = 10002;
        
        private static var ip:int = 1;
        
        private static var _instance:connection;
        
        private var _socket:Socket;
        
        private static const checkNum:uint = 0;
        
        public function connection()
        {
            if (_instance)
            {
                throw new Error("Single");
            }
            initSocket();
        }
        
        public function initSocket():void
        {
            if (_socket == null)
            {
                _socket = new Socket(SERVER_URL, PORT);
                _socket.timeout = 2000;
                _socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
                _socket.addEventListener(ProgressEvent.SOCKET_DATA, onProgress);
            }
        }
        
        public function connectServer():void
        {
            if (_socket.connected == false)
            {
                _socket.connect(SERVER_URL, PORT);
            }
            else
            {
                trace("has connected the server");
            }
        }
        
        public function read():void
        {
            connectServer();
        }
        
        public function write(bytes:ByteArray):void
        {
            connectServer();
            _socket.writeUnsignedInt(ip++); //
            _socket.writeDouble(10.444);
            _socket.writeUnsignedInt(4355);
            if (bytes)
            {
                _socket.writeBytes(bytes, 0, bytes.length);
            }
            _socket.writeMultiByte("Hello Java啊啊", "GBK");
            
            _socket.flush();
        }
        
        private function onError(e:Event):void
        {
            trace(e.type + ", " + e.toString());
        }
        
        private function onProgress(e:ProgressEvent):void
        {
            //setTimeout(deal, 0.00000000000000000000000000000000000000000000000000001);
            deal();
        }
        
        private function deal():void
        {
            var index:int = -1;
            if (_socket.bytesAvailable >= 30)
            {
                //dealString();
                index = _socket.readUnsignedInt();
                ondeal(index);
            }
        }
        
        private function ondeal(index:int):void
        {
            trace("Send to client --> " + index);
            var cmd:int = _socket.readUnsignedInt();
            trace("cmd -----> " + cmd);
            switch(index)
            {
                case 1:
                    break;
                case 2:
                    var len:int = _socket.bytesAvailable;
                    len = _socket.readUnsignedInt();
                    trace("服务器发的包的长度-- > " + len);
                    var bytes:ByteArray = getByteArray();
                    _socket.readBytes(bytes, 0, len);
                    var str:String = bytes.readMultiByte(len, "GBK");
                    bytes.position = 0;
                    trace(str);
                    break;
            }
        }
        
        private function dealString():void
        {
            var i:int = _socket.bytesAvailable;
                var str:String = "";
                while (i-- > 0)
                {
                    var value:int;
                    
                        value = _socket.readByte();
                    if (value != 0)
                    {
                        str += String.fromCharCode(value);
                    }
                }
                trace(str);
        }
        
        private function getByteArray():ByteArray
        {
            var byteArray:ByteArray = new ByteArray();
            byteArray.endian = Endian.LITTLE_ENDIAN;
            byteArray.position = 0;
            return byteArray;
        }
        
        public function get socket():Socket
        {
            return _socket;
        }
        
        static public function get instance():connection
        {
            if (_instance == null)
            {
                _instance = new connection();
            }
            return _instance;
        }
    }

}

 

Java服务器端的代码如下:

package test;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketExample {

    public static final int PROT = 10002;
    
    private static ServerSocket serverSocket;
    private static Socket socket;
    
    private static DataInputStream input;
    private static DataOutputStream output;
    
    @SuppressWarnings("unused")
    private static OutputStreamWriter outputStreamWriter;
    private static InputStreamReader inputStreamReader;
    
    
    private static char []bytes = new char[1024 * 3];
    
    public static void main(String[] args) throws IOException
    {
        SocketExample example = new SocketExample();
        example.initSocket();
        example.read();
    }
    
    private void initSocket() throws IOException
    {
        serverSocket = new ServerSocket(PROT);
        System.out.println("start: " + serverSocket);
        socket = serverSocket.accept();
        input = new DataInputStream(socket.getInputStream());
        output = new DataOutputStream(socket.getOutputStream());
        outputStreamWriter = new OutputStreamWriter(output, "GBK");
        inputStreamReader = new InputStreamReader(input,"GBK");
    }
    
    private void read() throws IOException
    {
        while(true)
        {
            try {
                try {
                    int cmd = input.readInt();
                    System.out.println("As3 send a CMD number: " + cmd);
                    double i = input.readDouble();
                    System.out.println(i);
                    int j = input.readInt();
                    System.out.println(j);
                    
                    int len = inputStreamReader.read(bytes, 0, 100);
                    
                    String string = "-->";
                    string += new String(bytes, 0, len);
                    System.out.println(string);
                    write(2, "Hello as3  你好啊啊\n你大爷的啊啊啊".getBytes("GBK"), cmd);
                    output.flush();
                    
                } catch (Exception e) {
                    // TODO: handle exception
                }
                finally
                {
    //                socket.close();
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
            finally
            {
    //            serverSocket.close();
            }
        }
    }
    
    private void write(int index, byte bytes[], int cmd) throws IOException
    {
        System.out.println("Send to client --> " + index);
        output.writeInt(index);
        output.writeInt(cmd);
        
//        output.flush();
        switch (index) {
        case 1:
            
            break;
        case 2:
            if(bytes != null)
            {
                output.writeInt(bytes.length);
                System.out.println("发送的数据包长度--> " + bytes.length);
                output.write(bytes);
//                output.flush();
            }
            break;
        default:
            break;
        }
        
        output.flush();
    }
    
    @SuppressWarnings("unused")
    private void closeSocket() throws IOException
    {
        serverSocket.close();
        socket.close();
    }
}

刚开始的时候as3读取包的时候直接readInt()等读的,遇到了一些莫名其妙的问题,不是遇到文件尾,就是读出了一系列乱七八糟的数据,但是调用setTimeout过段时间再读的话,不管这个时间有多小,例如上面的0....1,都会读取正确。后来断点看了一下,每次读的时候_socket的bytesAvailable即服务器发的包长度在不断的变化,很多情况下都是比服务器发的长度小,这样用字节流读取的话肯定就会遇到文件尾的错误了。因此在as3 Socket通信中读取服务器数据的时候一定要验证服务器包的完整性,即在代码中:

if (_socket.bytesAvailable >= 30)
            {
                //dealString();
                index = _socket.readUnsignedInt();
                ondeal(index);
            }

当客户端收到的包的长度>=服务器所发的包的长度时,再读取一次,而不是一收到数据就立即读取。但是相反的是,Java代码可以直接读取的,为什么是这样暂时没有搞清楚,看来还是要仔细学习一下TCP/IP通信。

 

究其原因,应该是AS3每收到一次服务器发的数据,即一串二进制流吧,就会派发ProgressEvent.SOCKET_DATA事件,但同一时间收到的并不是一个完整的通信包,而只是一部分,大概就相当于加载进度条了,每加载一部分就会派发事件,而不是加载完成才派发,加载完成派发Event.COMPLETED事件

posted @ 2014-04-03 10:26  chinayfhuang  阅读(2513)  评论(0编辑  收藏  举报