├── LICENSE ├── README.md ├── as_src ├── Demo.as └── u14 │ └── udpx │ ├── IntHelper.as │ ├── Seq.as │ ├── UxEvent.as │ ├── UxSocket.as │ └── frames │ ├── ACKFrame.as │ ├── DATFrame.as │ ├── EAKFrame.as │ ├── FINFrame.as │ ├── Frame.as │ ├── LIVFrame.as │ └── SYNFrame.as └── java_src ├── Demo.java └── u14 └── udpx ├── InetAddressUtils.java ├── Seq.java ├── UdpListener.java ├── UdpSocket.java ├── UdpWorkThread.java ├── UxServer.java ├── UxServerInnerSocket.java ├── UxSocket.java ├── UxSocketListener.java ├── UxSocketStat.java ├── frames ├── ACKFrame.java ├── DATFrame.java ├── EAKFrame.java ├── FINFrame.java ├── Frame.java ├── LIVFrame.java ├── SEE └── SYNFrame.java ├── think.txt └── tick ├── TickHelper.java └── TickThreadFactory.java /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UdpX 2 | ============= 3 | 4 | a reliable udp, dev by java as3 go 5 | 6 | 可靠UDP传输,基于java as3 go实现 7 | 8 | -------------------------------------------------------------------------------- /as_src/Demo.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Sprite; 4 | import flash.events.Event; 5 | import flash.net.DatagramSocket; 6 | import flash.utils.ByteArray; 7 | import flash.utils.setTimeout; 8 | 9 | import u14.udpx.Seq; 10 | import u14.udpx.UxEvent; 11 | import u14.udpx.UxSocket; 12 | import u14.udpx.frames.SYNFrame; 13 | 14 | public class Demo extends Sprite 15 | { 16 | private var socket:UxSocket; 17 | public function Demo() 18 | { 19 | // var socket:DatagramSocket = new DatagramSocket(); 20 | // socket.connect("127.0.0.1", 8008); 21 | // for(var i=0;i<20;i++){ 22 | // var bytes:ByteArray = new ByteArray(); 23 | // bytes.writeUTFBytes("hi-server@"+i); 24 | // socket.send(bytes); 25 | // } 26 | socket = new UxSocket(); 27 | socket.addEventListener(UxEvent.CONNECT, onConnect); 28 | socket.addEventListener(UxEvent.IOERROR, onError); 29 | socket.addEventListener(UxEvent.CLOSE, onClose); 30 | socket.addEventListener(UxEvent.DATA, onData); 31 | socket.connect("127.0.0.1", 8008); 32 | } 33 | 34 | protected function onData(event:UxEvent):void 35 | { 36 | var bytes:ByteArray = event.data; 37 | trace("on-data:"+bytes); 38 | } 39 | protected function onClose(event:UxEvent):void 40 | { 41 | trace("connect-close:"+event.data); 42 | } 43 | protected function onError(event:UxEvent):void 44 | { 45 | trace("connect-error:"+event.data); 46 | } 47 | protected function onConnect(event:UxEvent):void 48 | { 49 | trace("connect-ok"); 50 | send(); 51 | setTimeout(send,1000); 52 | } 53 | 54 | private function send():void 55 | { 56 | for(var i:int=0;i<100;i++){ 57 | socket.sendData(toBuf("rp-msg-fjpiwhpqirupq83ww.biblegateway.com/passage/?search=Psalm+62%3A5-12&version=NLTCommonww.biblegateway.com/passage/?search=Psalm+62%3A5-12&version=NLTCommon people are as worthlerpss as a puff of wind,and the powerful are not w people are as worthrpless as a puff of wind,and the powerful are not w7897408qyp8hfpuihapiyuu89r7098270598y708ehyphuihaufhuwnvm,nznknv;kaj;iamspeankinghanwensimidaoooaifwjjjjxxxxooooppppkkkkjpqiejporhpquhudhfahhelloworld,imzhanghengsimida-jdiqiurhas~~@@##"+i)); 58 | } 59 | } 60 | 61 | private function toBuf(s:String):flash.utils.ByteArray 62 | { 63 | var b:ByteArray = new ByteArray(); 64 | b.writeUTFBytes(s); 65 | b.position = 0; 66 | return b; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/IntHelper.as: -------------------------------------------------------------------------------- 1 | package u14.udpx 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | public final class IntHelper 6 | { 7 | private static var bytes:ByteArray = new ByteArray(); 8 | public static function byte(n:int):int{ 9 | bytes.position=0; 10 | bytes.writeByte(n); 11 | bytes.position=0; 12 | return bytes.readByte(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/Seq.as: -------------------------------------------------------------------------------- 1 | package u14.udpx 2 | { 3 | public class Seq 4 | { 5 | private var _num:int=0; 6 | private var _lastInNum:int=0; 7 | 8 | public function Seq() 9 | { 10 | } 11 | 12 | public function next():int{ 13 | return (_num = Seq.next(_num)); 14 | } 15 | public function get num():int{ 16 | return _num; 17 | } 18 | public function initNum():int{ 19 | var n:int=Math.floor(Math.random()*MAX_SEQ/2); 20 | return (_num = n); 21 | // return (num=0); 22 | } 23 | 24 | public function set lastInNum(n:int):void{ 25 | _lastInNum = n; 26 | } 27 | public function get lastInNum():int{ 28 | return _lastInNum; 29 | } 30 | 31 | private static const MAX_SEQ:int = 255; 32 | /** 33 | * Computes the consecutive sequence number. 34 | * @return the next number in the sequence. 35 | */ 36 | public static function next(n:int):int 37 | { 38 | return (n + 1) % MAX_SEQ; 39 | } 40 | /** 41 | * Compares two sequence numbers. 42 | * @return 0, 1 or -1 if the first sequence number is equal, 43 | * greater or less than the second sequence number. 44 | * (see RFC 1982). 45 | */ 46 | public static function compare(a:int, b:int):int 47 | { 48 | if (a == b) { 49 | return 0; 50 | }else if (((a < b) && ((b - a) > MAX_SEQ/2)) || 51 | ((a > b) && ((a - b) < MAX_SEQ/2))) { 52 | return 1; 53 | }else { 54 | return -1; 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/UxEvent.as: -------------------------------------------------------------------------------- 1 | package u14.udpx 2 | { 3 | import flash.events.Event; 4 | 5 | public class UxEvent extends Event 6 | { 7 | public static const IOERROR:String = "ioerror"; 8 | public static const CLOSE:String = "close"; 9 | public static const CONNECT:String = "connect"; 10 | public static const DATA:String = "data"; 11 | 12 | public var data:*; 13 | 14 | public function UxEvent(type:String, data:*=null) 15 | { 16 | super(type); 17 | this.data = data; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/UxSocket.as: -------------------------------------------------------------------------------- 1 | package u14.udpx 2 | { 3 | import flash.desktop.NativeApplication; 4 | import flash.events.DatagramSocketDataEvent; 5 | import flash.events.Event; 6 | import flash.events.EventDispatcher; 7 | import flash.events.IOErrorEvent; 8 | import flash.events.ProgressEvent; 9 | import flash.events.TimerEvent; 10 | import flash.net.DatagramSocket; 11 | import flash.utils.ByteArray; 12 | import flash.utils.Timer; 13 | import flash.utils.clearTimeout; 14 | import flash.utils.setTimeout; 15 | 16 | import u14.udpx.frames.ACKFrame; 17 | import u14.udpx.frames.DATFrame; 18 | import u14.udpx.frames.EAKFrame; 19 | import u14.udpx.frames.FINFrame; 20 | import u14.udpx.frames.Frame; 21 | import u14.udpx.frames.LIVFrame; 22 | import u14.udpx.frames.SYNFrame; 23 | 24 | /** 25 | * 建立连接成功 26 | * */ 27 | [Event(name="connect", type="u14.udpx.UxEvent")] 28 | /** 29 | * 建立连接失败 30 | * */ 31 | [Event(name="ioerror", type="u14.udpx.UxEvent")] 32 | /** 33 | * 连接关闭 34 | * */ 35 | [Event(name="close", type="u14.udpx.UxEvent")] 36 | /** 37 | * 收到数据 38 | * */ 39 | [Event(name="data", type="u14.udpx.UxEvent")] 40 | 41 | public class UxSocket extends EventDispatcher 42 | { 43 | private static const MaxFrameSize:int = 255; 44 | private static const MaxInQueueSize:int = 32; 45 | private static const MaxSynQueueSize:int = 32; 46 | private static const MaxRewriteNum:int = 8; 47 | private static const INTERVAL_HEART:int = 50; 48 | private static const INTERVAL_ALIVE:int = 90; 49 | private static const SendTimeOut:int = 2500; 50 | 51 | private static const INIT:int = 0; 52 | private static const CONNECT:int = 1; 53 | private static const WORK:int = 2; 54 | private static const CLOSED:int = 3; 55 | 56 | private var seq:Seq; 57 | private var socket:DatagramSocket; 58 | private var address:String; 59 | private var port:int; 60 | 61 | private var stat:int=0; 62 | 63 | private var inQueue:Vector.; 64 | private var synQueue:Vector.; 65 | private var outQueue:Vector.; 66 | 67 | private var closeInfo:String; 68 | private var timer:Timer; 69 | //多久未收到数据后断开 70 | private var heart_remote:int=0; 71 | //多久未写数据后,发alive 72 | private var heart_local:int=0; 73 | private var retry_interval:int=0; 74 | 75 | public function UxSocket() 76 | { 77 | seq = new Seq(); 78 | timer = new Timer(100); 79 | timer.addEventListener(TimerEvent.TIMER, this.onIntervalTick); 80 | 81 | inQueue = new Vector.(); 82 | synQueue = new Vector.(); 83 | outQueue = new Vector.(); 84 | 85 | socket = new DatagramSocket(); 86 | socket.receive(); 87 | 88 | } 89 | 90 | protected function onIntervalTick(event:TimerEvent):void 91 | { 92 | heart_remote++; 93 | heart_local++; 94 | if(heart_remote>INTERVAL_ALIVE){ 95 | this.closeInfo = "RemoteDead"; 96 | this.close(); 97 | return; 98 | } 99 | if(heart_local>INTERVAL_HEART){ 100 | heart_local=0; 101 | this.sendFrame(new LIVFrame(Seq.next(seq.lastInNum))); 102 | // trace("check:"+(outQueue.length)+"_"+synQueue.length+"_"+inQueue.length); 103 | } 104 | retry_interval++; 105 | if(retry_interval%2==0){ 106 | for each(var f:Frame in synQueue){ 107 | reSendFrame(f); 108 | if(connected==false){ 109 | break; 110 | } 111 | } 112 | } 113 | } 114 | private var connectTimerId:uint; 115 | public function connect(address:String, port:int):void{ 116 | if(this.stat==CONNECT){ 117 | return; 118 | } 119 | this.stat = CONNECT; 120 | this.address = address; 121 | this.port = port; 122 | this.sendFrameImp(new SYNFrame(seq.initNum())); 123 | this.socket.addEventListener(DatagramSocketDataEvent.DATA, onConnectData); 124 | connectTimerId=setTimeout(onConnectTimeout, 5000); 125 | } 126 | 127 | private function onConnectTimeout():void 128 | { 129 | this.socket.removeEventListener(DatagramSocketDataEvent.DATA, onConnectData); 130 | this.dispatchEvent(new UxEvent(UxEvent.IOERROR,address+":"+port+" Connect Timeout Error!")); 131 | } 132 | protected function onConnectData(event:DatagramSocketDataEvent):void 133 | { 134 | this.socket.removeEventListener(DatagramSocketDataEvent.DATA, onConnectData); 135 | var f:Frame = Frame.parse(event.data); 136 | if(f is ACKFrame){ 137 | if(f.ack==seq.num){ 138 | this.stat = WORK; 139 | this.seq.lastInNum = f.seq(); 140 | this.onOpen(); 141 | } 142 | } 143 | if(!connected){ 144 | this.dispatchEvent(new UxEvent(UxEvent.IOERROR,address+":"+port+" Connect Error!")); 145 | } 146 | NativeApplication.nativeApplication.addEventListener(Event.EXITING, onAppExit); 147 | } 148 | 149 | protected function onAppExit(event:Event):void 150 | { 151 | this.close(); 152 | } 153 | 154 | private function onOpen():void 155 | { 156 | clearTimeout(connectTimerId); 157 | synQueue.length=0;inQueue.length=0;outQueue.length=0; 158 | this.socket.addEventListener(DatagramSocketDataEvent.DATA, onPacketData); 159 | this.dispatchEvent(new UxEvent(UxEvent.CONNECT)); 160 | this.timer.start(); 161 | } 162 | 163 | public function get connected():Boolean{ 164 | return this.stat==WORK; 165 | } 166 | private function resetLiv(remote:Boolean):void{ 167 | if(remote){ 168 | heart_remote=0; 169 | }else{ 170 | heart_local=0; 171 | } 172 | } 173 | private function reciveData(f:DATFrame):void{ 174 | this.dispatchEvent(new UxEvent(UxEvent.DATA,f.getData())); 175 | } 176 | protected function onPacketData(event:DatagramSocketDataEvent):void 177 | { 178 | var frame:Frame = Frame.parse(event.data); 179 | if(frame==null)return; 180 | resetLiv(true); 181 | if(frame is FINFrame){ 182 | if(stat==WORK){ 183 | this.sendFrameImp(new ACKFrame(seq.num, frame.seq())); 184 | this.closeInfo = "RemoteClose"; 185 | this.close(); 186 | } 187 | return; 188 | }else if(frame is LIVFrame){ 189 | }else if(frame is DATFrame){ 190 | 191 | var compareRet:int = Seq.compare(frame.seq(), Seq.next(seq.lastInNum)); 192 | // trace(compareRet+":"+frame.seq()+"_"+seq.lastInNum + 193 | // " : "+new String(frame.getBytes())); 194 | if(compareRet==0){ 195 | seq.lastInNum = frame.seq(); 196 | reciveData(DATFrame(frame)); 197 | if(this.inQueue.length>0){ 198 | for each(var f:Frame in inQueue){ 199 | if(f.seq()==frame.seq()){ 200 | delList.push(f); 201 | }else if(Seq.compare(f.seq(), Seq.next(seq.lastInNum))==0){ 202 | delList.push(f); 203 | seq.lastInNum = frame.seq(); 204 | reciveData(DATFrame(frame)); 205 | } 206 | } 207 | delFrames(inQueue); 208 | } 209 | this.sendAck(); 210 | } 211 | else if(compareRet>0){ 212 | var add:Boolean = true; 213 | if(inQueue.length==0){ 214 | // System.out.println("add-frame:"+frame.seq()+"_in("+seq.getLastInNum()+")"); 215 | inQueue.push(frame); 216 | this.sendAck(); 217 | }else if(inQueue.length = (EAKFrame(frame)).getACKs(); 239 | for each(f in synQueue){ 240 | if(f.seq()==frame.ack){ 241 | delList.push(f); 242 | }else{ 243 | for each(var ack:int in acks){ 244 | if(f.seq()==ack){ 245 | delList.push(f); 246 | break; 247 | } 248 | } 249 | } 250 | } 251 | var delFlag:Boolean = delList.length>0; 252 | delFrames(synQueue); 253 | 254 | var in_last_seq:int = frame.ack; 255 | var out_last_seq:int = acks[acks.length-1]; 256 | for each(f in synQueue){ 257 | if(Seq.compare(f.seq(), in_last_seq)<0){ 258 | delList.push(f); 259 | continue; 260 | } 261 | } 262 | delFlag = delFlag || delList.length>0; 263 | delFrames(synQueue); 264 | 265 | for each(f in synQueue){ 266 | if(Seq.compare(in_last_seq, f.seq())<0 && Seq.compare(out_last_seq, f.seq())>0){ 267 | reSendFrame(f); 268 | if(!connected){ 269 | break; 270 | } 271 | } 272 | } 273 | if(connected && delFlag){ 274 | sendOutQueue(); 275 | } 276 | } 277 | if(frame.ack>=0){ 278 | for each(f in synQueue){ 279 | if(Seq.compare(f.seq(),frame.ack)<=0){ 280 | delList.push(f); 281 | } 282 | } 283 | if(delList.length>0){ 284 | delFrames(synQueue); 285 | sendOutQueue(); 286 | } 287 | } 288 | } 289 | 290 | public function close():void{ 291 | if(stat!=CLOSED){ 292 | var s:int = stat; 293 | stat = CLOSED; 294 | clearTimeout(connectTimerId); 295 | this.socket.removeEventListener(DatagramSocketDataEvent.DATA, onPacketData); 296 | NativeApplication.nativeApplication.removeEventListener(Event.EXITING, onAppExit); 297 | this.timer.stop(); 298 | if(s==WORK){ 299 | this.sendFrameImp(new FINFrame(seq.next())); 300 | this.dispatchEvent(new UxEvent(UxEvent.CLOSE, closeInfo)); 301 | } 302 | } 303 | } 304 | 305 | private function reSendFrame(f:Frame):void 306 | { 307 | if(connected==false)return; 308 | if(f.reWriteNum()>MaxRewriteNum){ 309 | this.closeInfo = "MaxRetry"; 310 | this.close(); 311 | }else{ 312 | f.reWriteNum(); 313 | sendFrame(f); 314 | } 315 | } 316 | private function sendAck():void 317 | { 318 | if(inQueue.length==0){ 319 | sendFrameImp(new ACKFrame(Seq.next(seq.lastInNum), seq.lastInNum)); 320 | }else{ 321 | var acks:Vector. = new Vector.(inQueue.length); 322 | for(var i:int=0;i = new Vector.(); 329 | private function delFrames(q:Vector.):void 330 | { 331 | for each(var f:Frame in delList){ 332 | var idx:int = q.indexOf(f); 333 | if(idx>=0){ 334 | q.splice(idx,1); 335 | } 336 | } 337 | delList.length = 0; 338 | } 339 | public function sendData(buf:ByteArray, offset:int=0, length:int=0):void{ 340 | length = length==0?buf.length:length; 341 | var s:int = length-offset; 342 | if(s<=0 )return; 343 | if(s<225){ 344 | sendSynFrame(new DATFrame(seq.next(), -1, buf, offset, length)); 345 | return; 346 | } 347 | var totalBytes:int = 0; 348 | while (totalBytes < length) { 349 | var writeBytes:int = Math.min(MaxFrameSize - Frame.HEADER_LEN, length - totalBytes); 350 | sendSynFrame(new DATFrame(seq.next(), 351 | seq.lastInNum, buf, offset + totalBytes, writeBytes)); 352 | totalBytes += writeBytes; 353 | } 354 | } 355 | private function sendOutQueue():void{ 356 | if(outQueue.length>0){ 357 | while(synQueue.length0?_dataLength:_data.length) + super.length(); 23 | } 24 | 25 | override public function type():String 26 | { 27 | return "DAT"; 28 | } 29 | 30 | public function getData():ByteArray 31 | { 32 | return _data; 33 | } 34 | 35 | override public function getBytes():ByteArray 36 | { 37 | var buffer:ByteArray = super.getBytes(); 38 | buffer.writeBytes(_data, _dataOffset, _dataLength); 39 | return buffer; 40 | } 41 | 42 | override protected function parseBytes(buffer:ByteArray, off:int, len:int):void 43 | { 44 | super.parseBytes(buffer, off, len); 45 | _data = new ByteArray();//new byte[len - HEADER_LEN]; 46 | off = off+HEADER_LEN; 47 | len = len>0?len-HEADER_LEN:0; 48 | _data.writeBytes(buffer, off, len); 49 | _data.position = 0; 50 | } 51 | private var _dataOffset:int=0; 52 | private var _dataLength:int=0; 53 | private var _data:ByteArray; 54 | } 55 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/frames/EAKFrame.as: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | public class EAKFrame extends Frame 6 | { 7 | public function EAKFrame(seqn:int=-1, ackn:int=-1, acks:Vector.=null) 8 | { 9 | init(EAK_FLAG, seqn, HEADER_LEN + acks.length); 10 | this.ack = (ackn); 11 | _acks = acks; 12 | } 13 | 14 | override public function type():String 15 | { 16 | return "EAK"; 17 | } 18 | 19 | override public function getBytes():ByteArray 20 | { 21 | var buf:ByteArray = super.getBytes(); 22 | for(var i:int=0;i 29 | { 30 | return _acks; 31 | } 32 | 33 | override protected function parseBytes(buffer:ByteArray, off:int, len:int):void 34 | { 35 | super.parseBytes(buffer, off, len); 36 | _acks = new Vector.(length() - HEADER_LEN); 37 | for (var i:int = 0; i < _acks.length; i++) { 38 | _acks[i] = buffer[off + HEADER_LEN + i];//(buffer[off + HEADER_LEN + i] & 0xFF); 39 | } 40 | } 41 | 42 | private var _acks:Vector.; 43 | } 44 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/frames/FINFrame.as: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames 2 | { 3 | public class FINFrame extends Frame 4 | { 5 | public function FINFrame(seqn:int=-1) 6 | { 7 | init(FIN_FLAG, seqn, HEADER_LEN); 8 | } 9 | override public function type():String 10 | { 11 | return "FIN"; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/frames/Frame.as: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames 2 | { 3 | import flash.utils.ByteArray; 4 | 5 | import u14.udpx.IntHelper; 6 | import u14.udpx.Seq; 7 | 8 | public class Frame 9 | { 10 | public static function Comparator(a:Frame, b:Frame):int{ 11 | return Seq.compare(a.seq(), b.seq()); 12 | } 13 | 14 | public static const SYN_FLAG:int = IntHelper.byte(0x80); 15 | public static const ACK_FLAG:int = IntHelper.byte(0x40); 16 | public static const EAK_FLAG:int = IntHelper.byte(0x20); 17 | public static const LIV_FLAG:int = IntHelper.byte(0x08); 18 | // public static byte CHK_FLAG = IntHelper.byte(0x04); 19 | public static const FIN_FLAG:int = IntHelper.byte(0x02); 20 | 21 | public static const HEADER_LEN:int = 4; 22 | 23 | private var _flag:int; 24 | private var _len:int; 25 | private var _seq:int; 26 | private var _ack:int=-1; 27 | 28 | private var _reWriteNum:int=0; 29 | 30 | public function Frame() 31 | { 32 | } 33 | 34 | public function type():String{ 35 | return "ABS"; 36 | } 37 | 38 | public function flag():int{ 39 | return _flag; 40 | } 41 | public function seq():int{ 42 | return _seq; 43 | } 44 | public function length():int{ 45 | return _len; 46 | } 47 | public function get ack():int{ 48 | return _ack; 49 | } 50 | public function set ack(n:int):void{ 51 | _ack = n; 52 | } 53 | 54 | public function incrReWriteNum():int{ 55 | _reWriteNum++; 56 | return _reWriteNum; 57 | } 58 | public function reWriteNum():int{ 59 | return _reWriteNum; 60 | } 61 | 62 | public function getBytes():ByteArray 63 | { 64 | var buffer:ByteArray = new ByteArray(); 65 | // buffer[0] = (byte) (flag & 0xFF); 66 | // buffer[1] = (byte) (len & 0xFF); 67 | // buffer[2] = (byte) (seq & 0xFF); 68 | // buffer[3] = (byte) (ack & 0xFF); 69 | buffer.writeByte(_flag&0xFF); 70 | buffer.writeByte(_len&0xFF); 71 | buffer.writeByte(_seq&0xFF); 72 | buffer.writeByte(_ack&0xFF); 73 | return buffer; 74 | } 75 | public function toString():String 76 | { 77 | return type() + 78 | " [" + 79 | " SEQ = " + seq() + 80 | ", ACK = " + ((ack >= 0) ? ""+ack : "N/A") + 81 | ", LEN = " + length() + 82 | " ]"; 83 | } 84 | protected function init(flag:int, seq:int, len:int):void 85 | { 86 | this._flag = flag; 87 | this._seq = seq; 88 | this._len = len; 89 | } 90 | protected function parseBytes(buffer:ByteArray, off:int, len:int):void 91 | { 92 | this._flag = buffer[off];//(buffer[off] & 0xFF); 93 | this._len = buffer[off+1];//(buffer[off+1] & 0xFF); 94 | this._seq = buffer[off+2];//(buffer[off+2] & 0xFF); 95 | this._ack = buffer[off+3];//(buffer[off+3] & 0xFF); 96 | } 97 | public static function parse(bytes:ByteArray, off:int=0, len:int=-1):Frame 98 | { 99 | if(len==-1){ 100 | len = bytes.length; 101 | } 102 | if (len < HEADER_LEN) { 103 | // throw new IllegalArgumentException("Invalid segment"); 104 | return null; 105 | } 106 | var segment:Frame = null; 107 | var flags:int = IntHelper.byte(bytes[off]&0xFF); 108 | if ((flags & SYN_FLAG) != 0) { 109 | segment = new SYNFrame(); 110 | } 111 | else if ((flags & LIV_FLAG) != 0) { 112 | segment = new LIVFrame(); 113 | } 114 | else if ((flags & EAK_FLAG) != 0) { 115 | segment = new EAKFrame(); 116 | } 117 | else if ((flags & FIN_FLAG) != 0) { 118 | segment = new FINFrame(); 119 | } 120 | else if ((flags & ACK_FLAG) != 0) { /* always process ACKs or Data segments last */ 121 | if (len == HEADER_LEN) { 122 | segment = new ACKFrame(); 123 | } 124 | else { 125 | segment = new DATFrame(); 126 | } 127 | } 128 | 129 | if (segment == null) { 130 | throw new Error("Invalid segment"); 131 | } 132 | 133 | segment.parseBytes(bytes, off, len); 134 | return segment; 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/frames/LIVFrame.as: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames 2 | { 3 | public class LIVFrame extends Frame 4 | { 5 | public function LIVFrame(seqn:int=-1) 6 | { 7 | init(LIV_FLAG, seqn, HEADER_LEN); 8 | } 9 | 10 | override public function type():String 11 | { 12 | return "LIV"; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /as_src/u14/udpx/frames/SYNFrame.as: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames 2 | { 3 | public class SYNFrame extends Frame 4 | { 5 | public function SYNFrame(seqn:int=-1) 6 | { 7 | init(SYN_FLAG, seqn, HEADER_LEN); 8 | } 9 | 10 | override public function type():String 11 | { 12 | return "SYN"; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /java_src/Demo.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | 6 | public class Demo { 7 | private static UxServer server; 8 | public static void testServer() throws IOException{ 9 | server = new UxServer().bind(new InetSocketAddress(8008)).listen(new UxSocketListener() { 10 | @Override 11 | public void onOpen(UxSocket socket) { 12 | System.out.println("on-socket-open:"+socket.address()); 13 | try { 14 | socket.sendData("https://www.biblegateway.com/passage/?search=Psalm+62%3A5-12&version=NLTCommon people are as worthless as a puff of wind,and the powerful are not what they appear to be.Don’t make your living by extortiondon’t make it the center of your life.God has spoken plainlyPower, O God, belongs to you".getBytes()); 15 | } catch (IOException e) { 16 | e.printStackTrace(); 17 | } 18 | } 19 | @Override 20 | public void onData(UxSocket socket, byte[] data) { 21 | System.out.println("on-socket-data:"+socket.address()+"->"+new String(data)); 22 | if(new String(data).startsWith("rp")){ 23 | try { 24 | socket.sendData(data); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | for(UxSocket s: server.clients()){ 30 | try { 31 | s.sendData(data); 32 | } catch (IOException e) { 33 | // TODO Auto-generated catch block 34 | e.printStackTrace(); 35 | } 36 | } 37 | } 38 | @Override 39 | public void onClose(UxSocket socket) { 40 | System.out.println("on-socket-close:"+socket.address()+ socket.closeInfo()); 41 | } 42 | }); 43 | System.out.println("server"); 44 | } 45 | public static void testClient() throws IOException{ 46 | UxSocket socket = new UxSocket(); 47 | socket.listen(new UxSocketListener() { 48 | @Override 49 | public void onOpen(UxSocket socket) { 50 | System.out.println("on-open"); 51 | try { 52 | socket.sendData("hi123456".getBytes()); 53 | socket.sendData("woabc".getBytes()); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | @Override 59 | public void onData(UxSocket socket, byte[] data) { 60 | System.out.println("on-data:"+new String(data)); 61 | } 62 | @Override 63 | public void onClose(UxSocket socket) { 64 | System.out.println("on-close-"+ socket.closeInfo()); 65 | } 66 | }) 67 | .connect(new InetSocketAddress("127.0.0.1",8008)); 68 | // .connect(new InetSocketAddress("s1.gz.1251014155.clb.myqcloud.com", 8008)); 69 | try { 70 | Thread.sleep(1000L); 71 | for(int i=0;i<1000;i++){ 72 | socket.sendData(("rp-msgat:"+i).getBytes()); 73 | Thread.sleep(10L); 74 | } 75 | Thread.sleep(300000L); 76 | System.exit(0); 77 | } catch (InterruptedException e) { 78 | // TODO Auto-generated catch block 79 | e.printStackTrace(); 80 | } 81 | } 82 | public static void main(String[] args) throws IOException { 83 | boolean serverAble = args.length==1 && args[0].equals("1"); 84 | if(args.length==0)serverAble=true; 85 | if(serverAble){ 86 | testServer(); 87 | }else{ 88 | testClient(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /java_src/u14/udpx/InetAddressUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ==================================================================== 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * ==================================================================== 20 | * 21 | * This software consists of voluntary contributions made by many 22 | * individuals on behalf of the Apache Software Foundation. For more 23 | * information on the Apache Software Foundation, please see 24 | * . 25 | * 26 | */ 27 | 28 | package u14.udpx; 29 | 30 | import java.util.regex.Pattern; 31 | 32 | 33 | /** 34 | * A collection of utilities relating to InetAddresses. 35 | * 36 | * @since 4.0 37 | */ 38 | public class InetAddressUtils { 39 | 40 | private InetAddressUtils() { 41 | } 42 | 43 | private static final Pattern IPV4_PATTERN = 44 | Pattern.compile( 45 | "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$"); 46 | 47 | private static final Pattern IPV6_STD_PATTERN = 48 | Pattern.compile( 49 | "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$"); 50 | 51 | private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = 52 | Pattern.compile( 53 | "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$"); 54 | 55 | public static boolean isIPv4Address(final String input) { 56 | return IPV4_PATTERN.matcher(input).matches(); 57 | } 58 | 59 | public static boolean isIPv6StdAddress(final String input) { 60 | return IPV6_STD_PATTERN.matcher(input).matches(); 61 | } 62 | 63 | public static boolean isIPv6HexCompressedAddress(final String input) { 64 | return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches(); 65 | } 66 | 67 | public static boolean isIPv6Address(final String input) { 68 | return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /java_src/u14/udpx/Seq.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | 4 | public class Seq { 5 | 6 | 7 | private volatile int num=0; 8 | private int lastInNum=0; 9 | // private int ackNum=0; 10 | 11 | public Seq() { 12 | } 13 | 14 | public int next(){ 15 | return (num = next(num)); 16 | } 17 | public int num(){ 18 | return num; 19 | } 20 | public int initNum(){ 21 | return (num = (new java.util.Random()).nextInt(MAX_SEQ/2)); 22 | // return (num=0); 23 | } 24 | 25 | public int setLastInNum(int n){ 26 | return (lastInNum = n); 27 | } 28 | public int getLastInNum(){ 29 | return lastInNum; 30 | } 31 | 32 | // public int incrActNum(){ 33 | // return ackNum++; 34 | // } 35 | // public int getActNum(){ 36 | // return ackNum; 37 | // } 38 | // public int resetActNum(){ 39 | // return ackNum=0; 40 | // } 41 | 42 | private static final int MAX_SEQ = 255; 43 | /** 44 | * Computes the consecutive sequence number. 45 | * @return the next number in the sequence. 46 | */ 47 | public static int next(int n) 48 | { 49 | return (n + 1) % MAX_SEQ; 50 | } 51 | /** 52 | * Compares two sequence numbers. 53 | * @return 0, 1 or -1 if the first sequence number is equal, 54 | * greater or less than the second sequence number. 55 | * (see RFC 1982). 56 | */ 57 | public static int compare(int a, int b) 58 | { 59 | if (a == b) { 60 | return 0; 61 | }else if (((a < b) && ((b - a) > MAX_SEQ/2)) || 62 | ((a > b) && ((a - b) < MAX_SEQ/2))) { 63 | return 1; 64 | }else { 65 | return -1; 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UdpListener.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.net.DatagramPacket; 4 | 5 | /** 6 | * udp-socket 数据侦听器 7 | * @author zhangheng 8 | */ 9 | @FunctionalInterface 10 | public interface UdpListener { 11 | public void handData(UdpSocket socket, DatagramPacket packet); 12 | } 13 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UdpSocket.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramPacket; 5 | import java.net.DatagramSocket; 6 | import java.net.InetAddress; 7 | import java.net.InetSocketAddress; 8 | import java.net.SocketAddress; 9 | import java.net.SocketTimeoutException; 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * udp-工作socket 14 | * @author zhangheng 15 | */ 16 | public class UdpSocket implements Runnable { 17 | 18 | private static int counter=0; 19 | 20 | private DatagramSocket channel; 21 | private UdpListener delegate; 22 | private String name = "UdpSocket:"+(counter++); 23 | private volatile Thread reciveThread; 24 | private SocketAddress address; 25 | 26 | private UdpWorkThread workThread; 27 | /** 28 | * 使用数据线程代理 29 | */ 30 | private boolean workAble; 31 | 32 | /** 33 | * 随机绑定端口-客户端模式 34 | * @return 35 | */ 36 | public static UdpSocket client(){ 37 | try { 38 | return new UdpSocket(new InetSocketAddress(0)); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | return null; 42 | } 43 | } 44 | 45 | public UdpSocket(){ 46 | this((UdpListener)null); 47 | } 48 | public UdpSocket(UdpListener delegate){ 49 | this.delegate = delegate; 50 | this.workThread = new UdpWorkThread(this); 51 | this.workThread.listen(delegate); 52 | } 53 | public UdpSocket(InetSocketAddress addr) throws IOException{ 54 | this(addr, null); 55 | } 56 | public UdpSocket(InetSocketAddress addr, UdpListener delegate) throws IOException{ 57 | this.delegate = delegate; 58 | this.workThread = new UdpWorkThread(this); 59 | this.workThread.listen(delegate); 60 | if(addr!=null){ 61 | this.bind(addr); 62 | } 63 | } 64 | 65 | public UdpSocket name(String n){ 66 | this.name = n; 67 | if(reciveThread!=null){ 68 | reciveThread.setName(n+"_recive"); 69 | } 70 | return this; 71 | } 72 | public String name(){ 73 | return this.name; 74 | } 75 | public SocketAddress address(){ 76 | return address; 77 | } 78 | 79 | public UdpSocket listen(UdpListener delegate){ 80 | this.delegate = delegate; 81 | this.workThread.listen(delegate); 82 | return this; 83 | } 84 | public UdpSocket bind(int port) throws IOException{ 85 | return this.bind(port, false); 86 | } 87 | private boolean isIPv6(String addr){ 88 | return Pattern.compile( 89 | "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$") 90 | .matcher(addr).matches(); 91 | } 92 | public UdpSocket bind(int port, boolean ipv6) throws IOException{ 93 | InetSocketAddress isa = null; 94 | if (ipv6) 95 | { 96 | InetAddress[] addresses = InetAddress.getAllByName("localhost"); 97 | for (InetAddress addr : addresses) 98 | { 99 | if (!addr.isLoopbackAddress() && isIPv6(addr.getHostAddress())) 100 | { 101 | isa = new InetSocketAddress(addr, port); 102 | break; 103 | } 104 | } 105 | if (isa == null) 106 | isa = new InetSocketAddress(port);//FIXME does this set an address? Should this method accept an address parameter? 107 | } 108 | else 109 | isa = new InetSocketAddress((InetAddress) null, port); 110 | return this.bind(isa); 111 | } 112 | public UdpSocket bind(SocketAddress addr) throws IOException{ 113 | // if(delegate==null){ 114 | // throw new IllegalAccessError("Must Set Delegate Before Bind"); 115 | // } 116 | if(channel!=null && !channel.isClosed()){ 117 | throw new IllegalAccessError("Had a alive Binded"); 118 | } 119 | channel = new DatagramSocket(addr); 120 | channel.setSoTimeout(1000); 121 | address = addr; 122 | return this; 123 | } 124 | /** 125 | * 发送数据包 126 | * @param p 127 | * @return 128 | * @throws IOException 129 | */ 130 | public UdpSocket send(DatagramPacket p) throws IOException{ 131 | if(channel==null||channel.isClosed()){ 132 | if(address==null){ 133 | throw new IOException("You must bind a address or use client model(UdpSocket.client())!"); 134 | } 135 | throw new IOException("Socket had closed!"); 136 | } 137 | channel.send(p); 138 | return this; 139 | } 140 | /** 141 | * 发送数据包 142 | * @param buf 143 | * @param address 144 | * @return 145 | * @throws IOException 146 | */ 147 | public UdpSocket send(byte[] buf, SocketAddress address) throws IOException{ 148 | return send(new DatagramPacket(buf, buf.length, address)); 149 | } 150 | /** 151 | * 发送数据包 152 | * @param buf 153 | * @param host 154 | * @param port 155 | * @return 156 | * @throws IOException 157 | */ 158 | public UdpSocket send(byte[] buf, String host, int port) throws IOException{ 159 | return send(new DatagramPacket(buf, buf.length, new InetSocketAddress(host, port))); 160 | } 161 | /** 162 | * 开始工作 163 | * @return 164 | */ 165 | public synchronized UdpSocket start(){ 166 | if(reciveThread==null){ 167 | reciveThread = new Thread(this); 168 | reciveThread.setName(this.name); 169 | if(this.channel!=null && channel.isBound()==false){ 170 | try { 171 | this.bind(address); 172 | } catch (Exception e) { 173 | this.stop(); 174 | throw new RuntimeException(e); 175 | } 176 | } 177 | reciveThread.start(); 178 | if(workAble){ 179 | workThread.listen(this.delegate); 180 | workThread.start(); 181 | } 182 | } 183 | return this; 184 | } 185 | /** 186 | * 停止工作 187 | * @return 188 | */ 189 | public synchronized UdpSocket stop(){ 190 | if(reciveThread!=null){ 191 | workThread.stop(); 192 | reciveThread = null; 193 | channel.close(); 194 | } 195 | return this; 196 | } 197 | /** 198 | * 是否在工作中 199 | * @return 200 | */ 201 | public boolean isAlive(){ 202 | return reciveThread!=null; 203 | } 204 | public void useWorkThread(boolean b){ 205 | this.workAble = b; 206 | if(this.workAble){ 207 | if(isAlive() && workThread.isAlive()==false){ 208 | workThread.start(); 209 | } 210 | }else{ 211 | workThread.stop(); 212 | } 213 | } 214 | @Override 215 | public void run() { 216 | byte[] buf = new byte[65535]; 217 | byte[] buf_empty = new byte[0]; 218 | while(isAlive()){ 219 | DatagramPacket packet = new DatagramPacket(buf,buf.length); 220 | try { 221 | channel.receive(packet); 222 | }catch(SocketTimeoutException et){ 223 | continue; 224 | }catch (IOException e) { 225 | e.printStackTrace(); 226 | break; 227 | } 228 | if(delegate!=null){ 229 | if(packet.getLength()==0){ 230 | packet.setData(buf_empty); 231 | }else{ 232 | byte[] data = new byte[packet.getLength()]; 233 | System.arraycopy(buf, packet.getOffset(), data, 0, packet.getLength()); 234 | packet.setData(data); 235 | } 236 | onRecivePacket(packet); 237 | } 238 | } 239 | this.stop(); 240 | } 241 | private void onRecivePacket(DatagramPacket packet) { 242 | if(workAble){ 243 | workThread.offer(packet); 244 | }else if(delegate!=null){ 245 | delegate.handData(this, packet); 246 | } 247 | } 248 | public DatagramSocket socket() { 249 | return channel; 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UdpWorkThread.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.net.DatagramPacket; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | 6 | /** 7 | * 数据处理代理线程
8 | * 用于帮助udp_socket接受数据后快速返回recive 9 | * @author zhangheng 10 | */ 11 | public class UdpWorkThread { 12 | 13 | private LinkedBlockingQueue queue; 14 | private Thread thread; 15 | private UdpListener listener; 16 | private volatile boolean alive; 17 | private UdpSocket owner; 18 | 19 | public void listen(UdpListener l){ 20 | this.listener = l; 21 | } 22 | 23 | public UdpWorkThread(UdpSocket owner) { 24 | this(owner, 0); 25 | } 26 | public UdpWorkThread(UdpSocket owner, int capacity) { 27 | this.queue = new LinkedBlockingQueue(capacity<=0?Short.MAX_VALUE:capacity); 28 | this.owner = owner; 29 | } 30 | 31 | public boolean offer(DatagramPacket d){ 32 | return this.queue.offer(d); 33 | } 34 | 35 | public void start(){ 36 | if(thread==null){ 37 | thread = new Thread(UdpWorkThread.class.getSimpleName()){ 38 | public void run(){ 39 | while(UdpWorkThread.this.isAlive()){ 40 | try { 41 | UdpListener l = listener; 42 | if(l!=null){ 43 | DatagramPacket packet = queue.take(); 44 | if(packet!=null){ 45 | l.handData(UdpWorkThread.this.owner, packet); 46 | } 47 | } 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | } 53 | }; 54 | alive = true; 55 | thread.start(); 56 | } 57 | } 58 | public void stop(){ 59 | if(alive){ 60 | alive = false; 61 | if(thread!=null){ 62 | thread.interrupt(); 63 | 64 | queue.add(null); 65 | DatagramPacket packet; 66 | while(listener!=null && (packet = queue.poll())!=null){ 67 | UdpListener l = listener; 68 | if(l!=null){ 69 | l.handData(owner, packet); 70 | }else{ 71 | break; 72 | } 73 | } 74 | queue.clear(); 75 | thread = null; 76 | } 77 | } 78 | } 79 | protected boolean isAlive() { 80 | return alive; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UxServer.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramPacket; 5 | import java.net.InetSocketAddress; 6 | import java.net.SocketAddress; 7 | import java.util.Collection; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import u14.udpx.frames.Frame; 11 | import u14.udpx.frames.SYNFrame; 12 | 13 | /** 14 | * 服务端 15 | * @author zhangheng 16 | */ 17 | public class UxServer { 18 | 19 | private UdpSocket socket; 20 | private ConcurrentHashMap map; 21 | private UxSocketListener delegate; 22 | private Thread hookThread; 23 | 24 | public UxServer(){ 25 | map = new ConcurrentHashMap(); 26 | socket = new UdpSocket().listen(new UdpListener() { 27 | @Override 28 | public void handData(UdpSocket socket, DatagramPacket packet) { 29 | UxServer.this.onReciveData(packet); 30 | } 31 | }).name("UxServer_recive"); 32 | socket.useWorkThread(true); 33 | hookThread = new Thread(){ 34 | @Override 35 | public void run(){ 36 | UxServer.this.stop(); 37 | } 38 | }; 39 | } 40 | 41 | public int size(){ 42 | return map.size(); 43 | } 44 | public Collection clients(){ 45 | return map.values(); 46 | } 47 | public UxServer listen(UxSocketListener listener){ 48 | this.delegate = listener; 49 | return this; 50 | } 51 | 52 | public UxServer bind(InetSocketAddress addr) throws IOException{ 53 | this.socket.bind(addr).start(); 54 | Runtime.getRuntime().addShutdownHook(hookThread); 55 | return this; 56 | } 57 | private void onReciveData(DatagramPacket packet) { 58 | UxSocket sk = map.get(packet.getSocketAddress()); 59 | if(sk==null){ 60 | // Frame frame = Frame.parse(packet.getData(),packet.getOffset(),packet.getLength()); 61 | Frame frame = Frame.parse(packet.getData()); 62 | if(frame instanceof SYNFrame && accept(packet)){ 63 | sk = new UxServerInnerSocket(this, packet.getSocketAddress()); 64 | // System.out.println("server-new-socket:"+sk.address+" # "+frame); 65 | map.put(packet.getSocketAddress(), sk); 66 | sk.handFrame(frame, packet.getSocketAddress()); 67 | if(this.delegate!=null){ 68 | this.delegate.onOpen(sk); 69 | } 70 | } 71 | }else{ 72 | sk.handData(packet); 73 | } 74 | } 75 | 76 | /** 77 | * 是否接受packet的链接确认 78 | * @param packet 79 | * @return 80 | */ 81 | protected boolean accept(DatagramPacket packet){ 82 | return true; 83 | } 84 | 85 | public synchronized void stop(){ 86 | Object[] arr = map.values().toArray(); 87 | map.clear(); 88 | for(Object n : arr){ 89 | ((UxSocket) n).close(); 90 | } 91 | socket.stop(); 92 | Runtime.getRuntime().removeShutdownHook(hookThread); 93 | } 94 | 95 | public UdpSocket socket() { 96 | return socket; 97 | } 98 | void remove(UxServerInnerSocket socket) { 99 | if(map.remove(socket.address())!=null){ 100 | if(this.delegate!=null){ 101 | this.delegate.onClose(socket); 102 | } 103 | } 104 | } 105 | void onReciveData(UxServerInnerSocket socket, byte[] data) { 106 | if(this.delegate!=null){ 107 | this.delegate.onData(socket, data); 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UxServerInnerSocket.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.io.IOException; 4 | import java.net.SocketAddress; 5 | 6 | import u14.udpx.frames.DATFrame; 7 | 8 | /** 9 | * 服务端接受的socket 10 | * @author zhangheng 11 | */ 12 | class UxServerInnerSocket extends UxSocket{ 13 | 14 | private UxServer parent; 15 | public UxServerInnerSocket(UxServer parent, SocketAddress addr){ 16 | super(); 17 | this.parent = parent; 18 | this.socket = parent.socket(); 19 | } 20 | 21 | @Override 22 | public synchronized void connect(SocketAddress addr, int timeout) 23 | throws IOException { 24 | throw new IllegalAccessError("Not implements!"); 25 | } 26 | 27 | @Override 28 | protected synchronized void closeImp() { 29 | this.socket = null; 30 | removeFromParent(); 31 | } 32 | 33 | private void removeFromParent(){ 34 | if(this.parent!=null){ 35 | this.parent.remove(this); 36 | this.parent=null; 37 | } 38 | } 39 | 40 | @Override 41 | public synchronized void close() { 42 | if(isConnected()){ 43 | removeFromParent(); 44 | super.close(); 45 | } 46 | } 47 | 48 | @Override 49 | protected void reciveData(DATFrame frame) { 50 | if(this.parent!=null){ 51 | this.parent.onReciveData(this, frame.getData()); 52 | super.reciveData(frame); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UxSocket.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramPacket; 5 | import java.net.SocketAddress; 6 | import java.net.SocketTimeoutException; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.Iterator; 10 | import java.util.concurrent.Future; 11 | import java.util.concurrent.LinkedBlockingDeque; 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.concurrent.locks.ReentrantLock; 14 | 15 | import u14.udpx.frames.ACKFrame; 16 | import u14.udpx.frames.DATFrame; 17 | import u14.udpx.frames.EAKFrame; 18 | import u14.udpx.frames.FINFrame; 19 | import u14.udpx.frames.Frame; 20 | import u14.udpx.frames.LIVFrame; 21 | import u14.udpx.frames.SYNFrame; 22 | import u14.udpx.tick.TickHelper; 23 | 24 | /** 25 | * 客户端 26 | * @author zhangheng 27 | */ 28 | public class UxSocket { 29 | 30 | private static final int MaxFrameSize = 255; 31 | private static final int MaxRewriteNum = 8; 32 | private static final int INTERVAL_HEART = 30; 33 | private static final int INTERVAL_ALIVE = 90; 34 | private static final int SendTimeOut = 2500; 35 | private static final int MaxInQueueSize = 32; 36 | private static final int MaxSynQueueSize = 32; 37 | private static final int MaxOutQueueSize = 1024; 38 | private static final int DefaultConnectTimeOut = 5000; 39 | 40 | private SocketAddress address; 41 | protected UdpSocket socket; 42 | 43 | protected volatile UxSocketStat stat = UxSocketStat.INIT; 44 | protected Seq seq; 45 | 46 | private ArrayList inQueue;//收到的帧队列(因为乱序-用于快速确认) 47 | private LinkedBlockingDeque synQueue;//待ack确认的队列 48 | private LinkedBlockingDeque outQueue;//待写出队列,防止一次大量写入阻塞超时 49 | 50 | private ReentrantLock locker; 51 | private UxSocketListener delegate; 52 | 53 | //多久未收到数据后断开 54 | private int heart_remote=0; 55 | //多久未写数据后,发alive 56 | private int heart_local=0; 57 | private int retry_interval=0; 58 | 59 | private Thread shutDownHook; 60 | private Runnable tickTask; 61 | private Future tickFuture; 62 | 63 | private String closeInfo; 64 | public String closeInfo(){ 65 | return closeInfo; 66 | } 67 | private static final int TICK_INTERVAL = 250; 68 | public UxSocket(){ 69 | locker = new ReentrantLock(); 70 | socket = UdpSocket.client(); 71 | seq = new Seq(); 72 | shutDownHook = new Thread(){ 73 | public void run(){ 74 | UxSocket.this.close(); 75 | } 76 | }; 77 | tickTask = new Runnable() { 78 | @Override 79 | public void run() { 80 | UxSocket.this.doTick(); 81 | } 82 | }; 83 | } 84 | /** 85 | * 目标地址 86 | * @return 87 | */ 88 | public SocketAddress address(){ 89 | return address; 90 | } 91 | /** 92 | * 连接目标地址 93 | * @param addr 94 | * @return 95 | * @throws IOException 96 | */ 97 | public UxSocket connect(SocketAddress addr) throws IOException{ 98 | this.connect(addr, DefaultConnectTimeOut); 99 | return this; 100 | } 101 | /** 102 | * 建立连接 103 | * @param addr 104 | * @param timeout 105 | * @throws IOException 106 | */ 107 | public synchronized void connect(SocketAddress addr, int timeout) throws IOException{ 108 | if(this.stat==UxSocketStat.CONNECT){ 109 | return; 110 | } 111 | this.address = addr; 112 | this.stat = UxSocketStat.CONNECT; 113 | seq.initNum(); 114 | int oldTimeout = socket.socket().getSoTimeout(); 115 | socket.socket().setSoTimeout(1000); 116 | Frame connectFrame = new SYNFrame(seq.num()); 117 | DatagramPacket packet = new DatagramPacket(new byte[MaxFrameSize], MaxFrameSize); 118 | long startTm = System.currentTimeMillis(); 119 | do{ 120 | try{ 121 | sendFrameImp(connectFrame); 122 | socket.socket().receive(packet); 123 | break; 124 | }catch(SocketTimeoutException e){ 125 | if((System.currentTimeMillis()-startTm)>timeout){ 126 | this.stat = UxSocketStat.CLOSED; 127 | throw new IOException("CONNECT-TIME-OUT"); 128 | } 129 | } 130 | }while(true); 131 | Frame frame = Frame.parse(packet.getData(), packet.getOffset(), packet.getLength()); 132 | if(frame!=null && frame instanceof ACKFrame && frame.ack()==seq.num() && this.stat==UxSocketStat.CONNECT){ 133 | seq.setLastInNum(frame.seq()); 134 | socket.socket().setSoTimeout(oldTimeout); 135 | socket.listen(new UdpListener() { 136 | @Override 137 | public void handData(UdpSocket socket, DatagramPacket packet) { 138 | UxSocket.this.handData(packet); 139 | } 140 | }).start(); 141 | this.stat = UxSocketStat.WORK; 142 | Runtime.getRuntime().addShutdownHook(shutDownHook); 143 | this.onOpen(); 144 | }else{ 145 | this.stat = UxSocketStat.CLOSED; 146 | throw new IOException("CONNECT-TIME-OUT"); 147 | } 148 | } 149 | /** 150 | * 添加侦听器 151 | * @param listener 152 | * @return 153 | */ 154 | public UxSocket listen(UxSocketListener listener){ 155 | this.delegate = listener; 156 | return this; 157 | } 158 | protected void onOpen(){ 159 | inQueue = new ArrayList(MaxInQueueSize); 160 | synQueue = new LinkedBlockingDeque(MaxSynQueueSize); 161 | outQueue = new LinkedBlockingDeque(MaxOutQueueSize); 162 | if(this.delegate!=null){ 163 | this.delegate.onOpen(this); 164 | } 165 | if(tickFuture!=null){ 166 | tickFuture.cancel(true); 167 | } 168 | tickFuture = TickHelper.timeout(tickTask, 250, TimeUnit.MILLISECONDS); 169 | } 170 | public boolean isConnected(){ 171 | return this.stat==UxSocketStat.WORK; 172 | } 173 | protected void reciveData(DATFrame frame) { 174 | if(delegate!=null){ 175 | delegate.onData(this, frame.getData()); 176 | } 177 | // System.out.println("recv:"+frame.seq()+", "+seq.getLastInNum()); 178 | } 179 | /** 180 | * 关闭连接 181 | */ 182 | public synchronized void close(){ 183 | if(this.stat==UxSocketStat.WORK){ 184 | this.sendFrame(new FINFrame(seq.next())); 185 | this.stat = UxSocketStat.CLOSED; 186 | this.closeImp(); 187 | }else{ 188 | this.stat = UxSocketStat.CLOSED; 189 | } 190 | } 191 | protected synchronized void closeImp(){ 192 | this.socket.stop(); 193 | if(this.delegate!=null){ 194 | this.delegate.onClose(this); 195 | } 196 | if(tickFuture!=null){ 197 | tickFuture.cancel(true); 198 | tickFuture = null; 199 | } 200 | this.synQueue = null; 201 | this.inQueue = null; 202 | this.outQueue = null; 203 | } 204 | private void resetLiv(boolean remote){ 205 | if(remote){ 206 | heart_remote=0; 207 | }else{ 208 | heart_local=0; 209 | } 210 | } 211 | void doTick(){ 212 | locker.lock(); 213 | try{ 214 | if(isConnected()){ 215 | this.doTickImp(); 216 | } 217 | }finally{ 218 | if(isConnected()){ 219 | tickFuture = TickHelper.timeout(tickTask, TICK_INTERVAL, TimeUnit.MILLISECONDS); 220 | } 221 | locker.unlock(); 222 | } 223 | } 224 | private void doTickImp() { 225 | heart_remote++; 226 | heart_local++; 227 | if(heart_remote>INTERVAL_ALIVE){ 228 | this.closeInfo = "RemoteDead"; 229 | this.close(); 230 | return; 231 | } 232 | if(heart_local>INTERVAL_HEART){ 233 | heart_local=0; 234 | this.sendFrame(new LIVFrame(Seq.next(seq.getLastInNum()))); 235 | } 236 | // if(!synQueue.isEmpty() || !inQueue.isEmpty()){ 237 | // System.out.println(seq.num()+" "+seq.getLastInNum()+" ->"+Arrays.toString(inQueue.toArray()) + " \n=> "+Arrays.toString(synQueue.toArray())); 238 | // } 239 | retry_interval++; 240 | if(retry_interval%2==0){ 241 | Iterator it = synQueue.iterator(); 242 | while(isConnected() && it.hasNext()){ 243 | try { 244 | reSendFrame(it.next()); 245 | } catch (IOException e) { 246 | e.printStackTrace(); 247 | break; 248 | } 249 | } 250 | } 251 | } 252 | /** 253 | * 接受到数据 254 | * @param packet 255 | */ 256 | void handData(DatagramPacket packet){ 257 | // Frame frame = Frame.parse(packet.getData(),packet.getOffset(),packet.getLength()); 258 | Frame frame = Frame.parse(packet.getData()); 259 | if(frame==null){ 260 | return; 261 | } 262 | locker.lock(); 263 | try{ 264 | handFrame(frame, packet.getSocketAddress()); 265 | }catch(Exception err){ 266 | err.printStackTrace(); 267 | }finally{ 268 | locker.unlock(); 269 | } 270 | } 271 | protected void handFrame(Frame frame, SocketAddress addr){ 272 | // System.out.println(socket.name()+"_recive:"+frame.type()+"-"+ " "+frame + " from:"+addr); 273 | // System.out.println("hand-"+frame.seq()+" , "+seq.getLastInNum()); 274 | this.resetLiv(true); 275 | if(frame instanceof SYNFrame){ 276 | if(this.stat==UxSocketStat.INIT){ 277 | this.stat = UxSocketStat.WORK; 278 | this.address = addr; 279 | this.seq.initNum(); 280 | this.seq.setLastInNum(frame.seq()); 281 | this.sendFrameImp(new ACKFrame(this.seq.num(), frame.seq())); 282 | this.onOpen(); 283 | } 284 | }else if(frame instanceof FINFrame){ 285 | if(this.stat==UxSocketStat.WORK||this.stat==UxSocketStat.CONNECT){ 286 | this.sendFrameImp(new ACKFrame(this.seq.num(), frame.seq())); 287 | this.stat = UxSocketStat.CLOSED; 288 | this.closeInfo = "RemoteClose"; 289 | this.closeImp(); 290 | return; 291 | } 292 | }else if(frame instanceof DATFrame){ 293 | int compareRet = Seq.compare(frame.seq(), Seq.next(seq.getLastInNum())); 294 | if(compareRet==0){ 295 | seq.setLastInNum(frame.seq()); 296 | reciveData((DATFrame)frame); 297 | if(inQueue.isEmpty()==false){ 298 | Iterator it = inQueue.iterator(); 299 | while(it.hasNext()){ 300 | Frame f = it.next(); 301 | if(f.seq()==frame.seq()){ 302 | it.remove(); 303 | }else if(Seq.compare(f.seq(), Seq.next(seq.getLastInNum()))==0){ 304 | it.remove(); 305 | seq.setLastInNum(f.seq()); 306 | reciveData((DATFrame)f); 307 | } 308 | } 309 | } 310 | this.sendAck(); 311 | }else if(compareRet>0){ 312 | boolean add = true; 313 | if(inQueue.isEmpty()){ 314 | // System.out.println("add-frame:"+frame.seq()+"_in("+seq.getLastInNum()+")"); 315 | inQueue.add(frame); 316 | this.sendAck(); 317 | }else if(inQueue.size() it = inQueue.iterator(); 319 | while(it.hasNext()){ 320 | if(it.next().seq()==frame.seq()){ 321 | add = false; 322 | break; 323 | } 324 | } 325 | if(add){ 326 | // System.out.println("add-frame:"+frame.seq()+"_in("+seq.getLastInNum()+")"); 327 | inQueue.add(frame); 328 | Collections.sort(inQueue, Frame.Comparator); 329 | this.sendAck(); 330 | }else{ 331 | //drop 332 | } 333 | }else{ 334 | add = false; 335 | //drop 336 | } 337 | } 338 | }else if(frame instanceof LIVFrame){ 339 | 340 | }else if(frame instanceof EAKFrame){ 341 | boolean deledSyn = false; 342 | int[] acks = ((EAKFrame)frame).getACKs(); 343 | Iterator it = synQueue.iterator(); 344 | while(it.hasNext()){ 345 | Frame f = it.next(); 346 | if(f.seq()==frame.ack()){ 347 | it.remove(); 348 | deledSyn = true; 349 | }else{ 350 | for(int i=0;i0){ 378 | try { 379 | reSendFrame(f); 380 | } catch (IOException e) { 381 | e.printStackTrace(); 382 | return; 383 | } 384 | } 385 | } 386 | } 387 | if(frame.ack()>=0){ 388 | Iterator it = synQueue.iterator(); 389 | boolean deledSyn = false; 390 | while(it.hasNext()){ 391 | Frame f = it.next(); 392 | if(Seq.compare(f.seq(),frame.ack())<=0){ 393 | it.remove(); 394 | deledSyn = true; 395 | } 396 | } 397 | if(deledSyn){ 398 | sendOutQueue(); 399 | } 400 | } 401 | } 402 | /** 403 | * 重传数据帧 404 | * @param f 405 | * @throws IOException 406 | */ 407 | protected void reSendFrame(Frame f) throws IOException { 408 | if(f.reWriteNum()>MaxRewriteNum){ 409 | this.closeInfo = "MaxRetry"; 410 | this.close(); 411 | throw new IOException("Socket Closed When max-retry."); 412 | }else{ 413 | f.reWriteNum(); 414 | // System.out.println("re-write:"+f); 415 | sendFrame(f); 416 | } 417 | } 418 | private void sendAck(){ 419 | if(inQueue.isEmpty()){ 420 | sendFrameImp(new ACKFrame(Seq.next(seq.getLastInNum()), seq.getLastInNum())); 421 | }else{ 422 | synchronized (inQueue) { 423 | int[] acks = new int[inQueue.size()]; 424 | for(int i=0;i0){ 519 | // f.ack(seq.getLastInNum()); 520 | // } 521 | // } 522 | f.ack(seq.getLastInNum()); 523 | sendFrameImp(f); 524 | } 525 | // private ArrayList frames = new ArrayList(); 526 | // private boolean first = true; 527 | /** 528 | * 写出数据的实现 529 | * @param f 530 | */ 531 | protected void sendFrameImp(Frame f){ 532 | /*if(!first && Math.random()>0.6 && frames.size()<=8){ 533 | synchronized(frames){ 534 | frames.add(f); 535 | } 536 | this.resetLiv(false); 537 | return; 538 | } 539 | first = false; 540 | if(frames.size()>8 || Math.random()<0.05){ 541 | synchronized (frames) { 542 | Collections.shuffle(frames); 543 | for(Frame n:frames){ 544 | byte[] bin = n.getBytes(); 545 | if(Math.random()>0.7){ 546 | bin[0] = 0; 547 | } 548 | DatagramPacket packet = new DatagramPacket(bin, bin.length, address); 549 | try { 550 | socket.send(packet); 551 | this.resetLiv(false); 552 | } catch (IOException e) { 553 | e.printStackTrace(); 554 | this.closeInfo = "CloseBySendIoException"; 555 | this.close(); 556 | } 557 | } 558 | frames.clear(); 559 | } 560 | }*/ 561 | 562 | // System.out.println(socket.name()+"_send:"+f.type()+"-"+ " "+f); 563 | byte[] bin = f.getBytes(); 564 | DatagramPacket packet = new DatagramPacket(bin, bin.length, address); 565 | try { 566 | socket.send(packet); 567 | this.resetLiv(false); 568 | } catch (IOException e) { 569 | e.printStackTrace(); 570 | this.closeInfo = "CloseBySendIoException"; 571 | this.close(); 572 | } 573 | } 574 | } 575 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UxSocketListener.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | /** 4 | * socket状况侦听 5 | * @author zhangheng 6 | */ 7 | public interface UxSocketListener { 8 | /** 9 | * 当收到数据 10 | * @param socket 11 | * @param data 12 | */ 13 | public void onData(UxSocket socket, byte[] data); 14 | /** 15 | * 当socket连接成功/接受到连接 16 | * @param socket 17 | */ 18 | public void onOpen(UxSocket socket); 19 | /** 20 | * 当socket关闭 21 | * @param socket 22 | */ 23 | public void onClose(UxSocket socket); 24 | } 25 | -------------------------------------------------------------------------------- /java_src/u14/udpx/UxSocketStat.java: -------------------------------------------------------------------------------- 1 | package u14.udpx; 2 | 3 | enum UxSocketStat { 4 | 5 | INIT, 6 | CONNECT, 7 | WORK, 8 | CLOSED 9 | 10 | } 11 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/ACKFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | 33 | 34 | 35 | /* 36 | * ACK Frame
37 | * [flag|headerLength|seq|ack] 38 | */ 39 | public class ACKFrame extends Frame 40 | { 41 | protected ACKFrame() 42 | { 43 | } 44 | 45 | public ACKFrame(int seqn, int ackn) 46 | { 47 | init(ACK_FLAG, seqn, HEADER_LEN); 48 | ack(ackn); 49 | } 50 | 51 | @Override 52 | public byte[] getBytes() { 53 | return sum(super.getBytes()); 54 | } 55 | 56 | public String type() 57 | { 58 | return "ACK"; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/DATFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | 33 | /* 34 | * Data Frame
35 | * [flag|headerLength|seq|ack|databytes] 36 | */ 37 | public class DATFrame extends Frame 38 | { 39 | protected DATFrame() 40 | { 41 | } 42 | 43 | public DATFrame(int seqn, int ackn, byte[] b, int off, int len) 44 | { 45 | init(ACK_FLAG, seqn, HEADER_LEN); 46 | ack(ackn); 47 | if(off==0 && len==b.length){ 48 | _data = b; 49 | }else{ 50 | _data = new byte[len]; 51 | System.arraycopy(b, off, _data, 0, len); 52 | } 53 | } 54 | 55 | public int length() 56 | { 57 | return _data.length + super.length(); 58 | } 59 | 60 | public String type() 61 | { 62 | return "DAT"; 63 | } 64 | 65 | public byte[] getData() 66 | { 67 | return _data; 68 | } 69 | 70 | public byte[] getBytes() 71 | { 72 | byte[] buffer = super.getBytes(); 73 | System.arraycopy(_data, 0, buffer, HEADER_LEN, _data.length); 74 | return sum(buffer); 75 | } 76 | 77 | public void parseBytes(byte[] buffer, int off, int len) 78 | { 79 | super.parseBytes(buffer, off, len); 80 | _data = new byte[len - HEADER_LEN]; 81 | System.arraycopy(buffer, off+HEADER_LEN, _data, 0, _data.length); 82 | } 83 | 84 | private byte[] _data; 85 | } 86 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/EAKFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | 33 | 34 | 35 | /* 36 | * EACK Frame
37 | * [flag|headerLength|seq|ack|ack_list] 38 | */ 39 | public class EAKFrame extends Frame 40 | { 41 | private static final int[] EMPTY_ACKS = new int[]{}; 42 | protected EAKFrame() 43 | { 44 | _acks = EMPTY_ACKS; 45 | } 46 | 47 | public EAKFrame(int seqn, int ackn, int[] acks) 48 | { 49 | init(EAK_FLAG, seqn, HEADER_LEN + acks.length); 50 | ack(ackn); 51 | _acks = acks; 52 | } 53 | 54 | public String type() 55 | { 56 | return "EAK"; 57 | } 58 | 59 | public int[] getACKs() 60 | { 61 | return _acks; 62 | } 63 | 64 | public byte[] getBytes() 65 | { 66 | byte[] buffer = super.getBytes(); 67 | 68 | for (int i = 0; i < _acks.length; i++) { 69 | buffer[HEADER_LEN+i] = (byte) (_acks[i] & 0xFF); 70 | } 71 | 72 | return sum(buffer); 73 | } 74 | 75 | protected void parseBytes(byte[] buffer, int off, int length) 76 | { 77 | super.parseBytes(buffer, off, length); 78 | _acks = new int[length() - HEADER_LEN]; 79 | for (int i = 0; i < _acks.length; i++) { 80 | _acks[i] = (buffer[off + HEADER_LEN + i] & 0xFF); 81 | } 82 | } 83 | 84 | private int[] _acks; 85 | } 86 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/FINFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | /* 33 | * FIN Frame
34 | * [flag|headerLength|seq|ack] 35 | */ 36 | public class FINFrame extends Frame 37 | { 38 | protected FINFrame() 39 | { 40 | } 41 | 42 | public FINFrame(int seqn) 43 | { 44 | init(FIN_FLAG, seqn, HEADER_LEN); 45 | } 46 | 47 | @Override 48 | public byte[] getBytes() { 49 | return sum(super.getBytes()); 50 | } 51 | 52 | public String type() 53 | { 54 | return "FIN"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/Frame.java: -------------------------------------------------------------------------------- 1 | package u14.udpx.frames; 2 | 3 | import java.util.Comparator; 4 | 5 | import u14.udpx.Seq; 6 | 7 | /** 8 | * [flag|headerLength|seq|ack] 9 | */ 10 | public abstract class Frame { 11 | 12 | public static final byte SYN_FLAG = (byte) 0x80; 13 | public static final byte ACK_FLAG = (byte) 0x40; 14 | public static final byte EAK_FLAG = (byte) 0x20; 15 | public static final byte LIV_FLAG = (byte) 0x08; 16 | // public static final byte CHK_FLAG = (byte) 0x04; 17 | public static final byte FIN_FLAG = (byte) 0x02; 18 | 19 | public static final byte HEADER_LEN = 4; 20 | 21 | private int flag; 22 | private int len; 23 | private int seq; 24 | private int ack=-1; 25 | 26 | private short reWriteNum=0; 27 | 28 | public Frame() { 29 | } 30 | public abstract String type(); 31 | 32 | public int flag(){ 33 | return flag; 34 | } 35 | public int seq(){ 36 | return seq; 37 | } 38 | public int length(){ 39 | return len; 40 | } 41 | public int ack(){ 42 | // if ((ack & ACK_FLAG) == ACK_FLAG) { 43 | // return ack; 44 | // } 45 | // return -1; 46 | return ack; 47 | } 48 | public void ack(int n){ 49 | ack = n; 50 | } 51 | 52 | public void incrReWriteNum(){ 53 | reWriteNum++; 54 | } 55 | public int reWriteNum(){ 56 | return reWriteNum; 57 | } 58 | public byte[] getBytes() 59 | { 60 | byte[] buffer = new byte[length()+2]; 61 | buffer[0] = (byte) (flag & 0xFF); 62 | buffer[1] = (byte) (len & 0xFF); 63 | buffer[2] = (byte) (seq & 0xFF); 64 | buffer[3] = (byte) (ack & 0xFF); 65 | return buffer; 66 | } 67 | protected static byte[] sum(byte[] b){ 68 | int len = b.length-2; 69 | if(len>255){ 70 | len = 255; 71 | } 72 | short n = 0; 73 | for(int i=0;i>8); 77 | b[b.length-1] = (byte)n; 78 | return b; 79 | } 80 | protected static boolean checkSum(byte[] b){ 81 | int len = b.length-2; 82 | if(len>255){ 83 | len = 255; 84 | } 85 | short n = 0; 86 | for(int i=0;i>8) && b[b.length-1] == (byte)n; 90 | } 91 | protected static boolean checkSum(byte[] b, int off, int len){ 92 | int size = len-2; 93 | if(size>255){ 94 | size = 255; 95 | } 96 | int end = off+size; 97 | short n = 0; 98 | for(int i=off;i>8) && b[end+1] == (byte)n; 102 | } 103 | public String toString() 104 | { 105 | return type() + 106 | " [" + 107 | " SEQ = " + seq() + 108 | ", ACK = " + ((ack() >= 0) ? ""+ack() : "N/A") + 109 | ", LEN = " + length() + 110 | " ]"; 111 | } 112 | protected void init(int flag, int seq, int len) 113 | { 114 | this.flag = flag; 115 | this.seq = seq; 116 | this.len = len; 117 | } 118 | protected void parseBytes(byte[] buffer, int off, int length) 119 | { 120 | this.flag = (buffer[off] & 0xFF); 121 | this.len = (buffer[off+1] & 0xFF); 122 | this.seq = (buffer[off+2] & 0xFF); 123 | this.ack = (buffer[off+3] & 0xFF); 124 | } 125 | 126 | public static Frame parse(byte[] bytes) 127 | { 128 | if(!checkSum(bytes)){ 129 | // throw new IllegalArgumentException("Invalid segment sum"); 130 | return null; 131 | } 132 | return parseImp(bytes, 0, bytes.length-2); 133 | } 134 | public static Frame parse(byte[] bytes, int off, int len){ 135 | if(!checkSum(bytes,off,len)){ 136 | // throw new IllegalArgumentException("Invalid segment sum"); 137 | return null; 138 | } 139 | return parseImp(bytes, off, len-2); 140 | } 141 | private static Frame parseImp(byte[] bytes, int off, int len) 142 | { 143 | if (len < HEADER_LEN) { 144 | // throw new IllegalArgumentException("Invalid segment"); 145 | return null; 146 | } 147 | Frame segment = null; 148 | int flags = bytes[off]; 149 | if ((flags & SYN_FLAG) != 0) { 150 | segment = new SYNFrame(); 151 | } 152 | else if ((flags & LIV_FLAG) != 0) { 153 | segment = new LIVFrame(); 154 | } 155 | else if ((flags & EAK_FLAG) != 0) { 156 | segment = new EAKFrame(); 157 | } 158 | else if ((flags & FIN_FLAG) != 0) { 159 | segment = new FINFrame(); 160 | } 161 | else if ((flags & ACK_FLAG) != 0) { /* always process ACKs or Data segments last */ 162 | if (len == HEADER_LEN) { 163 | segment = new ACKFrame(); 164 | } 165 | else { 166 | segment = new DATFrame(); 167 | } 168 | } 169 | 170 | if (segment == null) { 171 | throw new IllegalArgumentException("Invalid segment"); 172 | } 173 | 174 | segment.parseBytes(bytes, off, len); 175 | return segment; 176 | } 177 | 178 | /** 179 | * 比较器(用于排序) 180 | */ 181 | public static Comparator Comparator = new Comparator() { 182 | @Override 183 | public int compare(Frame o1, Frame o2) { 184 | return Seq.compare(o1.seq(), o2.seq()); 185 | } 186 | }; 187 | } 188 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/LIVFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | 33 | 34 | 35 | /* 36 | * LIV Frame
37 | * [flag|headerLength|seq|ack] 38 | */ 39 | public class LIVFrame extends Frame 40 | { 41 | protected LIVFrame() 42 | { 43 | } 44 | 45 | public LIVFrame(int seqn) 46 | { 47 | init(LIV_FLAG, seqn, HEADER_LEN); 48 | } 49 | @Override 50 | public byte[] getBytes() { 51 | return sum(super.getBytes()); 52 | } 53 | public String type() 54 | { 55 | return "LIV"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/SEE: -------------------------------------------------------------------------------- 1 | @see 2 | http://sourceforge.net/projects/rudp/?source=dlp 3 | 4 | Simple Reliable UDP (rudp) 5 | Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) All rights reserved. -------------------------------------------------------------------------------- /java_src/u14/udpx/frames/SYNFrame.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Reliable UDP (rudp) 3 | * Copyright (c) 2009, Adrian Granados (agranados@ihmc.us) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of the copyright holder nor the names of its 14 | * contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package u14.udpx.frames; 32 | 33 | 34 | 35 | /* 36 | * SYN Frame
37 | * [flag|headerLength|seq|ack] 38 | */ 39 | public class SYNFrame extends Frame 40 | { 41 | protected SYNFrame() 42 | { 43 | } 44 | 45 | public SYNFrame(int seqn) 46 | { 47 | init(SYN_FLAG, seqn, HEADER_LEN); 48 | } 49 | @Override 50 | public byte[] getBytes() { 51 | return sum(super.getBytes()); 52 | } 53 | public String type() 54 | { 55 | return "SYN"; 56 | } 57 | 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /java_src/u14/udpx/think.txt: -------------------------------------------------------------------------------- 1 | Frame{ 2 | flag:帧标记-1byte, 3 | len:帧头部长度-1byte, 4 | seq:序列号-1byte, 5 | ack:响应序号-1byte, 6 | 7 | writeNum:写出次数=重传次数+1 8 | createTime:创建时间,用于计算过去多久了 9 | } 10 | 11 | seq:当前SEQ 12 | lastSeq:最后收到的数据SEQ 13 | ackNum:需要响应的ACK数 14 | 15 | SYN_QUEUE[待ACK队列]写出后等待ACK,收到ACK后移除 16 | IN_QUEUE[接收到的Frame队列] 缺帧乱帧等待 17 | 18 | 主动查询SYN_QUEUE,如果队列满,不可以继续写入,如果队列中重传次数过多/或者超时,则关闭通道认为网络错误 19 | 主动重传SYN_QUEUE 20 | #主动查看接收队列,发送此类ACK,时间可以略久 21 | 22 | handFrame(frame){ 23 | if(!(frame is Ack)){ 24 | ackNum++; 25 | } 26 | if(连接){ 27 | 连接响应 28 | }else if(连接响应){ 29 | 连接成功 30 | }else if(关闭){ 31 | ->关闭 32 | 关闭自己 33 | }else{ 34 | if(Data){ 35 | if(frame.seq<=lastSeq){ 36 | sendAck(frame); 37 | } 38 | if(IN_QUEUE.isFull()){ 39 | if(IN_QUEUE[i].seq0){ 80 | reSend(i); 81 | } 82 | } 83 | }else if(ACK){ 84 | 85 | } 86 | checkAck(frame) 87 | } 88 | } 89 | reSend(frame){ 90 | if(frame.rewritenum>36){ 91 | //maybe-io-error 92 | } 93 | sendFrameImp(f); 94 | if(IN_QUEUE.isEmpty()==false && ackNum>1){ 95 | sendAckArr(); 96 | }else{ 97 | sendAck(); 98 | } 99 | } 100 | sendAck(){ 101 | sendFrame(new ACK(nextSeq(lastInSeq), lastInSequence)); 102 | } 103 | sendAckArr(){ 104 | sendFrame(new EACK(nextSeq(lastInSeq), lastInSequence, acks)); 105 | ackNum=0; 106 | } 107 | sendFrame(f){ 108 | if(!(f=ACK)){ 109 | if(ackNum>0){ 110 | f.ack = lastInSeq; 111 | } 112 | } 113 | sendFrameImp(f); 114 | } 115 | checkAck(frame){ 116 | if(frame.ack()<0)return; 117 | while(SYN_QUEUE){ 118 | if(compare(SYN_QUEUE[i].seq,frame.ack())<=0){ 119 | i.remove(); 120 | } 121 | } 122 | } 123 | 124 | private static final int MAX_SEQ = 255; 125 | /** 126 | * Computes the consecutive sequence number. 127 | * @return the next number in the sequence. 128 | */ 129 | public static int next(int n) 130 | { 131 | return (n + 1) % MAX_SEQ; 132 | } 133 | /** 134 | * Compares two sequence numbers. 135 | * @return 0, 1 or -1 if the first sequence number is equal, 136 | * greater or less than the second sequence number. 137 | * (see RFC 1982). 138 | */ 139 | public static int compare(int a, int b) 140 | { 141 | if (a == b) { 142 | return 0; 143 | }else if (((a < b) && ((b - a) > MAX_SEQ/2)) || 144 | ((a > b) && ((a - b) < MAX_SEQ/2))) { 145 | return 1; 146 | }else { 147 | return -1; 148 | } 149 | } -------------------------------------------------------------------------------- /java_src/u14/udpx/tick/TickHelper.java: -------------------------------------------------------------------------------- 1 | package u14.udpx.tick; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.Future; 5 | import java.util.concurrent.ScheduledThreadPoolExecutor; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * @author zhangheng 10 | */ 11 | public class TickHelper { 12 | 13 | private volatile static ScheduledThreadPoolExecutor executor = reset(Runtime.getRuntime().availableProcessors()); 14 | 15 | /** 16 | * 每次执行任务的时间不受前次任务延时影响。 17 | * @param task 具体待执行的任务 18 | * @param delay 等待多久执行任务 19 | * @param unit 时间单位 20 | */ 21 | public static Future timeout(Runnable task, long delay, TimeUnit unit) { 22 | return executor.schedule(task, delay, unit); 23 | } 24 | /** 25 | * 每次执行任务的时间不受前次任务延时影响。 26 | * @param task 具体待执行的任务 27 | * @param interval 每次执行任务的间隔时间 28 | * @param unit 时间单位 29 | */ 30 | public static Future interval(Runnable task, long interval, TimeUnit unit) { 31 | return interval(task, interval, interval, unit); 32 | } 33 | /** 34 | * 在指定的延时之后开始以固定的频率来运行任务。后续任务的启动时间不受前次任务延时影响。 35 | * @param task 具体待执行的任务 36 | * @param firstDelay 首次执行任务的延时时间 37 | * @param interval 每次执行任务的间隔时间 38 | * @param unit 时间单位 39 | */ 40 | public static Future interval(Runnable task, long firstDelay, long interval, TimeUnit unit) { 41 | return executor.scheduleAtFixedRate(task, firstDelay, interval, unit); 42 | } 43 | /** 44 | * 在指定的延时之后开始以固定的频率来运行任务。后续任务的启动时间不受前次任务延时影响。 45 | * @param task 具体待执行的任务 46 | * @param interval 每次执行任务的间隔时间 47 | * @param unit 时间单位 48 | */ 49 | public static Future intervalWithFixedDelay(Runnable task, long interval, TimeUnit unit) { 50 | return executor.scheduleWithFixedDelay(task, interval, interval, unit); 51 | } 52 | /** 53 | * 每次执行任务的时间不受前次任务延时影响。 54 | * @param task 具体待执行的任务 55 | * @param interval 等待多久执行任务 56 | * @param unit 时间单位 57 | */ 58 | public static Future timeout(Callable task, long delay, TimeUnit unit) { 59 | return executor.schedule(task, delay, unit); 60 | } 61 | 62 | public static Future submit(Runnable task){ 63 | return executor.submit(task); 64 | } 65 | public static Future submit(Callable task){ 66 | return executor.submit(task); 67 | } 68 | 69 | /** 70 | * 重置动定时任务服务,旧的任务如果没执行可能会被shutdown 71 | */ 72 | public synchronized static ScheduledThreadPoolExecutor reset(int size) { 73 | try{ 74 | if(executor!=null){ 75 | executor.shutdown(); 76 | } 77 | }finally{ 78 | executor = new ScheduledThreadPoolExecutor(Math.max(1, size), new TickThreadFactory("TickHelper")); 79 | } 80 | return executor; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /java_src/u14/udpx/tick/TickThreadFactory.java: -------------------------------------------------------------------------------- 1 | package u14.udpx.tick; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | class TickThreadFactory implements ThreadFactory{ 7 | 8 | private static final AtomicInteger poolNumber = new AtomicInteger(1); 9 | private final ThreadGroup group; 10 | private final AtomicInteger threadNumber = new AtomicInteger(1); 11 | private final String namePrefix; 12 | 13 | TickThreadFactory(){ 14 | this("TickThread"); 15 | } 16 | TickThreadFactory(String name) { 17 | SecurityManager s = System.getSecurityManager(); 18 | group = (s != null) ? s.getThreadGroup() : 19 | Thread.currentThread().getThreadGroup(); 20 | namePrefix = name +"_"+ 21 | poolNumber.getAndIncrement()+"@"; 22 | } 23 | 24 | public Thread newThread(Runnable r) { 25 | Thread t = new Thread(group, r, 26 | namePrefix + threadNumber.getAndIncrement(), 27 | 0); 28 | if (t.isDaemon()) 29 | t.setDaemon(false); 30 | if (t.getPriority() != Thread.NORM_PRIORITY) 31 | t.setPriority(Thread.NORM_PRIORITY); 32 | return t; 33 | } 34 | } 35 | --------------------------------------------------------------------------------