As3 Socket通信

Home / Article MrLee 2016-9-5 3119

最近研究了下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事件

本文链接:https://www.it72.com/10022.htm

推荐阅读
最新回复 (0)
返回