├── 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 |
--------------------------------------------------------------------------------