1 /***
2 *
3 * Copyright 2004 Hiram Chirino
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.activeio.net.benchmark;
18
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.HashMap;
24
25 import org.activeio.AcceptListener;
26 import org.activeio.AsynchChannel;
27 import org.activeio.AsynchChannelListener;
28 import org.activeio.AsynchChannelServer;
29 import org.activeio.Channel;
30 import org.activeio.ChannelFactory;
31 import org.activeio.Packet;
32 import org.activeio.adapter.SynchToAsynchChannelAdapter;
33 import org.activeio.packet.EOSPacket;
34 import org.activeio.stats.CountStatisticImpl;
35 import org.apache.commons.beanutils.BeanUtils;
36
37 import EDU.oswego.cs.dl.util.concurrent.Latch;
38
39 /***
40 * Implements a simple tcp echo server for use in benchmarking
41 * activeio channel implementations.
42 *
43 * @version $Revision$
44 */
45 public class Server implements Runnable, AcceptListener {
46
47 private URI url;
48 private Latch shutdownLatch;
49 private long requestDelay = 0;
50 private long sampleInterval = 1000;
51
52 private final CountStatisticImpl activeConnectionsCounter = new CountStatisticImpl("activeConnectionsCounter","The number of active connection attached to the server.");
53 private final CountStatisticImpl echoedBytesCounter = new CountStatisticImpl("echoedBytesCounter","The number of bytes that have been echoed by the server.");
54
55 public static void main(String[] args) throws URISyntaxException, IllegalAccessException, InvocationTargetException {
56
57 Server server = new Server();
58
59 HashMap options = new HashMap();
60 for( int i=0; i < args.length; i++ ) {
61
62 String option = args[i];
63 if( !option.startsWith("-") || option.length()<2 || i+1 >= args.length ) {
64 System.out.println("Invalid usage.");
65 return;
66 }
67
68 option = option.substring(1);
69 options.put(option, args[++i]);
70 }
71 BeanUtils.populate(server, options);
72
73 System.out.println();
74 System.out.println("Server starting with the following options: ");
75 System.out.println(" url="+server.getUrl());
76 System.out.println(" sampleInterval="+server.getSampleInterval());
77 System.out.println(" requestDelay="+server.getRequestDelay());
78 System.out.println();
79 server.run();
80
81 }
82
83 private void printSampleData() {
84 long now = System.currentTimeMillis();
85 float runDuration = (now - activeConnectionsCounter.getStartTime())/1000f;
86 System.out.println("Active connections: "+activeConnectionsCounter.getCount());
87 System.out.println("Echoed bytes: " + (echoedBytesCounter.getCount()/1024f) + " kb");
88 echoedBytesCounter.reset();
89 }
90
91
92 public void run() {
93 try {
94
95 activeConnectionsCounter.reset();
96 echoedBytesCounter.reset();
97
98 shutdownLatch = new Latch();
99
100 ChannelFactory factory = new ChannelFactory();
101 AsynchChannelServer server = factory.bindAsynchChannel(url);
102 System.out.println("Server accepting connections on: "+server.getConnectURI());
103 server.setAcceptListener(this);
104 server.start();
105
106 while(!shutdownLatch.attempt(sampleInterval)) {
107 printSampleData();
108 }
109
110 System.out.println("Stopping server.");
111 server.stop(1000*5);
112 server.dispose();
113
114 } catch (IOException e) {
115 e.printStackTrace();
116 } catch (InterruptedException e) {
117 }
118 }
119
120 public String getUrl() {
121 return url.toString();
122 }
123
124 public void setUrl(String url) throws URISyntaxException {
125 this.url = new URI(url);
126 }
127
128 class ServerConnectionHandler implements AsynchChannelListener {
129
130 private final AsynchChannel asynchChannel;
131 private boolean disposed;
132
133 public ServerConnectionHandler(AsynchChannel asynchChannel) {
134 this.asynchChannel = asynchChannel;
135 activeConnectionsCounter.increment();
136 }
137
138 public void onPacket(Packet packet) {
139
140 if( packet == EOSPacket.EOS_PACKET ) {
141 System.out.println("Peer disconnected.");
142 dispose();
143 return;
144 }
145
146 try {
147 if( requestDelay > 0 ) {
148 Thread.sleep(requestDelay);
149 }
150
151 echoedBytesCounter.add(packet.remaining());
152 asynchChannel.write(packet);
153 asynchChannel.flush();
154
155 } catch (IOException e) {
156 onPacketError(e);
157 } catch (InterruptedException e) {
158 System.out.println("Interrupted... Shutting down.");
159 dispose();
160 }
161 }
162
163 public void onPacketError(IOException error) {
164 error.printStackTrace();
165 dispose();
166 }
167
168 private void dispose() {
169 if( !disposed ) {
170 asynchChannel.dispose();
171 activeConnectionsCounter.decrement();
172 disposed=true;
173 }
174 }
175 }
176
177 public void onAccept(Channel channel) {
178 try {
179
180 AsynchChannel asynchChannel = SynchToAsynchChannelAdapter.adapt(channel);
181 asynchChannel.setAsynchChannelListener(new ServerConnectionHandler(asynchChannel));
182 asynchChannel.start();
183
184 } catch (IOException e) {
185 onAcceptError(e);
186 }
187 }
188
189 public void onAcceptError(IOException error) {
190 error.printStackTrace();
191 shutdownLatch.release();
192 }
193
194 /***
195 * @return Returns the requestDelay.
196 */
197 public long getRequestDelay() {
198 return requestDelay;
199 }
200 /***
201 * @param requestDelay The requestDelay to set.
202 */
203 public void setRequestDelay(long requestDelay) {
204 this.requestDelay = requestDelay;
205 }
206 /***
207 * @return Returns the sampleInterval.
208 */
209 public long getSampleInterval() {
210 return sampleInterval;
211 }
212 /***
213 * @param sampleInterval The sampleInterval to set.
214 */
215 public void setSampleInterval(long sampleInterval) {
216 this.sampleInterval = sampleInterval;
217 }
218 }