24 changed files with 674 additions and 32 deletions
@ -0,0 +1,52 @@ |
|||||||
|
package net.sopod.soim.client.net; |
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap; |
||||||
|
import io.netty.channel.Channel; |
||||||
|
import io.netty.channel.ChannelInitializer; |
||||||
|
import io.netty.channel.nio.NioEventLoopGroup; |
||||||
|
import io.netty.channel.socket.SocketChannel; |
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel; |
||||||
|
import net.sopod.soim.common.util.Jackson; |
||||||
|
import net.sopod.soim.core.net.ImEntryCodec; |
||||||
|
import net.sopod.soim.data.constant.SerializeType; |
||||||
|
import net.sopod.soim.data.serialize.ImMessage; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* ClientInitial |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-27 22:36 |
||||||
|
*/ |
||||||
|
public class ImNetClient { |
||||||
|
|
||||||
|
public void connect(String host, int port) throws InterruptedException { |
||||||
|
NioEventLoopGroup work = new NioEventLoopGroup(2); |
||||||
|
Bootstrap b = new Bootstrap() |
||||||
|
.group(work) |
||||||
|
.channel(NioSocketChannel.class) |
||||||
|
.handler(new ChannelInitializer<SocketChannel>() { |
||||||
|
@Override |
||||||
|
protected void initChannel(SocketChannel ch) throws Exception { |
||||||
|
ch.pipeline() |
||||||
|
.addLast(new ImEntryCodec()); |
||||||
|
} |
||||||
|
}); |
||||||
|
Channel channel = b.connect(host, port).await().channel(); |
||||||
|
Map<String, Object> body = new HashMap<>(); |
||||||
|
body.put("name", "二狗子"); |
||||||
|
body.put("age", 16); |
||||||
|
ImMessage imMessage = new ImMessage() |
||||||
|
.setServiceNo(1) |
||||||
|
.setSerializeType(SerializeType.json.ordinal()) |
||||||
|
.setBody(Jackson.json().serialize(body).getBytes(StandardCharsets.UTF_8)); |
||||||
|
channel.writeAndFlush(imMessage); |
||||||
|
channel.close(); |
||||||
|
work.shutdownGracefully(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -1,13 +0,0 @@ |
|||||||
package net.sopod.soim.client.server; |
|
||||||
|
|
||||||
/** |
|
||||||
* ClientInitial |
|
||||||
* |
|
||||||
* @author tmy |
|
||||||
* @date 2022-03-27 22:36 |
|
||||||
*/ |
|
||||||
public class ClientInitial { |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
package net.sopod.soim.common.constant; |
||||||
|
|
||||||
|
public class Consts { |
||||||
|
|
||||||
|
public static int KB = 1024; |
||||||
|
|
||||||
|
public static int MB = KB * KB; |
||||||
|
|
||||||
|
public static int GB = KB * MB; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,192 @@ |
|||||||
|
package net.sopod.soim.common.util; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory; |
||||||
|
import com.fasterxml.jackson.core.JsonParser; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.core.json.JsonReadFeature; |
||||||
|
import com.fasterxml.jackson.core.json.PackageVersion; |
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature; |
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; |
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import java.text.SimpleDateFormat; |
||||||
|
import java.time.LocalDate; |
||||||
|
import java.time.LocalDateTime; |
||||||
|
import java.time.LocalTime; |
||||||
|
import java.time.ZoneId; |
||||||
|
import java.time.format.DateTimeFormatter; |
||||||
|
import java.util.Locale; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.TimeZone; |
||||||
|
import java.util.function.Consumer; |
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-04 16:37 |
||||||
|
*/ |
||||||
|
public class Jackson { |
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(Jackson.class); |
||||||
|
|
||||||
|
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
||||||
|
private static final String DATE_FORMAT = "yyyy-MM-dd"; |
||||||
|
private static final String TIME_FORMAT = "HH:mm:ss"; |
||||||
|
|
||||||
|
private static volatile Jackson JSON_INSTANCE; |
||||||
|
private static volatile Jackson YAML_INSTANCE; |
||||||
|
private static volatile Jackson XML_INSTANCE; |
||||||
|
|
||||||
|
private final ObjectMapper objectMapper; |
||||||
|
|
||||||
|
private Jackson(ObjectMapper objectMapper) { |
||||||
|
this.objectMapper = objectMapper; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private static void getFactoryInstance(String clazz, Supplier<Boolean> predicate, Consumer<Jackson> setter) { |
||||||
|
getFactoryInstance(clazz, predicate, mapper->{}, setter); |
||||||
|
} |
||||||
|
|
||||||
|
private static void getFactoryInstance(String clazz, Supplier<Boolean> predicate, Consumer<ObjectMapper> setting, Consumer<Jackson> setter) { |
||||||
|
if (predicate.get()) { |
||||||
|
synchronized (Jackson.class) { |
||||||
|
if (predicate.get()) { |
||||||
|
try { |
||||||
|
Class<?> factoryClazz = Class.forName(clazz); |
||||||
|
Object factoryInstance = factoryClazz.getDeclaredConstructor().newInstance(); |
||||||
|
ObjectMapper mapper; |
||||||
|
if (factoryInstance instanceof ObjectMapper) { |
||||||
|
mapper = new JacksonObjectMapper((ObjectMapper) factoryInstance); |
||||||
|
} else { |
||||||
|
mapper = new JacksonObjectMapper((JsonFactory) factoryInstance); |
||||||
|
} |
||||||
|
setter.accept(new Jackson(mapper)); |
||||||
|
} catch (ReflectiveOperationException e) { |
||||||
|
throw new RuntimeException(clazz, e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class JacksonObjectMapper extends ObjectMapper { |
||||||
|
|
||||||
|
private static final long serialVersionUID = -1848248131995072046L; |
||||||
|
|
||||||
|
public JacksonObjectMapper(ObjectMapper src) { |
||||||
|
super(src); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
public JacksonObjectMapper(JsonFactory factory) { |
||||||
|
super(factory); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ObjectMapper copy() { |
||||||
|
return new JacksonObjectMapper(this); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void init() { |
||||||
|
super.setLocale(Locale.CHINA); |
||||||
|
super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); |
||||||
|
super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); |
||||||
|
super.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT, Locale.CHINA)); |
||||||
|
super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); |
||||||
|
super.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true); |
||||||
|
super.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true); |
||||||
|
|
||||||
|
super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); |
||||||
|
super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
||||||
|
super.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true); |
||||||
|
super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); |
||||||
|
|
||||||
|
super.findAndRegisterModules(); |
||||||
|
// 放到jackson-datatype-jsr310后注册,不然被覆盖
|
||||||
|
super.registerModule(new MyJavaTimeModule()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* jsr310 默认 LocalDateTime 正反序列化格式 DateTimeFormatter.ISO_LOCAL_DATE_TIME |
||||||
|
*/ |
||||||
|
private static class MyJavaTimeModule extends SimpleModule { |
||||||
|
public MyJavaTimeModule() { |
||||||
|
super(PackageVersion.VERSION); |
||||||
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); |
||||||
|
DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT); |
||||||
|
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT); |
||||||
|
this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter)); |
||||||
|
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateFormatter)); |
||||||
|
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); |
||||||
|
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter)); |
||||||
|
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateFormatter)); |
||||||
|
this.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Jackson json() { |
||||||
|
getFactoryInstance("com.fasterxml.jackson.core.JsonFactory", |
||||||
|
() -> JSON_INSTANCE == null, |
||||||
|
jackson -> JSON_INSTANCE = jackson); |
||||||
|
return JSON_INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 依赖 jackson-dataformat-yaml |
||||||
|
*/ |
||||||
|
public static Jackson yaml() { |
||||||
|
getFactoryInstance("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", |
||||||
|
() -> YAML_INSTANCE == null, |
||||||
|
jackson -> YAML_INSTANCE = jackson); |
||||||
|
return YAML_INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 依赖 jackson-dataformat-xml |
||||||
|
*/ |
||||||
|
public static Jackson xml() { |
||||||
|
getFactoryInstance("com.fasterxml.jackson.dataformat.xml.XmlMapper", |
||||||
|
() -> XML_INSTANCE == null, |
||||||
|
jackson -> XML_INSTANCE = jackson); |
||||||
|
return XML_INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public <T> T deserialize(String content, Class<T> valueType) { |
||||||
|
try { |
||||||
|
return objectMapper.readValue(content, valueType); |
||||||
|
} catch (JsonProcessingException e) { |
||||||
|
log.error(e.getMessage(), e); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public <T> String serialize(T value) { |
||||||
|
try { |
||||||
|
return objectMapper.writeValueAsString(value); |
||||||
|
} catch (JsonProcessingException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
log.error(e.getMessage(), e); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public <T> T toPojo(Map<String, Object> fromValue, Class<T> toValueType) { |
||||||
|
return objectMapper.convertValue(fromValue, toValueType); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>so-im</artifactId> |
||||||
|
<groupId>net.sopod</groupId> |
||||||
|
<version>1.0.0</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<artifactId>im-core</artifactId> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>net.sopod</groupId> |
||||||
|
<artifactId>im-common</artifactId> |
||||||
|
<version>${soim.version}</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>net.sopod</groupId> |
||||||
|
<artifactId>im-data</artifactId> |
||||||
|
<version>${soim.version}</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>io.netty</groupId> |
||||||
|
<artifactId>netty-all</artifactId> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
</project> |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
package net.sopod.soim.core.net; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.channel.ChannelHandlerContext; |
||||||
|
import io.netty.channel.CombinedChannelDuplexHandler; |
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder; |
||||||
|
import io.netty.handler.codec.MessageToByteEncoder; |
||||||
|
import net.sopod.soim.data.serialize.ImMessage; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* ImEntryCodec |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 11:29 |
||||||
|
*/ |
||||||
|
public class ImEntryCodec extends CombinedChannelDuplexHandler<ImEntryCodec.ImDecoder, ImEntryCodec.ImEncoder> { |
||||||
|
|
||||||
|
public ImEntryCodec() { |
||||||
|
super(new ImDecoder(), new ImEncoder()); |
||||||
|
} |
||||||
|
|
||||||
|
public static class ImDecoder extends ByteToMessageDecoder { |
||||||
|
@Override |
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception { |
||||||
|
ImMessage message = ImMessage.read(byteBuf); |
||||||
|
if (message == ImMessage.MAGIC_ERROR |
||||||
|
|| message == ImMessage.PROTOCOL_ERROR) { |
||||||
|
ctx.channel().close(); |
||||||
|
return; |
||||||
|
} |
||||||
|
list.add(message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class ImEncoder extends MessageToByteEncoder<ImMessage> { |
||||||
|
@Override |
||||||
|
protected void encode(ChannelHandlerContext ctx, ImMessage imMessage, ByteBuf byteBuf) throws Exception { |
||||||
|
imMessage.write(byteBuf); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
package net.sopod.soim.core.net; |
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext; |
||||||
|
import io.netty.channel.SimpleChannelInboundHandler; |
||||||
|
import net.sopod.soim.data.constant.SerializeType; |
||||||
|
import net.sopod.soim.data.serialize.ImMessage; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* ImMessageHandler |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 13:27 |
||||||
|
*/ |
||||||
|
public class ImMessageHandler extends SimpleChannelInboundHandler<ImMessage> { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ImMessage imMessage) throws Exception { |
||||||
|
byte[] body = imMessage.getBody(); |
||||||
|
SerializeType serialize = SerializeType.getSerializeByOrdinal(imMessage.getSerializeType()); |
||||||
|
Map data = serialize.getSerializer().deserialize(body, Map.class); |
||||||
|
System.out.println(data); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
package net.sopod.soim.core.registry; |
||||||
|
|
||||||
|
import net.sopod.soim.core.service.ReqHandler; |
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||||
|
|
||||||
|
/** |
||||||
|
* ServiceRegistry |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 14:30 |
||||||
|
*/ |
||||||
|
public class ServiceRegistry { |
||||||
|
|
||||||
|
private static final ConcurrentHashMap<Integer, Class<?>> serviceIdParamTypeMap; |
||||||
|
|
||||||
|
private static final ConcurrentHashMap<Class<?>, Integer> paramTypeServiceIdMap; |
||||||
|
|
||||||
|
private static final ConcurrentHashMap<Integer, ReqHandler<?>> serviceIdHandlers; |
||||||
|
|
||||||
|
static { |
||||||
|
serviceIdParamTypeMap = new ConcurrentHashMap<>(); |
||||||
|
paramTypeServiceIdMap = new ConcurrentHashMap<>(); |
||||||
|
serviceIdHandlers = new ConcurrentHashMap<>(); |
||||||
|
} |
||||||
|
|
||||||
|
private static final AtomicInteger serviceIdGen = new AtomicInteger(10000); |
||||||
|
|
||||||
|
private static <T> void registry(Class<T> paramType, ReqHandler<T> handler) { |
||||||
|
int serviceId = serviceIdGen.getAndIncrement(); |
||||||
|
serviceIdParamTypeMap.put(serviceId, paramType); |
||||||
|
paramTypeServiceIdMap.put(paramType, serviceId); |
||||||
|
serviceIdHandlers.put(serviceId, handler); |
||||||
|
} |
||||||
|
|
||||||
|
public void aaa() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
package net.sopod.soim.core.service; |
||||||
|
|
||||||
|
/** |
||||||
|
* ReqHandler |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 14:33 |
||||||
|
*/ |
||||||
|
public interface ReqHandler<T> { |
||||||
|
|
||||||
|
Object handle(T param); |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
package net.sopod.soim.data.serialize; |
||||||
|
|
||||||
|
/** |
||||||
|
* ByteSerializer |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 11:03 |
||||||
|
*/ |
||||||
|
public interface ByteSerializer { |
||||||
|
|
||||||
|
<T> T deserialize(byte[] data, Class<T> clazz) throws Exception; |
||||||
|
|
||||||
|
byte[] serialize(Object pojo) throws Exception; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
package net.sopod.soim.data.serialize; |
||||||
|
|
||||||
|
import net.sopod.soim.common.util.Jackson; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* JsonByteSerializer |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 11:05 |
||||||
|
*/ |
||||||
|
public class JacksonByteSerializer implements ByteSerializer{ |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(JacksonByteSerializer.class); |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> T deserialize(byte[] data, Class<T> clazz) throws Exception { |
||||||
|
String json = new String(data, StandardCharsets.UTF_8); |
||||||
|
T obj = Jackson.json().deserialize(json, clazz); |
||||||
|
if (obj == null) { |
||||||
|
logger.error("json数据解析失败:{}", json); |
||||||
|
throw new IllegalStateException("json数据解析失败"); |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public byte[] serialize(Object pojo) throws Exception { |
||||||
|
String json = Jackson.json().serialize(pojo); |
||||||
|
return json.getBytes(StandardCharsets.UTF_8); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
package net.sopod.soim.data.transer; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* LoginReq |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 14:24 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class LoginReq { |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
private String password; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,88 @@ |
|||||||
|
package net.sopod.soim.entry.server; |
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap; |
||||||
|
import io.netty.buffer.PooledByteBufAllocator; |
||||||
|
import io.netty.channel.ChannelFutureListener; |
||||||
|
import io.netty.channel.ChannelOption; |
||||||
|
import io.netty.channel.WriteBufferWaterMark; |
||||||
|
import io.netty.channel.nio.NioEventLoopGroup; |
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel; |
||||||
|
import io.netty.util.concurrent.DefaultThreadFactory; |
||||||
|
import net.sopod.soim.common.constant.Consts; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
/** |
||||||
|
* EntryServer |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 11:19 |
||||||
|
*/ |
||||||
|
public class EntryServer { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(EntryServer.class); |
||||||
|
|
||||||
|
private NioEventLoopGroup boss; |
||||||
|
private NioEventLoopGroup worker; |
||||||
|
private ServerBootstrap serverBootstrap; |
||||||
|
|
||||||
|
private String name; |
||||||
|
private int port; |
||||||
|
|
||||||
|
public static final int LOW_WATER_MARK = 32 * Consts.KB; |
||||||
|
public static final int HIGH_WATER_MARK = 64 * Consts.KB; |
||||||
|
|
||||||
|
public EntryServer(String name, int port) { |
||||||
|
this.name = name; |
||||||
|
this.port = port; |
||||||
|
this.boss = |
||||||
|
new NioEventLoopGroup(1, new DefaultThreadFactory("entry-boss", Thread.MAX_PRIORITY)); |
||||||
|
this.worker = |
||||||
|
new NioEventLoopGroup(new DefaultThreadFactory("entry-worker", Thread.MAX_PRIORITY)); |
||||||
|
this.bootstrap(); |
||||||
|
} |
||||||
|
|
||||||
|
private void bootstrap() { |
||||||
|
this.serverBootstrap = new ServerBootstrap() |
||||||
|
.group(boss, worker) |
||||||
|
.channel(NioServerSocketChannel.class) |
||||||
|
.childHandler(new ImEntryInitializer()) |
||||||
|
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) |
||||||
|
.option(ChannelOption.SO_RCVBUF, 32 * Consts.KB) |
||||||
|
.option(ChannelOption.SO_REUSEADDR, true) |
||||||
|
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, |
||||||
|
new WriteBufferWaterMark(LOW_WATER_MARK, HIGH_WATER_MARK)) |
||||||
|
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) |
||||||
|
.childOption(ChannelOption.TCP_NODELAY, true) |
||||||
|
.childOption(ChannelOption.SO_RCVBUF, 32 * Consts.KB) |
||||||
|
.childOption(ChannelOption.SO_SNDBUF, 64 * Consts.KB) |
||||||
|
.childOption(ChannelOption.SO_REUSEADDR, true) |
||||||
|
.childOption( |
||||||
|
ChannelOption.WRITE_BUFFER_WATER_MARK, |
||||||
|
new WriteBufferWaterMark(LOW_WATER_MARK, HIGH_WATER_MARK)); |
||||||
|
} |
||||||
|
|
||||||
|
public void startServer(Consumer<Throwable> onFail) { |
||||||
|
this.serverBootstrap |
||||||
|
.bind(port) |
||||||
|
.addListener((ChannelFutureListener) future -> { |
||||||
|
if (!future.isSuccess()) { |
||||||
|
if (onFail != null) { |
||||||
|
onFail.accept(future.cause()); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
System.out.println(String.format("%s %s listen...", name, port)); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public void shutdown() { |
||||||
|
logger.info("netty reactor group shutting down..."); |
||||||
|
boss.shutdownGracefully(); |
||||||
|
worker.shutdownGracefully(); |
||||||
|
logger.info("netty reactor group already shutdown!"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
package net.sopod.soim.entry.server; |
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer; |
||||||
|
import io.netty.channel.ChannelPipeline; |
||||||
|
import io.netty.channel.socket.SocketChannel; |
||||||
|
import io.netty.handler.logging.LogLevel; |
||||||
|
import io.netty.handler.logging.LoggingHandler; |
||||||
|
import net.sopod.soim.core.net.ImEntryCodec; |
||||||
|
import net.sopod.soim.core.net.ImMessageHandler; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* ImEntryInitializer |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-03-28 11:25 |
||||||
|
*/ |
||||||
|
public class ImEntryInitializer extends ChannelInitializer<SocketChannel> { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ImEntryInitializer.class); |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initChannel(SocketChannel socketChannel) throws Exception { |
||||||
|
LogLevel logLevel = logger.isDebugEnabled() ? LogLevel.DEBUG : LogLevel.INFO; |
||||||
|
ChannelPipeline pipeline = socketChannel.pipeline(); |
||||||
|
pipeline.addLast(new LoggingHandler(logLevel)) |
||||||
|
.addLast(new ImEntryCodec()) |
||||||
|
.addLast(new ImMessageHandler()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue