JAVA RPC (四) 之thrift序列化普通对象
先简单写一个thrift文件
本地通过thrift编译之后会生成一个java源文件。------编译口令 :thrift -gen java mytestrequest.thrift
编译后的源代码如下:
/**
* Autogenerated by Thrift Compiler (0.8.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
package com.thrift; import org.apache.thrift.scheme.IScheme;
import org.apache.thrift.scheme.SchemeFactory;
import org.apache.thrift.scheme.StandardScheme; import org.apache.thrift.scheme.TupleScheme;
import org.apache.thrift.protocol.TTupleProtocol;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Set;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.Collections;
import java.util.BitSet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 测试类
*
*/
public class koalasRequest implements org.apache.thrift.TBase<koalasRequest, koalasRequest._Fields>, java.io.Serializable, Cloneable {
private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("koalasRequest"); private static final org.apache.thrift.protocol.TField AGE_FIELD_DESC = new org.apache.thrift.protocol.TField("age", org.apache.thrift.protocol.TType.I32, (short)1);
private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)2);
private static final org.apache.thrift.protocol.TField ADDRESS_FIELD_DESC = new org.apache.thrift.protocol.TField("address", org.apache.thrift.protocol.TType.STRING, (short)3); private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
static {
schemes.put(StandardScheme.class, new koalasRequestStandardSchemeFactory());
schemes.put(TupleScheme.class, new koalasRequestTupleSchemeFactory());
} public int age; // required
public String name; // required
public String address; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
public enum _Fields implements org.apache.thrift.TFieldIdEnum {
AGE((short)1, "age"),
NAME((short)2, "name"),
ADDRESS((short)3, "address"); private static final Map<String, _Fields> byName = new HashMap<String, _Fields>(); static {
for (_Fields field : EnumSet.allOf(_Fields.class)) {
byName.put(field.getFieldName(), field);
}
} /**
* Find the _Fields constant that matches fieldId, or null if its not found.
*/
public static _Fields findByThriftId(int fieldId) {
switch(fieldId) {
case 1: // AGE
return AGE;
case 2: // NAME
return NAME;
case 3: // ADDRESS
return ADDRESS;
default:
return null;
}
} /**
* Find the _Fields constant that matches fieldId, throwing an exception
* if it is not found.
*/
public static _Fields findByThriftIdOrThrow(int fieldId) {
_Fields fields = findByThriftId(fieldId);
if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
return fields;
} /**
* Find the _Fields constant that matches name, or null if its not found.
*/
public static _Fields findByName(String name) {
return byName.get(name);
} private final short _thriftId;
private final String _fieldName; _Fields(short thriftId, String fieldName) {
_thriftId = thriftId;
_fieldName = fieldName;
} public short getThriftFieldId() {
return _thriftId;
} public String getFieldName() {
return _fieldName;
}
} // isset id assignments
private static final int __AGE_ISSET_ID = 0;
private BitSet __isset_bit_vector = new BitSet(1);
public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
static {
Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
tmpMap.put(_Fields.AGE, new org.apache.thrift.meta_data.FieldMetaData("age", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
tmpMap.put(_Fields.ADDRESS, new org.apache.thrift.meta_data.FieldMetaData("address", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
metaDataMap = Collections.unmodifiableMap(tmpMap);
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(koalasRequest.class, metaDataMap);
} public koalasRequest() {
} public koalasRequest(
int age,
String name,
String address)
{
this();
this.age = age;
setAgeIsSet(true);
this.name = name;
this.address = address;
} /**
* Performs a deep copy on <i>other</i>.
*/
public koalasRequest(koalasRequest other) {
__isset_bit_vector.clear();
__isset_bit_vector.or(other.__isset_bit_vector);
this.age = other.age;
if (other.isSetName()) {
this.name = other.name;
}
if (other.isSetAddress()) {
this.address = other.address;
}
} public koalasRequest deepCopy() {
return new koalasRequest(this);
} @Override
public void clear() {
setAgeIsSet(false);
this.age = 0;
this.name = null;
this.address = null;
} public int getAge() {
return this.age;
} public koalasRequest setAge(int age) {
this.age = age;
setAgeIsSet(true);
return this;
} public void unsetAge() {
__isset_bit_vector.clear(__AGE_ISSET_ID);
} /** Returns true if field age is set (has been assigned a value) and false otherwise */
public boolean isSetAge() {
return __isset_bit_vector.get(__AGE_ISSET_ID);
} public void setAgeIsSet(boolean value) {
__isset_bit_vector.set(__AGE_ISSET_ID, value);
} public String getName() {
return this.name;
} public koalasRequest setName(String name) {
this.name = name;
return this;
} public void unsetName() {
this.name = null;
} /** Returns true if field name is set (has been assigned a value) and false otherwise */
public boolean isSetName() {
return this.name != null;
} public void setNameIsSet(boolean value) {
if (!value) {
this.name = null;
}
} public String getAddress() {
return this.address;
} public koalasRequest setAddress(String address) {
this.address = address;
return this;
} public void unsetAddress() {
this.address = null;
} /** Returns true if field address is set (has been assigned a value) and false otherwise */
public boolean isSetAddress() {
return this.address != null;
} public void setAddressIsSet(boolean value) {
if (!value) {
this.address = null;
}
} public void setFieldValue(_Fields field, Object value) {
switch (field) {
case AGE:
if (value == null) {
unsetAge();
} else {
setAge((Integer)value);
}
break; case NAME:
if (value == null) {
unsetName();
} else {
setName((String)value);
}
break; case ADDRESS:
if (value == null) {
unsetAddress();
} else {
setAddress((String)value);
}
break; }
} public Object getFieldValue(_Fields field) {
switch (field) {
case AGE:
return Integer.valueOf(getAge()); case NAME:
return getName(); case ADDRESS:
return getAddress(); }
throw new IllegalStateException();
} /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
public boolean isSet(_Fields field) {
if (field == null) {
throw new IllegalArgumentException();
} switch (field) {
case AGE:
return isSetAge();
case NAME:
return isSetName();
case ADDRESS:
return isSetAddress();
}
throw new IllegalStateException();
} @Override
public boolean equals(Object that) {
if (that == null)
return false;
if (that instanceof koalasRequest)
return this.equals((koalasRequest)that);
return false;
} public boolean equals(koalasRequest that) {
if (that == null)
return false; boolean this_present_age = true;
boolean that_present_age = true;
if (this_present_age || that_present_age) {
if (!(this_present_age && that_present_age))
return false;
if (this.age != that.age)
return false;
} boolean this_present_name = true && this.isSetName();
boolean that_present_name = true && that.isSetName();
if (this_present_name || that_present_name) {
if (!(this_present_name && that_present_name))
return false;
if (!this.name.equals(that.name))
return false;
} boolean this_present_address = true && this.isSetAddress();
boolean that_present_address = true && that.isSetAddress();
if (this_present_address || that_present_address) {
if (!(this_present_address && that_present_address))
return false;
if (!this.address.equals(that.address))
return false;
} return true;
} @Override
public int hashCode() {
return 0;
} public int compareTo(koalasRequest other) {
if (!getClass().equals(other.getClass())) {
return getClass().getName().compareTo(other.getClass().getName());
} int lastComparison = 0;
koalasRequest typedOther = (koalasRequest)other; lastComparison = Boolean.valueOf(isSetAge()).compareTo(typedOther.isSetAge());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetAge()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.age, typedOther.age);
if (lastComparison != 0) {
return lastComparison;
}
}
lastComparison = Boolean.valueOf(isSetName()).compareTo(typedOther.isSetName());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetName()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, typedOther.name);
if (lastComparison != 0) {
return lastComparison;
}
}
lastComparison = Boolean.valueOf(isSetAddress()).compareTo(typedOther.isSetAddress());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetAddress()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.address, typedOther.address);
if (lastComparison != 0) {
return lastComparison;
}
}
return 0;
} public _Fields fieldForId(int fieldId) {
return _Fields.findByThriftId(fieldId);
} public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
} public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("koalasRequest(");
boolean first = true; sb.append("age:");
sb.append(this.age);
first = false;
if (!first) sb.append(", ");
sb.append("name:");
if (this.name == null) {
sb.append("null");
} else {
sb.append(this.name);
}
first = false;
if (!first) sb.append(", ");
sb.append("address:");
if (this.address == null) {
sb.append("null");
} else {
sb.append(this.address);
}
first = false;
sb.append(")");
return sb.toString();
} public void validate() throws org.apache.thrift.TException {
// check for required fields
} private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
try {
write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
} catch (org.apache.thrift.TException te) {
throw new java.io.IOException(te);
}
} private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
try {
// it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
__isset_bit_vector = new BitSet(1);
read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
} catch (org.apache.thrift.TException te) {
throw new java.io.IOException(te);
}
} private static class koalasRequestStandardSchemeFactory implements SchemeFactory {
public koalasRequestStandardScheme getScheme() {
return new koalasRequestStandardScheme();
}
} private static class koalasRequestStandardScheme extends StandardScheme<koalasRequest> { public void read(org.apache.thrift.protocol.TProtocol iprot, koalasRequest struct) throws org.apache.thrift.TException {
org.apache.thrift.protocol.TField schemeField;
iprot.readStructBegin();
while (true)
{
schemeField = iprot.readFieldBegin();
if (schemeField.type == org.apache.thrift.protocol.TType.STOP) {
break;
}
switch (schemeField.id) {
case 1: // AGE
if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
struct.age = iprot.readI32();
struct.setAgeIsSet(true);
} else {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 2: // NAME
if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
struct.name = iprot.readString();
struct.setNameIsSet(true);
} else {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 3: // ADDRESS
if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
struct.address = iprot.readString();
struct.setAddressIsSet(true);
} else {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
default:
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
iprot.readFieldEnd();
}
iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method
struct.validate();
} public void write(org.apache.thrift.protocol.TProtocol oprot, koalasRequest struct) throws org.apache.thrift.TException {
struct.validate(); oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(AGE_FIELD_DESC);
oprot.writeI32(struct.age);
oprot.writeFieldEnd();
if (struct.name != null) {
oprot.writeFieldBegin(NAME_FIELD_DESC);
oprot.writeString(struct.name);
oprot.writeFieldEnd();
}
if (struct.address != null) {
oprot.writeFieldBegin(ADDRESS_FIELD_DESC);
oprot.writeString(struct.address);
oprot.writeFieldEnd();
}
oprot.writeFieldStop();
oprot.writeStructEnd();
} } private static class koalasRequestTupleSchemeFactory implements SchemeFactory {
public koalasRequestTupleScheme getScheme() {
return new koalasRequestTupleScheme();
}
} private static class koalasRequestTupleScheme extends TupleScheme<koalasRequest> { @Override
public void write(org.apache.thrift.protocol.TProtocol prot, koalasRequest struct) throws org.apache.thrift.TException {
TTupleProtocol oprot = (TTupleProtocol) prot;
BitSet optionals = new BitSet();
if (struct.isSetAge()) {
optionals.set(0);
}
if (struct.isSetName()) {
optionals.set(1);
}
if (struct.isSetAddress()) {
optionals.set(2);
}
oprot.writeBitSet(optionals, 3);
if (struct.isSetAge()) {
oprot.writeI32(struct.age);
}
if (struct.isSetName()) {
oprot.writeString(struct.name);
}
if (struct.isSetAddress()) {
oprot.writeString(struct.address);
}
} @Override
public void read(org.apache.thrift.protocol.TProtocol prot, koalasRequest struct) throws org.apache.thrift.TException {
TTupleProtocol iprot = (TTupleProtocol) prot;
BitSet incoming = iprot.readBitSet(3);
if (incoming.get(0)) {
struct.age = iprot.readI32();
struct.setAgeIsSet(true);
}
if (incoming.get(1)) {
struct.name = iprot.readString();
struct.setNameIsSet(true);
}
if (incoming.get(2)) {
struct.address = iprot.readString();
struct.setAddressIsSet(true);
}
}
} }
生成了一个500多行的代码,那么我们现在对这个请求对象进行序列化,看看序列化结果。
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TIOStreamTransport; import java.io.ByteArrayOutputStream;
import java.util.Arrays; public class KoalaThriftSerialization { public static void main(String[] args) throws TException { koalasRequest request = new koalasRequest ( );
request.setName ( "小明" );
request.setAge ( 20 );
request.setAddress ( "北京" ); ByteArrayOutputStream out = new ByteArrayOutputStream();
TIOStreamTransport tioStreamTransport = new TIOStreamTransport (out);
TProtocol protocol = new TBinaryProtocol (tioStreamTransport);
request.write ( protocol );
System.out.println (Arrays.toString ( out.toByteArray () ) ); } }
看一看对于这么个简单的request对象,thrift到底序列化成什么了
实际生产中的传输方式一般采用TFramedTransport,序列化采用二进制序列化协议TBinaryProtocol,当然也有json和压缩协议等等,二进制确实最高效的。
我们来看看thrift的序列化方法。
public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
}
public void write(org.apache.thrift.protocol.TProtocol oprot, koalasRequest struct) throws org.apache.thrift.TException {
struct.validate(); oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(AGE_FIELD_DESC);
oprot.writeI32(struct.age);
oprot.writeFieldEnd();
if (struct.name != null) {
oprot.writeFieldBegin(NAME_FIELD_DESC);
oprot.writeString(struct.name);
oprot.writeFieldEnd();
}
if (struct.address != null) {
oprot.writeFieldBegin(ADDRESS_FIELD_DESC);
oprot.writeString(struct.address);
oprot.writeFieldEnd();
}
oprot.writeFieldStop();
oprot.writeStructEnd();
}
1:validate 验证一下request中是否合法,主要是验证在thrift文件里属性为required的,但是实际传输中为空的字段。required字段为空则会报错。
2:writeStructBegin 开始序列化request,TBinaryProtocol什么也不做,当然用户可以自己自定义Protocol。
3: writeFieldBegin 写入age字段开始,下面来看看writeFieldBegin到底写了什么
private static final org.apache.thrift.protocol.TField AGE_FIELD_DESC = new org.apache.thrift.protocol.TField("age", org.apache.thrift.protocol.TType.I32, (short)1);
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.apache.thrift.protocol; public final class TType {
public static final byte STOP = 0;
public static final byte VOID = 1;
public static final byte BOOL = 2;
public static final byte BYTE = 3;
public static final byte DOUBLE = 4;
public static final byte I16 = 6;
public static final byte I32 = 8;
public static final byte I64 = 10;
public static final byte STRING = 11;
public static final byte STRUCT = 12;
public static final byte MAP = 13;
public static final byte SET = 14;
public static final byte LIST = 15;
public static final byte ENUM = 16; public TType() {
}
}
public void writeFieldBegin(TField field) throws TException {
this.writeByte(field.type);
this.writeI16(field.id);
}
public void writeByte(byte b) throws TException {
this.bout[0] = b;
this.trans_.write(this.bout, 0, 1);
}
public void writeI16(short i16) throws TException {
this.i16out[0] = (byte)(255 & i16 >> 8);
this.i16out[1] = (byte)(255 & i16);
this.trans_.write(this.i16out, 0, 2);
}
(1)首先先写入age的类型和序号,age为int类型,int类型在thrift里面设置是byte类型的【8】,在写入age的位置,因为thrift的定义的age的位置序号是1,thrift会写入一下short类型的1,也就说thrift的请求体的成员最大数量不能超过short的最大值32767,一般来说够了,哪有变态的请求体需要几万个成员变量啊,不得把程序员搞死!写入short占用两个字节那么继续写入【0 1】
4: writeI32
public void writeI32(int i32) throws TException {
this.i32out[0] = (byte)(255 & i32 >> 24);
this.i32out[1] = (byte)(255 & i32 >> 16);
this.i32out[2] = (byte)(255 & i32 >> 8);
this.i32out[3] = (byte)(255 & i32);
this.trans_.write(this.i32out, 0, 4);
}
直接将age的值写入,也就是 0 0 0 20 占4个字节
5:writeFieldEnd 写入age字段结束,什么也不做。
以上写入一个int类型的字段就写完了,接下来写入String类型的name和String类型的address同理,需要注意的是
public void writeString(String str) throws TException {
try {
byte[] dat = str.getBytes("UTF-8");
this.writeI32(dat.length);
this.trans_.write(dat, 0, dat.length);
} catch (UnsupportedEncodingException var3) {
throw new TException("JVM DOES NOT SUPPORT UTF-8");
}
}
在写入String的时候需要先write字符串的长度,int类型占4个字节,因为string类型占用的字节不固定,反序列化时需要知道字符串类型到底是几个字节。
重复这个过程一直到写完所有的字段,这个过程都是由thrift给java语言自动生成的,很方便吧。
所以对于thrift来说,他的序列化就是对各个字段进行写入 1 字段类型 (1 byte)、2字段位置(2 byte)、3字段内容 ,TBinaryProtocol中对java所有的类型的写入都有封装,小伙伴们可以自行下载代码查看!
高级java交流群:825199617
欢迎热爱源码志同道合的朋友加入。
koalas rpc源码地址https://gitee.com/a1234567891/koalas-rpc
JAVA RPC (四) 之thrift序列化普通对象的更多相关文章
- JAVA RPC (五) 之thrift序列化RPC消息体
让大家久等了.继续更新thrift序列化的消息体,下面我们一步一步的看一看thrift的rpc是怎么实例化消息体的. 首先我们先准备一个request文件 namespace java bky str ...
- JAVA RPC (三) 之thrift序列化协议入门杂谈
首先抱歉让大家久等了,最近工作的原因,再加上自己维护koalas rpc利用的大部分时间,一直没腾出空来写这篇文章. 先放出来自研的企业级RPC框架源代码地址,上面有使用方式和部署环境说明,说环境部署 ...
- Thrift RPC实战(三) thrift序列化揭秘
本文主要讲解Thrift的序列化机制, 看看thrift作为数据交换格式是如何工作的? 1.构造应用场景: 1). 首先我们先来定义下thrift的简单结构. 1 2 3 4 5 namespace ...
- JAVA RPC(二)序列化协议杂谈
序列化和反序列化作为Java里一个较为基础的知识点,大家心里也有那么几句要说的,但我相信很多小伙伴掌握的也就是那么几句而已,如果再深究问一下Java如何实现序列化和反序列化的,就可能不知所措了!遥记当 ...
- java提高篇(六)-----使用序列化实现对象的拷贝
我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...
- JAVA RPC (六) 之thrift反序列化RPC消息体
我们来看一下服务端的简单实现,直接上thrift代码,很直观的来看一看thrift的server到底干了些什么 public boolean process(TProtocol in, TProtoc ...
- 菜鸟学Java(四)——JSP内置对象
学习JavaWeb就离不开JSP,而学习JSP又不得不了解它常用的九个内置对象.今天来做一个简单介绍. request Request封装了用户提交的信息,通过调用Request相应的方法可以获取封装 ...
- 一起学 Java(四) File、Try 、序列化、MySQL、Socket
一.Java 流(Stream).文件(File)和IO Java.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基 ...
- java提高篇(五)-----使用序列化实现对象的拷贝
我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性 ...
随机推荐
- CIA402状态转换图
CIA402状态转换如下图所示: 要想改变参数并使其生效,需要先将状态转换到ready,然后修改要配置的参数,再使其运行(operation enabled). 要发送的报文顺序基本如下: 1) ...
- 【原创】Java基础之常用JVM工具
查看当前所有java进程 # jps 查看某个进程的堆内存占用情况 # jmap -heap $pid 查看某个进程的堆内存中对象分布情况 # jmap -histo $pid 将某个进程的堆内存导出 ...
- Apache JMeter压力测试实例
脚本录制 脚本录制,JMeter启用WEB代理,浏览器把代理上网设置为JMeter所在的IP地址,自己电脑就是127.0.0.1代理端口默认8080.至于浏览器修改代理上网服务器,不做截图. Jmet ...
- Python-web应用 +HTTP协议 +web框架
web架构 # web应用 架构# C/S 架构 | B/S 架构# client server: 客户端服务器架构,C++# browser server:浏览器服务器架构,Java.Python ...
- IISARR方式整合Tomcat失敗
需要在IIS安裝ARR 目标服务器:targetServer 配置反向代理的服务器:reveseProxServer 1.确定最终访问的网址:比如www.baidu.com .www.csdn.ne ...
- SQL Update
转载至:https://www.liyongzhen.com/ UPDATE 语句 UPDATE语句用于修改表中的现有记录. UPDATE语法 1 2 3 UPDATE 表名 SET 字段1 = 值1 ...
- H5测试与PC端测试不同的点
1.通过H5网页(非手机的返回功能)的返回功能可以返回,不会出现无法返回的情况. 2.横屏竖屏相互切换,能自适应,并且布局不会乱掉: 3.为能在不同分辨率的手机上能更好的展示,建议采用响应式设计(如: ...
- BZOJ-10-1176: [Balkan2007]Mokia-CDQ第二类应用
思路 :按照操作的时间进行分治,这样转化成了 时间t ,x坐标,y坐标 经典的三维偏序. 最初时间就是递增顺序,无需排序直接进行第二维的分治,类似归并排序处理x坐标,在保证 x有序的情况下进行更新y坐 ...
- h5页面
<!DOCTYPE html><html lang="utf-8"><head> <meta charset="UTF-8&qu ...
- selenium截取具体元素图片(python版)
原理: 1.截图(整个窗口) 2.获取此元素坐标 element = driver.find_element_by_id("xx") element.location) 3.获取此 ...