1.根据session获取客户端的ip地址
String clientIP = "";
try {
InetAddress inetAddress = ((NettyChannel) iSession.getCurChannel()).getRemoteAddress().getAddress();
byte[] ipAddress = inetAddress.getAddress();
for (int i = 0; i < ipAddress.length; i++) {
if (i > 0) {
clientIP += ".";
}
clientIP += ipAddress[i] & 0xFF;
}
} catch (Exception e) {
// e.printStackTrace();
}
2.新增对外的curl接口
import com.google.gson.Gson;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.BufferedReader;
public class RPCGmServerTask extends Thread{
private static final Logger LOGGER = LoggerFactory.getLogger(RPCGmServerTask.class);
public RPCGmServerTask(){
}
@Override
public void run() {
try {
HttpServer server = HttpServer.create(new InetSocketAddress(2720), 0);
server.createContext("/", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
} catch (Exception e) {
LOGGER.error("run->{}", e);
}
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
InputStream is = exchange.getRequestBody();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
try {
String cmd = inputLine.toString();
if (cmd.startsWith("//")) {
System.out.println("gmgmgm:" + cmd.substring(2));
String cmd2 = cmd.substring(2);
GmService.exeCmd(cmd2);
}
} catch (Exception e) {
System.out.print("gmException" + e);
}
}
exchange.sendResponseHeaders(200, 0);
exchange.close();
}
}
}
3.jar包的各种启动方式超详细总结
1.java -jar
java -jar test.jar
弊端1:exit 退出终端会导致java进程中断。
弊端2:ctrl+c 退出启动展示页会导致java进程中断。
弊端3:直接关闭终端会导致java进程中断(启动时和启动完关闭都会导致java进程终端)。
弊端4:控制台日志不打印(这个可以不算弊端吧,其实很多场景不需要这个日志,这里姑且算是吧)2.java -jar test.jar &
弊端1:直接关闭终端会导致java进程中断(启动时和启动完关闭都会导致java进程终端)。
弊端2:控制台日志不打印(这个可以不算弊端吧,其实很多场景不需要这个日志,这里姑且算是吧)3.nohup java -jar test.jar
弊端1:exit 退出终端会导致java进程中断。
弊端2:ctrl+c 退出启动展示页会导致java进程中断。
弊端3:直接关闭终端会导致java进程中断(启动时和启动完关闭都会导致java进程终端)。4.nohup java -jar test.jar &
弊端1:日志定向输出当前文件夹下的nohup.out(与下面几个命令相比,姑且算是弊端吧)
5.nohup java -jar test.jar > ./info.log &
该命令没有弊端,与上一个场景的区别是会将日志打印到指定的info.log下面。不过打印方式是覆盖。也就是说每次启动以后,都会将之前的日志覆盖
6.nohup java -jar test.jar >> ./info.log &
该命令没有弊端,与上一个场景的区别是会将日志打印到指定的info.log下面。不过打印方式是拼接。也就是说每次启动以后,都会将本次的日志拼接到原日志之后进行输出,这里日志因为是控制台日志,一般没必要拼接
7.nohup java -jar test.jar >> /dev/null &
这个命令是将日志输出到/dev/null,/dev/null是linux系统里的黑洞,其实可以理解为垃圾桶,相当于把日志扔了不要了,其他就没什么区别了。
4. CopyOnWriterArrayList
CopyOnWriterArrayList 详解_copyonwritearraylist-CSDN博客
1. 简介
在 ArrayList 的类注释上,JDK 就提醒了我们,如果要把 ArrayList 作为共享变量的话,是线程不安全的,推荐我们自己加锁或者使用 Collections.synchronizedList 方法,其实 JDK 还提供了另外一种线程安全的 List,叫做 CopyOnWriteArrayList。
2. 原理
很多时候,我们的系统应对的都是读多写少的并发场景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。
线程安全的,多线程环境下可以直接使用,无需加锁;
通过锁 + 数组拷贝 + volatile 关键字保证了线程安全;
每次数组操作,都会把数组拷贝一份出来,在新数组上进行操作,操作成功之后再赋值回去。从整体架构上来说,CopyOnWriteArrayList 数据结构和 ArrayList 是一致的,底层是个数组,只不过 CopyOnWriteArrayList 在对数组进行操作的时候,基本会分四步走:
加锁;
从原数组中拷贝出新数组;
在新数组上进行操作,并把新数组赋值给数组容器;
解锁。除了加锁之外,CopyOnWriteArrayList 的底层数组还被 volatile 关键字修饰,意思是一旦数组被修改,其它线程立马能够感知到,代码如下:
private transient volatile Object[] array;
整体上来说,CopyOnWriteArrayList 就是利用锁 + 数组拷贝 + volatile 关键字保证了 List 的线程安全。
5.--spring.config.location命令学习
--spring.config.location命令主要是为了加载springBoot jar 外部的配置文档,比如我们可以将日志的级别控制放在jar外面的配置文档中,可以方便线上调试,不用改动jar中的配置文档,再打包这样比较麻烦的操作。
注意:当使用了这个命令后外面的配置文档级别要高于里面的文档,所以外面的属性会覆盖里面的,当然所有文档都是互补的,没有的话就相互补充。
#!/bin/bash
package="gameSrv.jar"
cfg="./assets/config/gameSrv.properties"
log="./logs/gameSrv.log"
mypackage=$PWD/$package
nohup java -jar $package --spring.config.location=$cfg --mypackage=$mypackage >> $log 2>&1 &
sleep 5
PID=$(ps -ef | grep $mypackage | grep -v grep | awk '{ print $2 }')
if [ -z "${PID}" ]; then
echo start ${mypackage} fail
else
echo start ${mypackage} success ${PID}
fi
6.Caused by: java.io.IOException: Connection reset by peer
这个错误的意思是:对方主机(peer)在建立连接时发送了一个重置连接的请求,导致连接中断。这可能是由于对方主机遇到了一些问题,或者是对方主机关闭了连接。
7.StringBuffer与StringBuider
深度剖析Java中StringBuffer与StringBuider两个类的异同_stirngbuffer和-CSDN博客
StringBuffer
String 的值是不可变的,每次对String的操作都会生成新的String对象,不仅效率低,而且耗费大量内存空间。
StringBuffer类和String类一样,也用来表示字符串,但是StringBuffer的内部实现方式和String不同,在进行字符串处理时,不生成新的对象,在内存使用上要优于String。StringBuffer 默认分配16字节长度的缓冲区,当字符串超过该大小时,会自动增加缓冲区长度,而不是生成新的对象。
StringBuffer不像String,只能通过 new 来创建对象,不支持简写方式StringBuffer str1 = new StringBuffer(); // 分配16个字节长度的缓冲区 StringBuffer str2 = =new StringBuffer(512); // 分配512个字节长度的缓冲区 // 在缓冲区中存放了字符串,并在后面预留了16个字节长度的空缓冲区 StringBuffer str3 = new StringBuffer("青00 studyjava");
主要方法
StringBuffer str = new StringBuffer(“biancheng100”);
str.append(true);
则对象str的值将变成”biancheng100true”。
StringBuffer str = new StringBuffer("abcdef");
str. deleteCharAt(3);
该代码将会删除索引值为3的字符,即”d“字符。
StringBuffer str = new StringBuffer("abcdef");
str.delete(1, 4);
该代码会删除索引值为1~4之间的字符,包括索引值1,但不包括4。
StringBuffer str = new StringBuffer("abcdef");
str.insert(3, "xyz");
最后str所指向的字符串为 abcdxyzef。
StringBuffer str = new StringBuffer("abcdef");
str.setCharAt(3, 'z');
该代码将把索引值为3的字符修改为 z,最后str所指向的字符串为 abczef。
StringBuilder
StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。
- 操作少量的数据使用 String;
- 单线程操作大量数据使用 StringBuilder;
- 多线程操作大量数据使用 StringBuffer。