重爱 发表于 2016-5-25 12:08:10

mina socket登录性能测试

本帖最后由 重爱 于 2016-5-25 12:41 编辑

mina socket 做的登录,客户端的原理,先生成json串(这个是我们拼接的发送报文,其中的用户名等要做参数化),再进行加密(加密规则问开发),再进行gzip加压,生成iobuffer,向服务端发送。
服务端原理,有个IP,一个端口,监听来自客户端的请求,接收iobuffer,进行gunzip解压,解密。转成json串。响应后再按加密和gzip发给客户端
客户端接收到服务端的响应信息,再进行gunzip解压,解密后转后json串(这个是我们判断响应是否正确的地方)


1.使用抓包工具,发现iobuffer的字节流没办法找出做参数化规律
2.便想从json串的地方开始做参数化,然后去查看工程,断点发登录的过程,得到json串。再找出加密和加压规则,生成iobuffer
3.eclipse写成的脚本

<blockquote>package com.test;

4.转成jmeter脚本
package jmeter;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import net.sf.json.JSONObject;

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

/**
*socket 测试jmeter脚本
* @author wenhuang
*
*/
public class LoginSocketTestJmeter extends AbstractJavaSamplerClient {
      private String Ip;
    private int Post;
    private String user;
    private String password;
    private String resultData;

    // 这个方法是用来自定义java方法入参的。
    //设置可用参数及的默认值;
    public Arguments getDefaultParameters() {
      Arguments params = new Arguments();
      params.addArgument("Ip", "192.168.1.1");
      params.addArgument("Post", "1111");
      params.addArgument("user", "test");
      params.addArgument("password", "1111");
      return params;
    }

    //每个线程测试前执行一次,做一些初始化工作;
    public void setupTest(JavaSamplerContext arg0) {
    }

    //开始测试,从arg0参数可以获得参数值;
    public SampleResult runTest(JavaSamplerContext arg0) {
            Ip = arg0.getParameter("Ip");
            Post = arg0.getIntParameter("Post");
            user = arg0.getParameter("user");
            password = arg0.getParameter("password");
            
      String json = "{\"test\":0,\"data\":{\"user\":\""+user+"\",\"password\":\""+password+"\"},\"key\":\"0\"}";
      
      SampleResult sr = new SampleResult();
      sr.setSampleLabel("登录");//设置样品标签
      sr.setResponseMessage("请求的JSON: "+ json);
      try {
            sr.sampleStart();// jmeter 开始统计响应时间标记
            
          //1.创建客户端Socket,指定服务器地址和端口
          Socket socket=new Socket(Ip, Post);
                //2.获取输出流,向服务器端发送信息
                OutputStream os=socket.getOutputStream();//字节输出流               
                os.write(getSendHex(json));
                os.flush();
               
                //3.获取输入流,并读取服务器端的响应信息
                InputStream is=socket.getInputStream();               
                resultData = getReceiveJson(is);

                //4.关闭资源
                if(os != null){
            os.close();
          }
          if(is != null){
            is.close();
          }
          if(socket != null){
                  socket.close();
          }

          System.out.println("接收到的json ="+resultData);
          JSONObject jsonObj = JSONObject.fromObject(resultData);
          String codeNum = jsonObj.get("code").toString();
          if (Integer.parseInt(codeNum) == 200){
                  sr.setSuccessful(true);
                  System.out.println("登录成功,返回code ="+codeNum);      
            //sr.setResponseMessage("请求的JSON: "+ json + " 登录成功,返回code ="+codeNum);      //输出在查看结果树-的取样器结果中
          }else{
                  sr.setSuccessful(false);
                  System.out.println("登录失败,返回code ="+codeNum);
                  //sr.setResponseMessage("请求的JSON: "+ json + " 登录失败,返回code ="+codeNum);
          }
      
          // 通过下面的操作就可以将被测方法的响应输出到Jmeter的察看结果树中的响应数据里面了。
          if (resultData != null && resultData.length() > 0) {
            sr.setResponseData("返回结果是:"+resultData, null);//输出在查看结果树-的响应结果中
            sr.setDataType(SampleResult.TEXT);
          }
          // System.out.println(resultData);
            
      } catch (Throwable e) {
            sr.setSuccessful(false);
            e.printStackTrace();
      } finally {
                sr.sampleEnd();// jmeter 结束统计响应时间标记
      }
      return sr;
    }

    //测试结束时调用;
    public void teardownTest(JavaSamplerContext arg0) {
         //System.out.println(end);
         //System.out.println("The cost is"+(end-start)/1000);
    }
   
    // main只是为了调试用,最后打jar包的时候注释掉。
    /*
      public static void main(String[] args)
      { // TODO Auto-generated method stub
            for (int i =0;i<5;i++){
          Arguments params = new Arguments();
          params.addArgument("Ip", "192.168.1.111");//设置参数,并赋予默认值
          params.addArgument("Post", "1111");//设置参数,并赋予默认值
          params.addArgument("user", "test");//设置参数,并赋予默认值
          params.addArgument("password", "1111");
          JavaSamplerContext arg0 = new JavaSamplerContext(params);
          LoginSocketTestJmeter test = new LoginSocketTestJmeter();
          test.setupTest(arg0);
          test.runTest(arg0);
          test.teardownTest(arg0);
            }
      }
      */
   
}
5.将相关类打包成jar包放在 X:\apache-jmeter-3.0\lib\ext目录下,使用jmeter进行压测试




重爱 发表于 2016-5-25 12:37:30

:L

重爱 发表于 2016-5-25 12:38:11

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import net.sf.json.JSONObject;
import org.apache.mina.core.buffer.IoBuffer;
//这两个加密加压的包根据项目修改
import com.tools.Des3;
import com.tools.ZLibUtils;

/**socket 发送消息,和接收消息 测试脚本
* @author Administrator
*
*/
public class LoginSocketTest {
        public static void main(String[] args) throws Exception {
                try {
                        //1.创建客户端Socket,指定服务器地址和端口
                        Socket socket=new Socket("192.168.1.1", 11111);
                        //2.获取输出流,向服务器端发送信息
                        OutputStream os=socket.getOutputStream();//字节输出流
                        //PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
                       
                        String json = "{\"test\":0,\"data\":{\"user\":\"test\",\"password\":\"test\"},\"key\":\"0\"}";
                        //将json转成16进制的字节流
                        os.write(getSendHex(json));
                        //发送
                        os.flush();
                        //socket.shutdownOutput();//关闭输出流
                       
                        //3.获取输入流,并读取服务器端的响应信息
                        InputStream is=socket.getInputStream();             
                        //将接收的字节流转成json
                        String recjson = getReceiveJson(is);
                        //判断结果是否正确将json转为object对象,取出要判断的参数值code做断言。
      JSONObject jsonObj = JSONObject.fromObject(recjson);
      String codeNum = jsonObj.get("code").toString();
      System.out.println("code="+codeNum);

                        //4.关闭资源
                        if(os != null){
          os.close();
      }
      if(is != null){
          is.close();
      }
      if(socket != null){
              socket.close();
      }
                
                } catch (UnknownHostException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

        /**
       * json转为客户端发送的16进制报文
       * @param json
       * @return
       * @throws Exception
       */
        public static byte[] getSendHex(String json) throws Exception {
                System.out.println("json ="+json);
                IoBuffer buff = IoBuffer.allocate(1024).setAutoExpand(true);
                //加密规则,根据项目做修改
                json = Des3.encode(json, "test");
                //加压
                byte[] bytes = ZLibUtils.compress(json.getBytes("UTF-8"));
                //装bytes存入buff
                buff.putInt(bytes.length);
                buff.put(bytes);
                buff.flip();
                // 将buff转为 字节 再转为16进制
                byte[] b = new byte;
                buff.get(b);
                return b;
        }

        /**
       * byte数组转换成16进制字符串
       *
       * @param src
       * @return
       */
        public static String bytesToHexString(byte[] src) {
                StringBuilder stringBuilder = new StringBuilder();
                if (src == null || src.length <= 0) {
                        return null;
                }
                for (int i = 0; i < src.length; i++) {
                        int v = src & 0xFF;
                        String hv = Integer.toHexString(v);
                        if (hv.length() < 2) {
                                stringBuilder.append(0);
                        }
                        stringBuilder.append(hv);
                        stringBuilder.append("\\x");
                }
                //16进制前面要加\x
                return ("\\x"+stringBuilder.substring(0,stringBuilder.length()-2)).toString();
        }
       
    /**
   * 字节流转int型   
   * @param b
   * @return
   */
    public static int b2i(byte[] b) {
      int value = 0;
      for (int i = 0; i < 4; i++) {
      int shift = (4 - 1 - i) * 8;
      value += (b & 0x000000FF) << shift;
      }
      return value;
    }


    /**客户端得接收服务端返回的iobuffer并转成json
   * 接收的iobuffer,前四个字节是表示字节流的长度,先接收前四个字节,并用16进制转10进制int型方法,得到长度的数字
   * 再根据长度接收所有的字节流。如果长度错误,拨收是会出错的。
   * @param is socket的输入流
   * @return json
   * @throws Exception
   */
    public static String getReceiveJson(InputStream is) throws Exception{
            byte[] intByte = new byte;
      is.read(intByte);
      int msgLength = b2i(intByte);
      System.out.println("int:"+msgLength);
      int readPosition = 0;
      byte[] byteArray = new byte;
      while(readPosition < msgLength){
            int value = is.read(byteArray, readPosition, msgLength-readPosition);
            if(value == -1){
                break;
            }
            readPosition += value;
      }
                byte[] data = ZLibUtils.decompress(byteArray); //解压
                String code = new String(data, "UTF-8");
                String text = Des3.decode(code, "test");        //解密
                System.out.println("服务端接收消息内容为:="+text);
                return text;
           
    }
}

独慕 发表于 2016-6-27 11:30:36

上一步是做什么的?

lsekfe 发表于 2016-6-28 09:38:12

支持下~
页: [1]
查看完整版本: mina socket登录性能测试