1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.nio;
21
22 import java.io.IOException;
23 import java.net.SocketAddress;
24 import java.net.SocketException;
25 import java.nio.channels.SelectionKey;
26 import java.nio.channels.SocketChannel;
27
28 import org.apache.mina.api.IdleStatus;
29 import org.apache.mina.api.IoFuture;
30 import org.apache.mina.api.IoSession;
31 import org.apache.mina.api.MinaRuntimeException;
32 import org.apache.mina.service.executor.IoHandlerExecutor;
33 import org.apache.mina.service.executor.OrderedHandlerExecutor;
34 import org.apache.mina.service.idlechecker.IdleChecker;
35 import org.apache.mina.service.idlechecker.IndexedIdleChecker;
36 import org.apache.mina.transport.ConnectFuture;
37 import org.apache.mina.transport.tcp.AbstractTcpClient;
38 import org.apache.mina.transport.tcp.TcpSessionConfig;
39 import org.apache.mina.util.Assert;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43
44
45
46
47
48 public class NioTcpClient extends AbstractTcpClient {
49
50
51 private static final Logger LOG = LoggerFactory.getLogger(NioTcpClient.class);
52
53
54
55 private final SelectorLoop connectSelectorLoop;
56
57
58
59 private final SelectorLoopPool readWriteSelectorPool;
60
61
62 private IdleChecker idleChecker;
63
64
65
66
67
68 public NioTcpClient() {
69
70 this(new NioSelectorLoop("connect", 0), new FixedSelectorLoopPool("Client", 2), null);
71 }
72
73
74
75
76
77
78
79
80
81
82
83 public NioTcpClient(SelectorLoopPool selectorLoopPool, IoHandlerExecutor handlerExecutor) {
84 super(handlerExecutor);
85 connectSelectorLoop = selectorLoopPool.getSelectorLoop();
86 readWriteSelectorPool = selectorLoopPool;
87 }
88
89
90
91
92
93
94
95
96
97
98 public NioTcpClient(SelectorLoop connectSelectorLoop, SelectorLoopPool readWriteSelectorLoop,
99 IoHandlerExecutor handlerExecutor) {
100 super(handlerExecutor);
101 this.connectSelectorLoop = connectSelectorLoop;
102 this.readWriteSelectorPool = readWriteSelectorLoop;
103 idleChecker = new IndexedIdleChecker();
104 }
105
106
107
108
109 @Override
110 public IoFuture<IoSession> connect(SocketAddress remoteAddress) {
111 Assert.assertNotNull(remoteAddress, "remoteAddress");
112
113 SocketChannel clientSocket;
114 try {
115 clientSocket = SocketChannel.open();
116 } catch (IOException e) {
117 throw new MinaRuntimeException("can't create a new socket, out of file descriptors ?", e);
118 }
119
120 try {
121 clientSocket.socket().setSoTimeout(getConnectTimeoutMillis());
122 } catch (SocketException e) {
123 throw new MinaRuntimeException("can't set socket timeout", e);
124 }
125
126
127 try {
128 clientSocket.configureBlocking(false);
129 } catch (IOException e) {
130 throw new MinaRuntimeException("can't configure socket as non-blocking", e);
131 }
132
133
134
135 final NioTcpSession session = new NioTcpSession(this, clientSocket, readWriteSelectorPool.getSelectorLoop(),
136 idleChecker);
137 TcpSessionConfig config = getSessionConfig();
138
139 session.getConfig().setIdleTimeInMillis(IdleStatus.READ_IDLE, config.getIdleTimeInMillis(IdleStatus.READ_IDLE));
140 session.getConfig().setIdleTimeInMillis(IdleStatus.WRITE_IDLE,
141 config.getIdleTimeInMillis(IdleStatus.WRITE_IDLE));
142
143
144 Boolean keepAlive = config.isKeepAlive();
145
146 if (keepAlive != null) {
147 session.getConfig().setKeepAlive(keepAlive);
148 }
149
150 Boolean oobInline = config.isOobInline();
151
152 if (oobInline != null) {
153 session.getConfig().setOobInline(oobInline);
154 }
155
156 Boolean reuseAddress = config.isReuseAddress();
157
158 if (reuseAddress != null) {
159 session.getConfig().setReuseAddress(reuseAddress);
160 }
161
162 Boolean tcpNoDelay = config.isTcpNoDelay();
163
164 if (tcpNoDelay != null) {
165 session.getConfig().setTcpNoDelay(tcpNoDelay);
166 }
167
168 Integer receiveBufferSize = config.getReadBufferSize();
169
170 if (receiveBufferSize != null) {
171 session.getConfig().setReadBufferSize(receiveBufferSize);
172 } else {
173 int rcvBufferSize;
174 try {
175 rcvBufferSize = clientSocket.socket().getReceiveBufferSize();
176 } catch (SocketException e) {
177 throw new MinaRuntimeException("can't configure socket receive buffer size", e);
178 }
179 session.getConfig().setReadBufferSize(rcvBufferSize);
180 }
181
182 Integer sendBufferSize = config.getSendBufferSize();
183
184 if (sendBufferSize != null) {
185 session.getConfig().setSendBufferSize(sendBufferSize);
186 } else {
187 int sndBufferSize;
188 try {
189 sndBufferSize = clientSocket.socket().getSendBufferSize();
190 } catch (SocketException e) {
191 throw new MinaRuntimeException("can't configure socket send buffe size", e);
192 }
193 session.getConfig().setSendBufferSize(sndBufferSize);
194 }
195
196 Integer trafficClass = config.getTrafficClass();
197
198 if (trafficClass != null) {
199 session.getConfig().setTrafficClass(trafficClass);
200 }
201
202 Integer soLinger = config.getSoLinger();
203
204 if (soLinger != null) {
205 session.getConfig().setSoLinger(soLinger);
206 }
207
208
209 if (config.isSecured()) {
210 session.initSecure(config.getSslContext());
211 }
212
213
214
215 boolean connected;
216 try {
217 connected = clientSocket.connect(remoteAddress);
218 } catch (IOException e) {
219 ConnectFuture future = new ConnectFuture();
220 future.cannotConnect(e);
221 return future;
222 }
223
224 ConnectFuture connectFuture = new ConnectFuture();
225 session.setConnectFuture(connectFuture);
226
227 if (!connected) {
228
229
230 connectSelectorLoop.register(false, true, false, false, session, clientSocket, new RegistrationCallback() {
231
232 @Override
233 public void done(SelectionKey selectionKey) {
234 session.setSelectionKey(selectionKey);
235 }
236 });
237 } else {
238
239
240 connectSelectorLoop.register(false, false, true, false, session, clientSocket, new RegistrationCallback() {
241
242 @Override
243 public void done(SelectionKey selectionKey) {
244 session.setSelectionKey(selectionKey);
245 }
246 });
247
248 session.setConnected();
249 }
250
251 return connectFuture;
252 }
253
254
255
256
257 public synchronized void disconnect() throws IOException {
258 LOG.info("Disconnecting sessions");
259
260
261 for (IoSession session : getManagedSessions().values()) {
262 session.close(true);
263 }
264
265 fireServiceInactivated();
266
267
268 idleChecker.destroy();
269 }
270 }