<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-4  評論-10  文章-0  trackbacks-0
    2012年8月29日編寫   
    2012年8月29日修改
    1. 線程組,在我們測試方案里面,每個線程模擬一個用戶,執行用戶的登錄、等等等一系列的操作。由于我們的項目是長連接的,如何能實現多個sample公用一個長連接客戶端,考慮了很久,最后實現方法如下:
     1 package tea.client.network;
     2 /**
     3  * @author Teaey
     4  * @creation 2012-8-25
     5  */
     6 public class NetworkClientHolder
     7 {
     8     /**
     9      * 這里使用ThradLocal存儲BaseClient
    10      * 方便一輪測試的每個sample都是由同一個socketChannel發送
    11      * 更真實的模擬用戶
    12      */
    13     private static ThreadLocal<BaseClient> clientHolder = new ThreadLocal<BaseClient>();
    14     public static BaseClient getClient(String ip, String port)
    15     {
    16         BaseClient client = clientHolder.get();
    17         if (null == client)
    18         {
    19             client = new BaseClient(ip, port);
    20             client.connect();
    21             clientHolder.set(client);
    22         }
    23         return client;
    24     }
    25 }
    26 
    代碼中使用thread_local保存Socket客戶端,這樣每個sample中發送數據的客戶端都是從這里拿的,就可以保證長連接的情況下,socket不會重復創建,很好的模擬了用戶。
    當然不單單是鏈接可以保存,所有需要在線程中共享的數據都可以通過這種方法來實現。
    2. 接下來是如何封裝發送請求的客戶端,這里用的netty,具體可以根據項目情況使用mina或者nio都可以。代碼直接明了^_^:
      1 package tea.client.network;
      2 
      3 import java.net.InetSocketAddress;
      4 import java.util.concurrent.Executors;
      5 import org.jboss.netty.bootstrap.ClientBootstrap;
      6 import org.jboss.netty.channel.Channel;
      7 import org.jboss.netty.channel.ChannelFuture;
      8 import org.jboss.netty.channel.ChannelHandlerContext;
      9 import org.jboss.netty.channel.ChannelPipeline;
     10 import org.jboss.netty.channel.ChannelPipelineFactory;
     11 import org.jboss.netty.channel.ChannelStateEvent;
     12 import org.jboss.netty.channel.Channels;
     13 import org.jboss.netty.channel.ExceptionEvent;
     14 import org.jboss.netty.channel.MessageEvent;
     15 import org.jboss.netty.channel.SimpleChannelHandler;
     16 import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
     17 import tea.common.network.ClientDecoder;
     18 import tea.common.network.ClientEncoder;
     19 import tea.common.network.ClientMessage;
     20 
     21 /**
     22  * @author Teaey
     23  * @creation 2012-8-25
     24  */
     25 public class BaseClient
     26 {
     27     public BaseClient(String ip, String port)
     28     {
     29         this.ip = ip;
     30         this.port = port;
     31     }
     32     private String           ip;
     33     private String           port;
     34     private Channel          channel;
     35     private ClientBootstrap  bootstrap;
     36     private Object           syn             = new Object();
     37     private static final int Receive_Timeout = 10000;       //ms
     38     private ClientMessage    response        = null;
     39     public void connect()
     40     {
     41         bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
     42         bootstrap.setOption("tcpNoDelay", true);
     43         bootstrap.setPipelineFactory(new ClientPipelineFactory());
     44         while (true)
     45         {
     46             ChannelFuture future = bootstrap.connect(new InetSocketAddress(ip, Integer.parseInt(port)));
     47             future.awaitUninterruptibly(5000);
     48             if (future.isDone())
     49             {
     50                 channel = future.getChannel();
     51                 if (channel != null && channel.isConnected())
     52                 {
     53                     break;
     54                 }
     55             }
     56         }
     57     }
     58     public void disconnect()
     59     {
     60         if (channel.isConnected())
     61         {
     62             channel.disconnect();
     63         }
     64     }
     65     public boolean isConnected()
     66     {
     67         return channel.isConnected();
     68     }
     69     public void close()
     70     {
     71         if (this.channel.isOpen())
     72         {
     73             this.channel.close();
     74         }
     75         bootstrap.releaseExternalResources();
     76     }
     77     /**
     78      * 發送消息,無需返回
     79      */
     80     public void send(ClientMessage message)
     81     {
     82         channel.write(message);
     83     }
     84     /**
     85      * 發送消息,等待返回
     86      */
     87     public ClientMessage sendWaitBack(ClientMessage message)
     88     {
     89         response = null;
     90         try
     91         {
     92             channel.write(message);
     93             synchronized (syn)
     94             {
     95                 try
     96                 {
     97                     syn.wait(Receive_Timeout);
     98                 } catch (InterruptedException e)
     99                 {
    100                     e.printStackTrace();
    101                 }
    102             }
    103             if (null == response)
    104             {
    105                 System.err.println("Receive response timeout");
    106             }
    107         } catch (Exception e)
    108         {
    109             e.printStackTrace();
    110         }
    111         return response;
    112     }
    113     class ClientPipelineFactory implements ChannelPipelineFactory
    114     {
    115         public ChannelPipeline getPipeline() throws Exception
    116         {
    117             ChannelPipeline p = Channels.pipeline();
    118             p.addLast("frameDecoder", new ClientDecoder());
    119             p.addLast("fremeEncoder", new ClientEncoder());
    120             p.addLast("logicHandler", new ClientMsgHandler());
    121             return p;
    122         }
    123     }
    124     class ClientMsgHandler extends SimpleChannelHandler
    125     {
    126         public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception
    127         {
    128             Object obj = e.getMessage();
    129             if (obj instanceof ClientMessage)
    130             {
    131                 ClientMessage msg = (ClientMessage) obj;
    132                 response = msg;
    133                 synchronized (syn)
    134                 {
    135                     syn.notifyAll();
    136                 }
    137             }
    138         }
    139         public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
    140         {
    141             System.out.println("connected server:" + ctx.getChannel());
    142         }
    143         public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
    144         {
    145             System.out.println("disconnected server:" + ctx.getChannel());
    146         }
    147         public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception
    148         {
    149             System.out.println("Error in exceptionCaught:" + e.getCause());
    150         }
    151     }
    152 }
    153 
    這段代碼展示了我們的客戶端,這里所有的請求有兩種發送模式,一種是發送并阻塞等待返回(sendWaitBack
    ),第二種就是直接發送(send)。
    3. 有了發送請求的客戶端,那如何能夠更簡單的實現一個協議好讓客戶端發送,再貼一段代碼^_^:
      1 package tea.client.network;
      2 
      3 import org.apache.jmeter.config.Arguments;
      4 import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
      5 import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
      6 import org.apache.jmeter.samplers.SampleResult;
      7 import com.google.protobuf.InvalidProtocolBufferException;
      8 import com.google.protobuf.MessageLite;
      9 
     10 /**
     11  * @author Teaey
     12  * @creation 2012-8-25
     13  */
     14 public abstract class BaseSample extends AbstractJavaSamplerClient
     15 {
     16     public static final String PARAM_IP   = "ip";
     17     public static final String PARAM_PORT = "port";
     18     public static final String VAR_IP     = "${ip}";
     19     public static final String VAR_PORT   = "${port}";
     20     protected BaseClient       client;
     21     public void addParameter(Arguments params)
     22     {
     23     }
     24     /**
     25      * Jmeter獲取消息參數,默認配置ip和port兩個參數
     26      * 如果子類有更多參數,調用super.getDefaultParameters()獲取Arguments后,繼續設置其他方法
     27      */
     28     @Override
     29     public Arguments getDefaultParameters()
     30     {
     31         System.out.println("1.getDefaultParameters");
     32         Arguments params = new Arguments();
     33         params.addArgument(PARAM_IP, VAR_IP);
     34         params.addArgument(PARAM_PORT, VAR_PORT);
     35         addParameter(params);
     36         return params;
     37     }
     38     /**
     39      * runTest的前置方法
     40      */
     41     @Override
     42     public void setupTest(JavaSamplerContext context)
     43     {
     44         System.out.println("2.setupTest:" + context.containsParameter(PARAM_IP));
     45         String ip = context.getParameter(PARAM_IP);
     46         String port = context.getParameter(PARAM_PORT);
     47         this.client = NetworkClientHolder.getClient(ip, port);
     48         System.out.println("thread--->" + Thread.currentThread().getId() + " client--->" + client);
     49     }
     50     /**
     51      * Jmeter調用,用于實際的測試
     52      */
     53     @Override
     54     public SampleResult runTest(JavaSamplerContext context)
     55     {
     56         SampleResult sample = getSample();
     57         sample.sampleStart();
     58         try
     59         {
     60             MessageLite response = doTest();
     61             String msg = response == null ? "" : response.toString();
     62             sample.setResponseMessage(msg);
     63             sample.setSuccessful(true);
     64         } catch (Exception e)
     65         {
     66             sample.setSuccessful(false);
     67             e.printStackTrace();
     68         } finally
     69         {
     70             sample.sampleEnd();
     71         }
     72         return sample;
     73     }
     74     /**
     75      * 獲取本Sample的標簽,子類實現
     76      */
     77     public abstract String getLabel();
     78     /**
     79      * 獲取一個帶標簽的Sample 
     80      */
     81     public SampleResult getSample()
     82     {
     83         SampleResult sample = new SampleResult();
     84         sample.setSampleLabel(getLabel());
     85         return sample;
     86     }
     87     /**
     88      * Jmeter調用,用于
     89      */
     90     @Override
     91     public void teardownTest(JavaSamplerContext context)
     92     {
     93         System.out.println("4.teardownTest");
     94     }
     95     /**
     96      * 需實現,具體測試的方法,調用client的send/sendWithBack發送請求
     97      * 如無返回,放回null即可 
     98      */
     99     public abstract MessageLite doTest() throws InvalidProtocolBufferException;
    100 }
    好的,這里封裝了下AbstractJavaSamplerClient,每個消息默認包含ip和port參數,這可以再jmeter的用戶變量中定義好。為了方便大家添加消息的參數,這里實現了空的
    addParameter(Arguments params)方法,這樣在具體消息中直接重寫這個方法,來添加具體的參數。是不是很方便?^_^,具體協議還需要實現的兩個方法分別是:getLabel和doTest。第一個方法時用于報告顯示的請求名字,一般定義為消息名字+“Label”就OKay。第二個方法就是我們重點重寫的方法,這里再貼段代碼,是一個具體消息的實現:
     1 package tea.client;
     2 
     3 import com.google.protobuf.InvalidProtocolBufferException;
     4 import com.google.protobuf.MessageLite;
     5 import tea.client.network.BaseSample;
     6 import tea.common.network.ClientMessage;
     7 import tea.common.network.RPC.HeartBeat_C2S;
     8 import tea.common.network.RPC.HeartBeat_S2C;
     9 
    10 /**
    11  * @author Teaey
    12  * @creation 2012-8-24
    13  */
    14 public class HeartBeatSample extends BaseSample
    15 {
    16     @Override
    17     public MessageLite doTest() throws InvalidProtocolBufferException
    18     {
    19         HeartBeat_C2S.Builder request = HeartBeat_C2S.newBuilder();
    20         request.setTimestamp(System.currentTimeMillis());
    21         ClientMessage cm = new ClientMessage();
    22         cm.setContent(request.build().toByteArray());
    23         cm.setName("HeartBeat");
    24         ClientMessage sm = client.sendWaitBack(cm);
    25         HeartBeat_S2C response = HeartBeat_S2C.parseFrom(sm.getContent());
    26         return response;
    27     }
    28     @Override
    29     public String getLabel()
    30     {
    31         return "HeartBeatSample";
    32     }
    33 }
    34 
    可以看到doTest的工作就是封裝請求,并拿到父類的client發送,然后返回響應(send方式返回null),Okay,大功告成。
    要說的就是這么多,寫得不好但屬原創,體量作者轉載請標明出處。提意見請留言或者163郵箱:masfay,感謝。
    posted on 2012-08-29 11:44 沖杯茶喝 閱讀(7153) 評論(2)  編輯  收藏

    評論:
    # re: Jmeter“Java請求”使用總結 2015-10-11 17:35 | 打雜程序員
    看了你的blog,受益匪淺~! 有個問題請教你:如果是異步的請求,應該怎樣設置SampleResult? 比如我在runTest里發一個登陸請求,它的登陸回復應該是在messageReceived里,這時runTest函數要阻塞等待么?還是jmeter根本就不適用這種場景?  回復  更多評論
      
    # re: Jmeter“Java請求”使用總結 2015-10-12 12:18 | 沖杯茶喝
    @打雜程序員
    在登錄的Sample里,需要阻塞等待登錄返回的,Jmeter可以這么做,一般單獨作為一個sample,這樣也可以統計出登錄所消耗的時間  回復  更多評論
      

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 四虎成人免费网站在线| 亚洲精品视频在线免费| 亚洲中文字幕无码亚洲成A人片| 国产免费AV片在线观看| 91精品国产免费网站| 曰皮全部过程视频免费国产30分钟| 亚洲av无码片在线观看| 日韩吃奶摸下AA片免费观看| 亚洲成AV人片久久| 免费人成网站在线观看10分钟| 伊人久久精品亚洲午夜| 在线综合亚洲中文精品| 国产精品免费看久久久香蕉| 亚洲国产综合人成综合网站| 97亚洲熟妇自偷自拍另类图片| 久久久久成人片免费观看蜜芽| 国产性生交xxxxx免费| 亚洲AV永久无码精品一福利| 又粗又硬免费毛片| 亚洲沟沟美女亚洲沟沟| 一个人在线观看视频免费| 亚洲日韩国产欧美一区二区三区| 久久黄色免费网站| 亚洲婷婷天堂在线综合| 巨胸喷奶水视频www网免费| 狠狠综合亚洲综合亚洲色| 女人与禽交视频免费看| 无遮挡呻吟娇喘视频免费播放| 久久精品国产亚洲5555| 亚洲电影免费观看| 亚洲精品永久在线观看| 77777亚洲午夜久久多人| 啦啦啦完整版免费视频在线观看| 亚洲色偷偷色噜噜狠狠99网| 亚洲精品美女久久久久99小说| 久久免费公开视频| 亚洲AV无码一区二区大桥未久 | 亚洲一区二区三区免费| 亚洲午夜未满十八勿入| 久久99免费视频| 日本亚洲色大成网站www久久|