XlightWeb 的使用

XlightWeb 的使用


本文目的学会使用HttpClient ,同步请求方式, 异步请求方式, timeout设置预处理,发送大数据。

1  XlightWeb是基于xsockets的使用了NIO的框架。
   XlightWeb可以构建同步阻塞的或者异步非阻塞的http客户端和http服务器。


2 先看客户端的构建
   HttpClient
    
XlightWeb 的使用_第1张图片
这幅图的含义是:HttpClient 实现了 IHttpClientEndpoint接口,里边含有若干HttpClientConnection。
而 HttpClientconnection实现了INonBlockingConnection的tcp链接。 也就是说HttpClient是一个非阻塞
的连接池。
    示例1 用call方法发送请求  
    HttpClient httpClient = new HttpClient();

   //设置一些httpclient的属性
   httpClient.setFollowsRedirect(true);  
   httpClient.setAutoHandleCookies(false);
 
   //生成request
   IHttpRequest request = new GetRequest("http://www.sohu.com");
   //设置request属性
   request.setHeader("Accept-Encoding", "gzip,deflate");
   
   //call方法是同步方法,知道收到http头后才返回,这个方法会阻塞在这里。
   //这里也可以用非阻塞的方式send方法访问 下边示例介绍
   HttpResponse response =   (HttpResponse)httpClient .call(request);
   System.out.println(response.getResponseHeader());

   //获得http头后,http的body并没有收完,可以用response获得BlockingBodyDataSource 
   //或者 NonBlockingBodyDataSource 这里用了阻塞同步的方式
   BlockingBodyDataSource bodyDataSource = response.getBlockingBody() ;
   String data = bodyDataSource.readString( ); 
   System.out.println(data);
   httpClient.close();

  
     示例2 加入 Interceptor 
     Interceptor 允许程序在发送request的是后就是调用call方法之后,call方法返回之前,做一些处理,如
   把这个request记录在日志上。上边代码加入如下一句:
    
     .......
    httpClient.addInterceptor(new HeaderLogFilter());
    ..... .

     //最为一个interceptor 要实现 IHttpRequestHandler 接口的onRequest方法
    class HeaderLogFilter implements IHttpRequestHandler {

              public void onRequest(final IHttpExchange exchange) throws IOException {
                 System.out.println("-------------------intercepter onRequest----------------"); 
                 System.out.println(exchange.getRequest().getRequestHeader());
                 exchange.forward(exchange.getRequest());
           }
        

     示例3 自动重试  
   
      GET DELETE PUT 方法是幂等的,所以多次一样的请求服务器不会出现问题,例如get一个资源失败后再次get
    服务器可以返回一样的结果。默认情况下HttpClient在请求失败后不会自动重试,需要设置 setCallReturnOnMessage
  
     HttpClient httpClient = new HttpClient(); 
     httpClient.setCallReturnOnMessage(true); 
     IHttpResponse response = httpClient.call(new GetRequest("http://www.sohu.com"))

     示例4 HttpClient 异步send方式
     使用异步的方式有两种 一种是使用FutureResponse 一种是使用 send方法指定ResponseHandler。
     这里介绍第二种使用handler

    ......
     //发送请求时生成一个handler 来处理将来的返回
     httpClient.send(request, new MyResponseHandler());
    .....

     //实现 IHttpResponseHandler  接口的Handler
     @Execution(Execution.MULTITHREADED)
      class MyResponseHandler implements IHttpResponseHandler {

            @InvokeOn(InvokeOn.MESSAGE_RECEIVED)
           public void onResponse(IHttpResponse response) throws IOException {
              System.out.println("-------------------Handler onResponse----------------");
              System.out.println(response.getResponseHeader());
           }

           public void onException(IOException ioe) {
              System.out.println("error occured by receiving response " + ioe.toString());
           }
     }

     这里需要注意的是两个 Annotation 。
      Execution    两个参数值  MULTITHREADED 指明回调将在一个线程里完成, NONTHREADED指明回调在I/O主线程完成
    InvokeOn   连个参数 MESSAGE_RECEIVED 回调再收到body之后发生, HEADER_RECEIVED 在收到http头时发生 

     关于 Execution    的更多信息 参考 xSocket 框架图

     XlightWeb 的使用_第2张图片

    The Dispatcher (I/O thread) is responsible to perform the socket read & write I/O operations and to delegate the call back handling. By default number of CPUs + 1  dispatchers will be created. A connection is bound to one dispatcher during the total lifetime.
     xSocket uses the worker pool only to perform the handler's call back method. The pool can be set by calling the appropriate setter method. A worker pool has to implement the java.util.concurrent.Executor interface. 

   xSocket 底层有个IO线程负责Connection的读写,IO线程个数为cpu个数+1 ,而handler回调是由一个线程池来处理,
     每个connection是绑定在一个IO线程上的。  所以如果把回调放入到IO线程中处理时 一定注意能有异常和阻塞方法调用。
   否则会只是整个IO线程阻塞。

   示例5 处理timeout
   有三种timeout类型可以设置,各个类型代表的时间如图

  • ConnectionTimeout : 获得链接的时间限制
  • ResponseTimeout : 获得响应的时间限制, 从send到获得header的时间。
  • BodyDataReceiveTimeout : 获取body的时间间隔最长是多少。
XlightWeb 的使用_第3张图片
    设置timeout
     httpClient .setConnectionTimeoutMillis(24L * 60L * 60L * 1000L); 
     httpClient .setResponseTimeoutMillis(2L * 60L * 1000L); 
     httpClient .setBodyDataReceiveTimeoutMillis(30L * 1000L);

     timeout的处理
     使handler实现接口 IHttpSocketTimeout  的 onException(SocketTimeoutException stoe) 方法
    class MyHandler implements IHttpResponseHandler, IHttpSocketTimeoutHandler { 
               public void onResponse(IHttpResponse response) throws IOException { // ... } 
               public void onException(IOException ioe) { // ... } 
               public void onException(SocketTimeoutException stoe) { // response timeout occured //} 
               }
     
  示例6 异步使用流方式发送request的body
    这种方法在上传文件等发送大数据的时候很有用。
    1  因为body比较大 所以先把reqeust的header 和 body的length发送出去
    2 打开文件构建 FileChannel 然后用 BodyDataSink  传送。 BodyDataSink来自send函数返回
     // create a response handler
     IHttpResponseHandler hdl = new MyResponseHandler();

     // get the file to transfer
     RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
     FileChannel fc = raf.getChannel();
     int bodyLength = (int) fc.size();      

     // 先构建header发送
     IHttpRequestHeader header = new HttpRequestHeader("POST", "http://server:80/in", "text/plain");

     // 如果指定了bodylength 那么就会用非chunk的方式传送数据
     BodyDataSink bodyDataSink = httpClient.send(header, bodyLength, hdl);

     // 这里存在一个同步异步的问题
     bodyDataSink.transferFrom(fc);

     // finish the send procedure
     bodyDataSink.close();
    
   
    这里需要改进一下发送数据时的方式,默认情况下BodyDataSink是同步发送的,也就是把文件里的数据同步自动写入到了
   底层的IO中,这里会造成效率的地下。需要设置为异步的 改动如下

     bodyDataSink.setAutoflush(false);            // 取消自动写入
     bodyDataSink.setFlushmode(FlushMode.ASYNC);  // 设置为异步方式

     // 写入数据 
     bodyDataSink.write(bytebuffer);
   //手动flush到底层IO
     bodyDataSink.flush();

   同时要注意,write时候的bytebuffer 不能重用。 如果需要重复使用write时候的bytebuffer  会造成和底层内部IO线程的竞争,致使数据坏掉。如下摘抄自Xsocket

   By using the  WritableByteChannel  interface methods write(ByteBuffer) and write(ByteBuffer[]) some restriction exits. Calling such a write method in mode ASYNC causes that the byte buffer will be read asynchronously by the internal I/O thread. If the byte buffer will be accessed (reused) after calling the write method, race conditions will occur. The write(ByteBuffer) and write(ByteBuffer[]) should only called in ASYNC mode, if the byte buffer will not be accessed (reused) after the write operation.

你可能感兴趣的:(thread,框架,socket,Exchange)