日立扶梯項(xiàng)目功能測(cè)試
對(duì)于試用期新人來(lái)說(shuō)沒(méi)正事做,并不等于沒(méi)事做。一些練練手的東西還是源源不斷的。這兩天在搗鼓日立扶梯項(xiàng)目的一些功能。其實(shí)這項(xiàng)目還未正式簽約的,但一些功能上的實(shí)踐還是必須的。這項(xiàng)目是日立公司應(yīng)用于新品發(fā)布會(huì),運(yùn)用Flash動(dòng)態(tài)畫面,實(shí)時(shí)展示他們扶梯的安全性。日立對(duì)扶梯運(yùn)行狀況進(jìn)行實(shí)時(shí)監(jiān)控,將一些扶梯的運(yùn)行數(shù)據(jù)從服務(wù)端傳輸?shù)娇头耍簿褪瞧桨咫娔X。這是基于C/S模式的,F(xiàn)lash在這方面的應(yīng)用我也是首次嘗試。
Flash對(duì)實(shí)時(shí)數(shù)據(jù)傳輸提供了套接字連接,也即是Socket連接。AS3.0提供兩種不同類型的套接字連接,XML套接字連接的XMLSocket類和二進(jìn)制套接字連接的Socket類。對(duì)于我來(lái)說(shuō)如果服務(wù)器能發(fā)送XML數(shù)據(jù)過(guò)來(lái)當(dāng)然是最好的,但可惜服務(wù)器是傳輸十六進(jìn)制的數(shù)據(jù)的。相對(duì)XMLSocket來(lái)說(shuō),Socket數(shù)據(jù)處理更為底層,可操控范圍更大,但難度也較大。
對(duì)于實(shí)時(shí)傳輸數(shù)據(jù)有幾大有解決的問(wèn)題,如何持續(xù)正確連接,如何處理粘包,如何緩存數(shù)據(jù)等。正確連接,可以采用類似三次握手原則,服務(wù)端向服務(wù)器發(fā)起連接請(qǐng)求,服務(wù)器接收后返回一個(gè)驗(yàn)證碼,客服端接收到后確認(rèn)可以進(jìn)行連接,然后后向服務(wù)器發(fā)回一個(gè)指定的數(shù)據(jù),服務(wù)器確認(rèn)了數(shù)據(jù)的正確性再發(fā)送指令確認(rèn)客服端可以連接了。
Flash的Socket連接是基于TCP的,所以不存在掉包的情況,最要是如何解決粘包或斷包。從網(wǎng)上看到一些解決法案是服務(wù)器發(fā)送的數(shù)據(jù)在包頭上加上數(shù)據(jù)長(zhǎng)度信息,當(dāng)客服端接收到數(shù)據(jù)包,先讀取信息頭,讀取指示后面的數(shù)據(jù)有多大。如果已經(jīng)讀了信息頭,則看能不能收到滿足條件的字節(jié)數(shù),若數(shù)據(jù)流里的數(shù)據(jù)滿足條件,開(kāi)始讀數(shù)據(jù),如果數(shù)據(jù)流里還未滿足讀取數(shù)據(jù)條件,則繼續(xù)讀取數(shù)據(jù)。至于如何緩存數(shù)據(jù),最簡(jiǎn)單的就是將數(shù)據(jù)保存到數(shù)組中,不過(guò)如何在適當(dāng)?shù)臅r(shí)候讀取數(shù)組中的數(shù)據(jù)還未想到較好的辦法。
package { import flash.display.Sprite; import flash.net.Socket; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.events.ProgressEvent; import flash.events.Event; import flash.errors.IOError; import flash.events.MouseEvent; import flash.errors.EOFError; import flash.system.Security; import flash.utils.ByteArray; /** * * @author whk */ public class SocketExample extends Sprite { private var targetServer:String = "192.168.0.68"; //連接ip地址 private var port:uint = 9991; //連接端口 private var socket:Socket; private var str:String; private var response:String; private var msgLenMax:int; //收到的消息最大長(zhǎng)度 private var msgLen:int; //消息長(zhǎng)度 private var headLen:int; //消息頭長(zhǎng)度 private var isReadHead:Boolean; //是否已經(jīng)讀了消息頭 private var bytes:ByteArray; //所讀數(shù)據(jù)的緩沖數(shù)據(jù),讀出的數(shù)據(jù)放在這里 public function SocketExample() { isReadHead = true; headLen = 2; //2個(gè)字節(jié) msgLenMax = 4028; bytes = new ByteArray(); //Security.loadPolicyFile("socket://"+targetServer+":"+port); socket = new Socket(); btnSend.enabled = false; btnConnect.addEventListener(MouseEvent.CLICK, btnHandler); } /** * 處理按鈕事件 */ private function btnHandler(event:MouseEvent):void { switch (event.target.name) { case "btnConnect": btnLabel(); break; case "btnSend": sendRequest(); break; } } private function btnLabel():void { if (btnConnect.label == "連接" || btnConnect.label == "重新連接") { //注冊(cè)socket事件 configureListeners(); //進(jìn)行socket連接 connectToSocketServer(); } if (btnConnect.label == "關(guān)閉連接") { if (socket.connected) { socket.close(); btnConnect.label = "連接"; pringMessage("客服端已關(guān)閉連接"); } } } /** * 連接socket服務(wù)器 */ private function connectToSocketServer():void { try { socket.connect(targetServer, port); } catch (error:SecurityError) { pringMessage("SecurityError: " + error); } } private function configureListeners():void { socket.addEventListener(Event.CONNECT, connectHandler); socket.addEventListener(Event.CLOSE, closeHandler); socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); } /** * 連接成功 */ private function connectHandler(event:Event):void { btnSend.enabled = true; btnConnect.label = "關(guān)閉連接"; pringMessage("連接成功" + "\n" + "connectHandler: " + event + "\n"); btnSend.addEventListener(MouseEvent.CLICK, btnHandler); trace("connectHandler: " + event); trace(txtRead.text); } /** * 向服務(wù)器發(fā)送數(shù)據(jù) */ private function sendRequest():void { trace("sendRequest"); response = ""; //發(fā)送內(nèi)容 writeln("GET /"); } private function writeln(str:String):void { str += txtSend.text + "\n"; if (socket.connected) { try { //將UTF-8字符串寫入套接字 socket.writeInt(int(str)); txtRead.text += "發(fā)送數(shù)據(jù)的數(shù)據(jù):" + str; socket.flush(); } catch (error:IOError) { pringMessage("socket.flush error\n" + error); } } else { //進(jìn)行socket連接 connectToSocketServer(); } } /** * 接收數(shù)據(jù),并讀取 */ private function socketDataHandler(event:ProgressEvent):void { trace("socketDataHandler: " + event); readResponse(); } private function readResponse():void { try { //parseNetData(); var str:String = socket.readUTFBytes(socket.bytesAvailable); response += str; trace(response); //遍歷數(shù)據(jù)包 while (socket.bytesAvailable) { var data:int = socket.readByte(); trace(data); } txtRead.text += "接收的數(shù)據(jù):" + str + "\n"; } catch (error:IOError) { pringMessage("當(dāng)socket已關(guān)閉而去讀取時(shí)引發(fā)I/O 異常\n" + "socket.read error\n" + error); } catch (error:EOFError) { pringMessage("沒(méi)有數(shù)據(jù)可讀而讀取時(shí)引發(fā)EOF異常\n" + "socket.read error\n" + error); } } /** * 解析網(wǎng)絡(luò)數(shù)據(jù)流 * 根據(jù)信息頭長(zhǎng)度讀取數(shù)據(jù) */ private function parseNetData():void { //如果需要讀信息頭 if (isReadHead) { if (socket.bytesAvailable >= headLen) { //讀出指示后面的數(shù)據(jù)有多大 msgLen = socket.readShort(); isReadHead = false; } } //如果已經(jīng)讀了信息頭,則看能不能收到滿足條件的字節(jié)數(shù) if (!isReadHead && msgLen <= msgLenMax) { //如果為0,表示收到異常消息 if (msgLen == 0) { //一般消息長(zhǎng)度為0的話,表示與服務(wù)器出了錯(cuò),或者即將被斷開(kāi)等,通知客戶端,進(jìn)行特別處理 return; } //數(shù)據(jù)流里的數(shù)據(jù)滿足條件,開(kāi)始讀數(shù)據(jù) if (socket.bytesAvailable >= msgLen) { //指針回歸 bytes.position = 0; //取出指定長(zhǎng)度的網(wǎng)絡(luò)字節(jié) socket.readBytes(bytes, 0, msgLen); isReadHead = true; } } //如果數(shù)據(jù)流里還滿足讀取數(shù)據(jù)條件,繼續(xù)讀取數(shù)據(jù) if (socket.bytesAvailable >= headLen) { parseNetData(); } } /** * socket服務(wù)器關(guān)閉連接 */ private function closeHandler(event:Event):void { btnConnect.label = "重新連接"; pringMessage("socke服務(wù)器已關(guān)閉\n" + "closeHandler: " + event); trace("closeHandler: " + event); } private function ioErrorHandler(event:IOErrorEvent):void { trace("ioErrorHandler: " + event); pringMessage("輸入/輸出錯(cuò)誤并導(dǎo)致發(fā)送或加載操作失敗\n" + "ioErrorHandler: " + event); } private function securityErrorHandler(event:SecurityErrorEvent):void { trace("securityErrorHandler: " + event); pringMessage("嘗試連接到調(diào)用方安全沙箱外部的服務(wù)器或端口號(hào)低于 1024 的端口\n" + "securityErrorHandler: " + event); } /** * 將消息打印到屏幕 * @param m:打印的消息 */ private function pringMessage(m:String = null):void { txtError.visible = true; if (m == null) { txtError.text = ""; txtError.visible = false; return; } if (txtError.text == null) { txtError.text = ""; txtError.visible = false; } txtError.text = m; } } } |
Socket三次握手例子:
package { import flash.display.Sprite; import flash.events.ProgressEvent; import flash.net.Socket; import flash.utils.ByteArray; /** * * 三次握手連接socket * 來(lái)源socket編程 */ public class SocketHandshake extends Sprite { public const DETERMINE_VERSION:int = 0; public const RECEIVE_CHALLENGE:int = 1; public const NORMAL:int = 2; private var stateMap:Object; private var currentState:int; private var socket:Socket; public function SocketHandshake( ) { stateMap = new Object( ); stateMap[DETERMINE_VERSION] = readVersion; stateMap[RECEIVE_CHALLENGE] = readChallenge; stateMap[NORMAL] = readNormalProtocol; currentState = DETERMINE_VERSION; socket = new Socket( ); socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData ); socket.connect( "localhost", 9000 ); trace(currentState); } private function onSocketData( event:ProgressEvent ):void { trace(currentState); var processFunc:Function = stateMap[currentState]; processFunc( ); } private function readVersion( ):void { try { var version:int = socket.readInt(); trace(version); } catch (error:Error) { trace("error:"+error); } currentState = RECEIVE_CHALLENGE; socket.writeInt( version ); socket.flush( ); } private function readChallenge( ):void { var bytes:ByteArray = new ByteArray( ); socket.readBytes( bytes, 0, 8 ); currentState = NORMAL; socket.writeBytes( bytes ); socket.flush( ); } private function readNormalProtocol( ):void { } } } |
posted on 2012-09-10 10:01 順其自然EVO 閱讀(210) 評(píng)論(0) 編輯 收藏