qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Jmeter《Java請求》使用總結

          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 }
            代碼中使用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 }
            這段代碼展示了我們的客戶端,這里所有的請求有兩種發送模式,一種是發送并阻塞等待返回(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 }
            可以看到doTest的工作就是封裝請求,并拿到父類的client發送,然后返回響應(send方式返回null),Okay,大功告成。

          posted on 2013-11-04 13:17 順其自然EVO 閱讀(437) 評論(0)  編輯  收藏 所屬分類: jmeter and badboy

          <2013年11月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 栖霞市| 双流县| 阿坝| 江油市| 靖安县| 鸡泽县| 无棣县| 那曲县| 广德县| 岱山县| 漳浦县| 汨罗市| 綦江县| 天柱县| 奇台县| 沙雅县| 清苑县| 自贡市| 樟树市| 牙克石市| 敖汉旗| 宽城| 新泰市| 侯马市| 云阳县| 玉田县| 府谷县| 东宁县| 华蓥市| 阜新市| 安仁县| 廊坊市| 德兴市| 喜德县| 康保县| 无极县| 洪洞县| 新沂市| 涡阳县| 连云港市| 延安市|