hprose.client.HproseTcpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hprose-java Show documentation
Show all versions of hprose-java Show documentation
Hprose is a High Performance Remote Object Service Engine.
It is a modern, lightweight, cross-language, cross-platform, object-oriented, high performance, remote dynamic communication middleware. It is not only easy to use, but powerful. You just need a little time to learn, then you can use it to easily construct cross language cross platform distributed application system.
Hprose supports many programming languages, for example:
* AAuto Quicker
* ActionScript
* ASP
* C++
* Dart
* Delphi/Free Pascal
* dotNET(C#, Visual Basic...)
* Golang
* Java
* JavaScript
* Node.js
* Objective-C
* Perl
* PHP
* Python
* Ruby
* ...
Through Hprose, You can conveniently and efficiently intercommunicate between those programming languages.
This project is the implementation of Hprose for Java.
/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* HproseTcpClient.java *
* *
* hprose tcp client class for Java. *
* *
* LastModified: Jun 2, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
package hprose.client;
import hprose.common.HproseException;
import hprose.io.HproseMode;
import hprose.net.Connection;
import hprose.net.ConnectionHandler;
import hprose.net.Connector;
import hprose.net.ReceiveCallback;
import hprose.net.TimeoutType;
import hprose.util.concurrent.Threads;
import hprose.util.concurrent.Timer;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
final class Request {
public final ByteBuffer buffer;
public final ReceiveCallback callback;
public final int timeout;
public Request(ByteBuffer buffer, ReceiveCallback callback, int timeout) {
this.buffer = buffer;
this.callback = callback;
this.timeout = timeout;
}
}
final class Response {
public final ReceiveCallback callback;
public final long createTime;
public final int timeout;
public Response(ReceiveCallback callback, int timeout) {
this.callback = callback;
this.createTime = System.currentTimeMillis();
this.timeout = timeout;
}
}
abstract class SocketTransporter extends Thread implements ConnectionHandler {
protected final static class ConnectorHolder {
final static Connector connector;
static {
Connector temp = null;
try {
temp = new Connector(HproseTcpClient.getReactorThreads());
}
catch (IOException e) {}
finally {
connector = temp;
connector.start();
}
Threads.registerShutdownHandler(new Runnable() {
public void run() {
if (connector != null) {
connector.close();
}
}
});
}
}
protected final HproseTcpClient client;
protected final BlockingQueue idleConnections = new LinkedBlockingQueue();
protected final BlockingQueue requests = new LinkedBlockingQueue();
protected final AtomicInteger size = new AtomicInteger(0);
public SocketTransporter(HproseTcpClient client) {
super();
this.client = client;
}
public final int getReadTimeout() {
return client.getReadTimeout();
}
public final int getWriteTimeout() {
return client.getWriteTimeout();
}
public final int getConnectTimeout() {
return client.getConnectTimeout();
}
@Override
public void run() {
try {
while (!isInterrupted()) {
Request request;
if (requests.isEmpty()) {
request = requests.take();
requests.offer(request);
}
if (idleConnections.isEmpty()) {
if (geRealPoolSize() < client.getMaxPoolSize()) {
try {
ConnectorHolder.connector.create(client.uri, this, client.isKeepAlive(), client.isNoDelay());
}
catch (IOException ex) {
while ((request = requests.poll()) != null) {
request.callback.handler(null, ex);
}
}
}
}
Connection conn = idleConnections.poll(client.getConnectTimeout(), TimeUnit.MILLISECONDS);
if (conn != null) {
request = requests.poll();
if (request == null) {
request = requests.take();
}
send(conn, request);
}
}
}
catch (InterruptedException e) {}
}
protected abstract int geRealPoolSize();
protected abstract void send(Connection conn, Request request);
public final synchronized void send(ByteBuffer buffer, ReceiveCallback callback, int timeout) {
requests.offer(new Request(buffer, callback, timeout));
}
protected void close(Map responses) {
interrupt();
while (!responses.isEmpty()) {
Iterator it = responses.keySet().iterator();
while (it.hasNext()) {
Connection conn = it.next();
conn.close();
}
}
while (!requests.isEmpty()) {
requests.poll().callback.handler(null, new ClosedChannelException());
}
}
public final void onClose(Connection conn) {
idleConnections.remove(conn);
onError(conn, new ClosedChannelException());
}
public abstract void close();
}
final class FullDuplexSocketTransporter extends SocketTransporter {
private final static AtomicInteger nextId = new AtomicInteger(0);
private final Map> responses = new ConcurrentHashMap>();
private final Timer timer = new Timer(new Runnable() {
public void run() {
long currentTime = System.currentTimeMillis();
Iterator>> iterator = responses.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry> entry = iterator.next();
Connection conn = entry.getKey();
Map res = entry.getValue();
Iterator> it = res.entrySet().iterator();
while (it.hasNext()) {
Map.Entry e = it.next();
Response response = e.getValue();
if ((currentTime - response.createTime) >= response.timeout) {
it.remove();
response.callback.handler(null, new TimeoutException("timeout"));
}
}
if (res.isEmpty() && conn.isConnected()) {
recycle(conn);
}
}
}
});
public FullDuplexSocketTransporter(HproseTcpClient client) {
super(client);
init();
}
private void init() {
int timeout = Math.min(client.getTimeout(), client.getConnectTimeout());
timeout = Math.min(timeout, client.getReadTimeout());
timeout = Math.min(timeout, client.getWriteTimeout());
timeout = Math.max(timeout, 1000);
timer.setInterval((timeout + 1) >> 1);
start();
}
private void recycle(Connection conn) {
conn.setTimeout(client.getIdleTimeout(), TimeoutType.IDLE_TIMEOUT);
}
protected final void send(Connection conn, Request request) {
Map res = responses.get(conn);
if (res != null) {
if (res.size() < 10) {
int id = nextId.incrementAndGet() & 0x7fffffff;
res.put(id, new Response(request.callback, request.timeout));
conn.send(request.buffer, id);
}
else {
idleConnections.offer(conn);
requests.offer(request);
}
}
}
protected final int geRealPoolSize() {
return responses.size();
}
@Override
@SuppressWarnings("unchecked")
public final void close() {
timer.clear();
close((Map)(Object)responses);
}
public void onConnect(Connection conn) {
responses.put(conn, new ConcurrentHashMap());
}
public void onConnected(Connection conn) {
idleConnections.offer(conn);
recycle(conn);
}
public final void onTimeout(Connection conn, TimeoutType type) {
if (TimeoutType.CONNECT_TIMEOUT == type) {
responses.remove(conn);
Request request;
while ((request = requests.poll()) != null) {
request.callback.handler(null, new TimeoutException("connect timeout"));
}
}
else if (TimeoutType.IDLE_TIMEOUT != type) {
Map res = responses.get(conn);
if (res != null) {
Iterator> it = res.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
it.remove();
Response response = entry.getValue();
response.callback.handler(null, new TimeoutException(type.toString()));
}
}
}
}
public final void onReceived(Connection conn, ByteBuffer data, Integer id) {
Map res = responses.get(conn);
if (res != null) {
Response response = res.remove(id);
if (response != null) {
if (data.position() != 0) {
data.flip();
}
response.callback.handler(data, null);
}
if (res.isEmpty()) {
recycle(conn);
}
}
}
public final void onSended(Connection conn, Integer id) {
idleConnections.offer(conn);
}
public final void onError(Connection conn, Exception e) {
Map res = responses.remove(conn);
if (res != null) {
Iterator> it = res.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
it.remove();
Response response = entry.getValue();
response.callback.handler(null, e);
}
}
}
}
final class HalfDuplexSocketTransporter extends SocketTransporter {
private final static Response nullResponse = new Response(null, 0);
private final Map responses = new ConcurrentHashMap();
private final Timer timer = new Timer(new Runnable() {
public void run() {
long currentTime = System.currentTimeMillis();
Iterator> it = responses.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
Connection conn = entry.getKey();
Response response = entry.getValue();
if ((currentTime - response.createTime) >= response.timeout) {
it.remove();
response.callback.handler(null, new TimeoutException("timeout"));
conn.close();
}
}
}
});
public HalfDuplexSocketTransporter(HproseTcpClient client) {
super(client);
init();
}
private void init() {
int timeout = Math.min(client.getTimeout(), client.getConnectTimeout());
timeout = Math.min(timeout, client.getReadTimeout());
timeout = Math.min(timeout, client.getWriteTimeout());
timeout = Math.max(timeout, 1000);
timer.setInterval((timeout + 1) >> 1);
start();
}
private void recycle(Connection conn) {
idleConnections.offer(conn);
conn.setTimeout(client.getIdleTimeout(), TimeoutType.IDLE_TIMEOUT);
}
protected final void send(Connection conn, Request request) {
responses.put(conn, new Response(request.callback, request.timeout));
conn.send(request.buffer, null);
}
protected final int geRealPoolSize() {
return responses.size();
}
@Override
@SuppressWarnings("unchecked")
public final void close() {
timer.clear();
close((Map)(Object)responses);
}
public void onConnect(Connection conn) {
responses.put(conn, nullResponse);
}
public void onConnected(Connection conn) {
recycle(conn);
}
public final void onTimeout(Connection conn, TimeoutType type) {
if (TimeoutType.CONNECT_TIMEOUT == type) {
responses.remove(conn);
Request request;
while ((request = requests.poll()) != null) {
request.callback.handler(null, new TimeoutException("connect timeout"));
}
}
else if (TimeoutType.IDLE_TIMEOUT != type) {
Response response = responses.put(conn, nullResponse);
if (response != null && response != nullResponse) {
response.callback.handler(null, new TimeoutException(type.toString()));
}
}
conn.close();
}
public final void onReceived(Connection conn, ByteBuffer data, Integer id) {
Response response = responses.put(conn, nullResponse);
recycle(conn);
if (response != null && response != nullResponse) {
if (data.position() != 0) {
data.flip();
}
response.callback.handler(data, null);
}
}
public final void onSended(Connection conn, Integer id) {}
public final void onError(Connection conn, Exception e) {
Response response = responses.remove(conn);
if (response != null && response != nullResponse) {
response.callback.handler(null, e);
}
}
}
final class Result {
public volatile ByteBuffer buffer;
public volatile Throwable e;
}
public class HproseTcpClient extends HproseClient {
private static int reactorThreads = 2;
public static int getReactorThreads() {
return reactorThreads;
}
public static void setReactorThreads(int aReactorThreads) {
reactorThreads = aReactorThreads;
}
private volatile boolean fullDuplex = false;
private volatile boolean noDelay = false;
private volatile int maxPoolSize = 2;
private volatile int idleTimeout = 30000;
private volatile int readTimeout = 30000;
private volatile int writeTimeout = 30000;
private volatile int connectTimeout = 30000;
private volatile boolean keepAlive = true;
private final SocketTransporter fdTrans = new FullDuplexSocketTransporter(this);
private final SocketTransporter hdTrans = new HalfDuplexSocketTransporter(this);
public HproseTcpClient() {
super();
}
public HproseTcpClient(String uri) {
super(uri);
}
public HproseTcpClient(HproseMode mode) {
super(mode);
}
public HproseTcpClient(String uri, HproseMode mode) {
super(uri, mode);
}
public HproseTcpClient(String[] uris) {
super(uris);
}
public HproseTcpClient(String[] uris, HproseMode mode) {
super(uris, mode);
}
public static HproseClient create(String uri, HproseMode mode) throws IOException, URISyntaxException {
String scheme = (new URI(uri)).getScheme().toLowerCase();
if (!scheme.equals("tcp") &&
!scheme.equals("tcp4") &&
!scheme.equals("tcp6")) {
throw new HproseException("This client doesn't support " + scheme + " scheme.");
}
return new HproseTcpClient(uri, mode);
}
public static HproseClient create(String[] uris, HproseMode mode) throws IOException, URISyntaxException {
for (int i = 0, n = uris.length; i < n; ++i) {
String scheme = (new URI(uris[i])).getScheme().toLowerCase();
if (!scheme.equals("tcp") &&
!scheme.equals("tcp4") &&
!scheme.equals("tcp6")) {
throw new HproseException("This client doesn't support " + scheme + " scheme.");
}
}
return new HproseTcpClient(uris, mode);
}
@Override
public final void close() {
fdTrans.close();
hdTrans.close();
super.close();
}
public final boolean isFullDuplex() {
return fullDuplex;
}
public final synchronized void setFullDuplex(boolean fullDuplex) {
this.fullDuplex = fullDuplex;
}
public final boolean isNoDelay() {
return noDelay;
}
public final void setNoDelay(boolean noDelay) {
this.noDelay = noDelay;
}
public final int getMaxPoolSize() {
return maxPoolSize;
}
public final void setMaxPoolSize(int maxPoolSize) {
if (maxPoolSize < 1) throw new IllegalArgumentException("maxPoolSize must be great than 0");
this.maxPoolSize = maxPoolSize;
}
public final int getIdleTimeout() {
return idleTimeout;
}
public final void setIdleTimeout(int idleTimeout) {
if (idleTimeout < 0) throw new IllegalArgumentException("idleTimeout must be great than -1");
this.idleTimeout = idleTimeout;
}
public final int getReadTimeout() {
return readTimeout;
}
public final void setReadTimeout(int readTimeout) {
if (readTimeout < 1) throw new IllegalArgumentException("readTimeout must be great than 0");
this.readTimeout = readTimeout;
}
public final int getWriteTimeout() {
return writeTimeout;
}
public final void setWriteTimeout(int writeTimeout) {
if (writeTimeout < 1) throw new IllegalArgumentException("writeTimeout must be great than 0");
this.writeTimeout = writeTimeout;
}
public final int getConnectTimeout() {
return connectTimeout;
}
public final void setConnectTimeout(int connectTimeout) {
if (connectTimeout < 1) throw new IllegalArgumentException("connectTimeout must be great than 0");
this.connectTimeout = connectTimeout;
}
public final boolean isKeepAlive() {
return keepAlive;
}
public final void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
@Override
protected final ByteBuffer sendAndReceive(ByteBuffer request, int timeout) throws Throwable {
final Result result = new Result();
final Semaphore sem = new Semaphore(0);
sendAndReceive(request, new ReceiveCallback() {
public void handler(ByteBuffer buffer, Throwable e) {
result.buffer = buffer;
result.e = e;
sem.release();
}
}, timeout);
try {
sem.acquire();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
if (result.e == null) {
return result.buffer;
}
throw result.e;
}
@Override
protected final void sendAndReceive(ByteBuffer request, ReceiveCallback callback, int timeout) {
if (fullDuplex) {
fdTrans.send(request, callback, timeout);
}
else {
hdTrans.send(request, callback, timeout);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy