`
hpt321
  • 浏览: 9234 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

基于XSocket框架的socket编程技巧(同步通信)

    博客分类:
  • Java
阅读更多

基于XSocket框架的socket编程技巧(同步通信)

最近在做socket通信编程,现总结如下,关于XSocket的大话就不再多说了,google一下一大片。

一、  Server

Socket监听如下:

ServerHandler handler = new ServerHandler();

//创建一个服务端的对象  

IServer srv = new Server(address, port, handler);

//设置当前的采用的异步模式  

srv.setFlushmode(FlushMode.ASYNC);

//设置连接的超时时间和最大空闲时间

srv.setConnectionTimeoutMillis(5000);

srv.setIdleTimeoutMillis(10000);

//启动监听

srv.start();

 

其中如下两个方法的设置与ServerHandler的实现有关系,

srv.setConnectionTimeoutMillis(5000);

srv.setIdleTimeoutMillis(10000);

 

下面再看ServerHandler

public class ServerHandler implements IDataHandler, IConnectHandler,

    IIdleTimeoutHandler, IConnectionTimeoutHandler, IDisconnectHandler

{

  public boolean onConnect(INonBlockingConnection nbc) throws IOException,

      BufferUnderflowException, MaxReadSizeExceededException

  {

    return true;

  }

  public boolean onDisconnect(INonBlockingConnection nbc) throws IOException

  {

    return true;

  } 

  public boolean onData(INonBlockingConnection nbc) throws IOException,

      BufferUnderflowException, ClosedChannelException,

      MaxReadSizeExceededException

  {

    return true;

  }

  public boolean onIdleTimeout(INonBlockingConnection connection)

      throws IOException

  {  

      System.out.println("onIdleTimeout");

    return false;

  }

  public boolean onConnectionTimeout(INonBlockingConnection connection)

      throws IOException

  {

      System.out.println("onConnectionTimeout");

    return true;

  }

 

ServerHandler分别实现了以下接口

IDataHandler, IConnectHandler,IIdleTimeoutHandler, IConnectionTimeoutHandler, IDisconnectHandler

 

其中主要说一下IDataHandlerIIdleTimeoutHandlerIConnectionTimeoutHandler吧。

 

首先说明一下,socket连接的生命周期与server端的connectionTimeoutidleTimeoutclient端有关系。

 

A、 IDataHandler中的事件onData事件就是处理业务逻辑的,当客户端发送一个业务请求时,会触发此事件。

B、 IIdleTimeoutHandler中的onIdleTimeout事件是在socket连接空闲超时被触发,这个超时时间就是刚刚srv.setIdleTimeoutMillis(10000)设置的值“10000”,单位毫秒。此事件返回一个bool状态,

  (1)   如果返回truexsocket则认为这事件已经关闭了此连接,那么我们在此事件中是否去关闭连接了呢?前面说了这个连接的生命周期和与server端的connectionTimeoutidleTimeoutclient端有关,如下解释,

1)、如果close();,那么就不多说了;

2)、如果没有close();,此时又和IConnectionTimeoutHandler的事件onConnectionTimeoutclient有关。如果onConnectionTimeout返回false,则此事件被触发并在事件结束后,则xsocket关闭连接;如果onConnectionTimeout返回true,则此连接由client负责关闭。

  (2)   如果返回false,相当于onIdleTimeout没有做任何处理,则此时又和IConnectionTimeoutHandler的事件onConnectionTimeout有关。如果onConnectionTimeout事件返回true,则onIdleTimeout事件被触发并在事件结束后由xsocket关闭连接;如果onConnectionTimeout事件返回false,则onConnectionTimeoutonIdleTimeout任何一个事件被触发后就会由xsocket关闭连接。

 

C、 IConnectionTimeoutHandler中的onConnectionTimeout事件是在socket建立连接后,经过srv.setConnectionTimeoutMillis(5000)这个方法中的值时间后触发此事件,强调是指建立连接时,不是指上一次通信时间。此事件返回一个bool状态:

 

  (1)   如果返回true,如下解释,

IIdleTimeoutHandler的事件onIdleTimeoutclient有关。如果onIdleTimeout返回false,则在onIdleTimeout事件被触发并在事件结束后,则xsocket关闭连接;如果onIdleTimeout返回true,则此连接由client负责关闭。

  (2)   如果返回false,解释如下:

IIdleTimeoutHandler的事件onIdleTimeout有关。如果onIdleTimeout事件返回true,则onConnectionTimeout事件被触发并在事件结束后由xsocket关闭连接;如果onIdleTimeout事件返回false,则onConnectionTimeoutonIdleTimeout任何一个事件被触发后就会由xsocket关闭连接。

 

终上,关于在服务器端socket连接的生命周期如下表(以下事件中都没有通过编程主动关闭连接):

 

onIdleTimeout

返回值

onConnectionTimeout

返回值

何时关闭

true

true

client端负责

false

true

idleTimeout到时

true

false

connectionTimeout到时

false

false

idleTimeoutconnectionTimeout的最小值到达时

 

说明一下connectionTimeoutidleTimeout从何时开始计时:

connectionTimeout是从建立连接开始计时;

idleTimeout是从建立连接或最后一次触发onData事件时开始计时;

 

 

二、  Client

 

1、如何创建一个同步socket连接?

   A、 可以通过直接new 一个BlockingConnection(String hostname, int port)

   B、 也可通过异步连接构建,如new BlockingConnection(INonBlockingConnection delegate)

 

 

2、当然XSocket也提供了连接池,同样包括同步连接池和异步连接池。

BlockingConnectionPool pool = new BlockingConnectionPool();这样就创建了一个同步连接池,既然是池,肯定会有池的大小了,pool.setMaxActivePerServer(poolSize);这是为池设置每个server池的大小,也可以设置池的总大小,如果不设置,默认为值为Integer.MAX_VALUE

 

如何从池中获取一个连接呢,如IBlockingConnection bc = pool.getBlockingConnection(host,port);有很多重载方法了。

当获取这个连接之后,我们可以通过设置如下参数进行调整优化:

 

设置连接超时时间

bc.setConnectionTimeoutMillis(connectTimeoutMillis);

设置连接最大空闲时间

bc.setIdleTimeoutMillis(this.idleTimeoutMillis);

是否自动刷新缓存

bc.setAutoflush(false);

这项时设置在真正要关闭连接时,client端是否要立即释放随机分配的端口,默认不会立即释放端口,需要等待1~4分钟,连接一直处于TIME_WAIT状态,如果这样设置,当关闭连接时,就会立即释放端口。

bc.setOption(IBlockingConnection.SO_LINGER , "0");

 

当然当连接使用完以后,需要调用bc.close();放回连接池中,如果close失败,那就要调用pool.destroy(bc)真正的关闭连接了。

 

仍需要解释下这里的connectTimeoutMillisidleTimeoutMillis了,

connectTimeoutMillis是池中获取连接开始算起的;

idleTimeoutMillis是在调用close方法后开始算起的;

 

client端连接的生命周期为connectTimeoutMillisidleTimeoutMillis的最小值

1
1
分享到:
评论
2 楼 tony_zq 2011-12-08  
还有一个问题,就是如果设置:
bc.setIdleTimeoutMillis(1000); //sets the idle timeout in millis,在调用close方法后开始算起的

那么1秒后,连接不是idle,而是Destroyed

INFO (ConnectionPool.java:67) - getNumIdle:0
INFO (ConnectionPool.java:68) - getNumActive:0
INFO (ConnectionPool.java:69) - getNumCreated:5
INFO (ConnectionPool.java:70) - getNumDestroyed:5

bc.close(); 的意思是// always close the connection! (the connection will be returned into the connection pool),同时设置了bc.setIdleTimeoutMillis(1000);按理结果应该是:
INFO (ConnectionPool.java:67) - getNumIdle:5
INFO (ConnectionPool.java:68) - getNumActive:0
INFO (ConnectionPool.java:69) - getNumCreated:5
INFO (ConnectionPool.java:70) - getNumDestroyed:0

问题出在哪里??????

1 楼 tony_zq 2011-12-08  
同样的host and port,"bc = pool.getBlockingConnection(host, port);"为什么建立新连接?

代码如下:

package com.tmp.xSocket;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xsocket.connection.BlockingConnectionPool;
import org.xsocket.connection.IBlockingConnection;
import org.xsocket.connection.MaxConnectionsExceededException;
import com.zhangqing.util.DocbookXSDCheck;
public class ConnectionPool {
protected static Log logger = LogFactory.getLog(ConnectionPool.class); 
private static int MAXCON = 10000;
private final static BlockingConnectionPool pool = new BlockingConnectionPool();
static {
  pool.setMaxActive(MAXCON);
  pool.setMaxIdle(MAXCON/2);
   
}
private static void sendMessage(String host, int port, String msg) {
  IBlockingConnection bc = null;
  try {
  // retrieve a connection (if no connection is in pool, a new one will be created)
  bc = pool.getBlockingConnection(host, port);
  logger.info("bc.getId(): " + bc.getId());
  bc.write(msg); //发送信息
   
  //接收
  ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  int length = bc.read(byteBuffer);
  logger.info("length: " + length);
  byteBuffer.flip();
  byte[] content = new byte[byteBuffer.limit()];
  byteBuffer.get(content); // 从ByteBuffer中读取数据到byte数组中
  logger.info(new String(content));
  byteBuffer.clear();
  bc.flush();
  // always close the connection! (the connection will be returned into the connection pool)
  bc.close(); 
  } catch (IOException ioe) {
  logger.info(ioe.toString());
  if (bc != null) {
  try {
  // if the connection is invalid -> destroy it , it will not return to the pool)
  pool.destroy(bc);
  } catch (Exception ignore) {
  }
  }
  }
}
 
private static void displayPoolInfo(){
  logger.info("--------------------------------------------------------");
  logger.info("getMaxActive:" + pool.getMaxActive());
  logger.info("getMaxActivePerServer:" + pool.getMaxActivePerServer());
  logger.info("getMaxIdle:" + pool.getMaxIdle());
  logger.info("getNumIdle:" + pool.getNumIdle());
  logger.info("getNumActive:" + pool.getNumActive());
  logger.info("getNumCreated:" + pool.getNumCreated());
  logger.info("getNumDestroyed:" + pool.getNumDestroyed());
  logger.info("getNumPendingGet:" + pool.getNumPendingGet());
  logger.info("getNumTimeoutPooledMaxIdleTime:" + pool.getNumTimeoutPooledMaxIdleTime());
  logger.info("getNumTimeoutPooledMaxLifeTime:" + pool.getNumTimeoutPooledMaxLifeTime());
  logger.info("getPooledMaxIdleTimeMillis:" + pool.getPooledMaxIdleTimeMillis());
  logger.info("getPooledMaxLifeTimeMillis:" + pool.getPooledMaxLifeTimeMillis());
  logger.info("isOpen:" + pool.isOpen());
  for (String str: pool.getActiveConnectionInfos()){
  logger.info(str);
  
  }
  logger.info("--------------------------------------------------------");
  
}
 
public static void main(String[] args) throws Exception {
  for (int i = 0; i < 5; i++){
  sendMessage("127.0.0.1",8889,"Send messsage to server.");
  Thread.sleep(1000);
  }
  displayPoolInfo();
  
}
}

And the log is :

INFO (ConnectionPool.java:35) - bc.getId(): 74396444134120d6da52bb96e33C1I0
INFO (ConnectionPool.java:44) - server received data from client sucessful
INFO (ConnectionPool.java:35) - bc.getId(): 74396444134120d6da52bb96e33C2I0
INFO (ConnectionPool.java:44) - server received data from client sucessful
INFO (ConnectionPool.java:35) - bc.getId(): 74396444134120d6da52bb96e33C3I0
INFO (ConnectionPool.java:44) - server received data from client sucessful
INFO (ConnectionPool.java:35) - bc.getId(): 74396444134120d6da52bb96e33C4I0
INFO (ConnectionPool.java:44) - server received data from client sucessful
INFO (ConnectionPool.java:35) - bc.getId(): 74396444134120d6da52bb96e33C5I0
INFO (ConnectionPool.java:44) - server received data from client sucessful
INFO (ConnectionPool.java:63) - --------------------------------------------------------
INFO (ConnectionPool.java:64) - getMaxActive:10000
INFO (ConnectionPool.java:65) - getMaxActivePerServer:2147483647
INFO (ConnectionPool.java:66) - getMaxIdle:5000
INFO (ConnectionPool.java:67) - getNumIdle:0
INFO (ConnectionPool.java:68) - getNumActive:5
INFO (ConnectionPool.java:69) - getNumCreated:5
INFO (ConnectionPool.java:70) - getNumDestroyed:0
INFO (ConnectionPool.java:71) - getNumPendingGet:0
INFO (ConnectionPool.java:72) - getNumTimeoutPooledMaxIdleTime:0
INFO (ConnectionPool.java:73) - getNumTimeoutPooledMaxLifeTime:0
INFO (ConnectionPool.java:74) - getPooledMaxIdleTimeMillis:2147483647
INFO (ConnectionPool.java:75) - getPooledMaxLifeTimeMillis:2147483647
INFO (ConnectionPool.java:76) - isOpen:true
INFO (ConnectionPool.java:78) - /127.0.0.1:3608 -> /127.0.0.1:8889 [74396444134120d6da52bb96e33C1] creationTime=2011.12.06 14:26:37, ageMillis=5141, elapsedLastUsageMillis=5031, countUsage=1, isReusable=true
INFO (ConnectionPool.java:78) - /127.0.0.1:3613 -> /127.0.0.1:8889 [74396444134120d6da52bb96e33C2] creationTime=2011.12.06 14:26:38, ageMillis=4031, elapsedLastUsageMillis=4031, countUsage=1, isReusable=true
INFO (ConnectionPool.java:78) - /127.0.0.1:3614 -> /127.0.0.1:8889 [74396444134120d6da52bb96e33C3] creationTime=2011.12.06 14:26:39, ageMillis=3031, elapsedLastUsageMillis=3031, countUsage=1, isReusable=true
INFO (ConnectionPool.java:78) - /127.0.0.1:3615 -> /127.0.0.1:8889 [74396444134120d6da52bb96e33C4] creationTime=2011.12.06 14:26:40, ageMillis=2031, elapsedLastUsageMillis=2031, countUsage=1, isReusable=true
INFO (ConnectionPool.java:78) - /127.0.0.1:3616 -> /127.0.0.1:8889 [74396444134120d6da52bb96e33C5] creationTime=2011.12.06 14:26:41, ageMillis=1031, elapsedLastUsageMillis=1031, countUsage=1, isReusable=true
INFO (ConnectionPool.java:81) - --------------------------------------------------------

Why 5 connections has been created? In my opinion, only one connection should be created, because :
 
  for (int i = 0; i < 5; i++){
  sendMessage("127.0.0.1",8889,"Send messsage to server.");
  Thread.sleep(1000);
  }

同样的address and port, and "bc = pool.getBlockingConnection(host, port);" means "getting a pool connection for the given address. If no free connection is in the pool, a new one will be created. "

但是从第二次循环开始,该地址和端口已经有一个连接了,就不应该建立连接了.

相关推荐

Global site tag (gtag.js) - Google Analytics