登陆,注册,私聊,群聊
syntax = "proto2";
message Request{
//消息类型 ,用户名,密码,消息,接收者(私聊,群聊)
required int32 type = 1;//登录,心跳,私聊,群聊
required string username = 2;
optional string password = 3;
optional string msg = 4;
optional string receiver = 5;
}
你需要使用protoc.exe生成Msg类,这里不涉及介绍
public class Constant {
public static final String LOGIN_SUCCESS = "LOGIN_OK";
public static final String LOGIN_FAIL = "LOGIN_FAIL";
public static final String REGISTER_SUCCESS = "REGISTER_OK";
public static final String REGISTER_FAIL = "REGISTER_FAIL";
public static final String ALL = "all";
public static final String LOGIN = "login";//登录指令
public static final String REGISTER = "register";//注册指令
public static final String SEND = "send";//发送消息指令
}
public enum MsgType {
//请求消息
SERVICE_REQ(0),
//响应消息
SERVICE_RESP(1),
//请求响应消息
ONE_WAY(2),
//握手请求消息
LOGIN_REQ(3),
//握手响应消息
LOGIN_RESP(4),
//心跳请求消息
HEARTBEAT_REQ(5),
//心跳响应消息
HEARTBEAT_RESP(6),
//发送消息请求
SEND_REQ(7),
//发送消息响应
SEND_RESP(8),
//注册请求
REGISTER_REQ(9),
//注册响应
REGISTER_RESP(10),
//接收响应
RECEIVE_RESP(11);
private int value;
MsgType(int value) {
this.value = value;
}
public int value(){
return this.value;
}
}
public class Account {
//username pwd
public static Map<String,String> account = new HashMap<>();
//username channel
public static Map<String, ChannelHandlerContext> channelMap = new HashMap<>();
//channels
public static List<ChannelHandlerContext> channels = new ArrayList<>();
}
public class Server {
public static void main(String[] args) {
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(boss,worker);
server.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024) //设置TCP缓冲区
.option(ChannelOption.SO_RCVBUF, 32*1024) // 设置接受数据的缓存大小
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE) // 设置保持连接
.childOption(ChannelOption.SO_SNDBUF, 32*1024);
server.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(Msg.Request.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new ServerHandler());
}
});
ChannelFuture future = server.bind(9990).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
@ChannelHandler.Sharable
public class ServerHandler extends SimpleChannelInboundHandler<Msg.Request> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Msg.Request request) throws Exception {
System.out.println(request);
int msgType = request.getType();
//注册请求
if(msgType== MsgType.REGISTER_REQ.value()){
String username = request.getUsername();
Msg.Request registerResp = null;
if(Constant.ALL.equals(username)||Account.account.containsKey(username)){
registerResp = buildRegisterResult(username,false);
}else{
String pwd = request.getPassword();
Account.account.put(username,pwd);//注册的账户
registerResp = buildRegisterResult(username,true);
}
ctx.writeAndFlush(registerResp);
}
//登录请求
else if(msgType== MsgType.LOGIN_REQ.value()){
String username = request.getUsername();
String password = request.getPassword();
Msg.Request loginResp = null;
String accountPwd = Account.account.get(username);
if(password.equals(accountPwd)){
Account.channelMap.put(username,ctx);
loginResp = buildLoginResult(true,username);
}else {
loginResp = buildLoginResult(false,username);
}
ctx.writeAndFlush(loginResp);
}
//发送请求
else if(msgType== MsgType.SEND_REQ.value()){
String username = request.getUsername();//发送者
String receiver = request.getReceiver();//接收者
String msg = request.getMsg();//发送消息
//群聊 通知接收者
if(Constant.ALL.equals(receiver)){
Set set = Account.channelMap.entrySet();
Iterator it = set.iterator();
while(it.hasNext()){
Map.Entry<String, ChannelHandlerContext> entry = (Map.Entry<String, ChannelHandlerContext>) it.next();
if(ctx!=entry.getValue()){
//除了自己不发,其他都发
Msg.Request allReceiveResp = buildReceiveResult(username,msg,entry.getKey());
entry.getValue().writeAndFlush(allReceiveResp);
}
}
}else{ //私聊 通知接收者
//判断receiver是否存在
if(!Account.account.containsKey(receiver)){
//通知发送者发送失败
Msg.Request sendFailResp = buildSendFailResult(receiver,"不存在该账户");
ctx.writeAndFlush(sendFailResp);
return;
}
ChannelHandlerContext channel = Account.channelMap.get(receiver);
Msg.Request receiveResp = buildReceiveResult(username,msg,receiver);
channel.writeAndFlush(receiveResp);
}
//通知发送者发送成功
Msg.Request sendResp = buildSendResult(receiver);
ctx.writeAndFlush(sendResp);
}
}
private Msg.Request buildSendFailResult(String receiver, String failReason) {
Msg.Request sendFailResp = Msg.Request.newBuilder().
setType(MsgType.SEND_RESP.value())
.setUsername("server").
setMsg("发送给"+receiver+"失败:"+failReason).build();
return sendFailResp;
}
/**
*
* @param username 发送者
* @param msg 内容
* @param receiver 接收者
* @return
*/
private Msg.Request buildReceiveResult(String username, String msg, String receiver) {
Msg.Request receiveResp = Msg.Request.newBuilder().
setType(MsgType.RECEIVE_RESP.value()) //消息类型
.setUsername(username). //发送者
setMsg(msg). //消息内容
setReceiver(receiver). //接收者
build();
return receiveResp;
}
private Msg.Request buildSendResult(String receiver) {
Msg.Request sendResp = Msg.Request.newBuilder().
setType(MsgType.SEND_RESP.value())
.setUsername("server").
setMsg("发送给"+receiver+"成功").build();
return sendResp;
}
private Msg.Request buildLoginResult(boolean isSuccess, String username){
String msg = isSuccess?Constant.LOGIN_SUCCESS:Constant.LOGIN_FAIL;
Msg.Request loginResp = Msg.Request.newBuilder().
setType(MsgType.LOGIN_RESP.value())
.setUsername("server").
setMsg(msg).
setReceiver(username).
build();
return loginResp;
}
private Msg.Request buildRegisterResult(String username, boolean isSuccess) {
String msg = isSuccess? Constant.REGISTER_SUCCESS:Constant.REGISTER_FAIL;
Msg.Request registerResp = Msg.Request.newBuilder().
setType(MsgType.REGISTER_RESP.value())
.setUsername("server").
setMsg(msg).
setReceiver(username).
build();
return registerResp;
}
}
public class Client {
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap client = new Bootstrap();
client.group(group);
client.channel(NioSocketChannel.class);
client.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());//半包
pipeline.addLast(new ProtobufDecoder(Msg.Request.getDefaultInstance()));//解码的目标类
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture future = client.connect(new InetSocketAddress("localhost",9990)).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
}
@ChannelHandler.Sharable
public class ClientHandler extends SimpleChannelInboundHandler<Msg.Request> {
private static String username;
ExecutorService exec = Executors.newSingleThreadExecutor();
@Override
protected void channelRead0(final ChannelHandlerContext ctx, Msg.Request request) throws Exception {
int msgType = request.getType();
//注册响应
if(msgType==MsgType.REGISTER_RESP.value()){
if(Constant.REGISTER_SUCCESS.equals(request.getMsg())){
System.out.println("register success");
System.out.println("登录指令示范:login 用户名 密码");
}else{
System.out.println("register fail");
}
}
//登录响应
else if(msgType==MsgType.LOGIN_RESP.value()){
if(Constant.LOGIN_SUCCESS.equals(request.getMsg())){
username = request.getReceiver();
System.out.println("login success");
System.out.println("发送指令示范:send 接收者(发送给所有人写all) 发送内容");
}else{
System.out.println("login fail");
}
}
//发送响应
else if(msgType==MsgType.SEND_RESP.value()){
System.out.println(request.getMsg());
}
//接收别人的消息
else if(msgType==MsgType.RECEIVE_RESP.value()){
String sendName = request.getUsername();
String msg = request.getMsg();
System.out.println("接收到"+sendName+"的消息:"+msg);
}
exec.execute(new Runnable() {
@Override
public void run() {
try {
handlerCommend(ctx);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("注册指令示范:register 用户名 密码");
System.out.println("登录指令示范:login 用户名 密码");
System.out.println("发送指令示范:send 接收者(发送给所有人写all) 发送内容");
handlerCommend(ctx);
}
private void handlerCommend(ChannelHandlerContext ctx) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String commendStr = reader.readLine();
String[] splits = commendStr.split(" ");
String commend = splits[0];
Msg.Request req = null;
switch (commend){
//注册
case Constant.REGISTER:
if(splits.length!=3){
System.out.println("指令错误,正确示范:register 用户名 密码");
handlerCommend(ctx);
}
req = buildRegisterReq(splits[1],splits[2]);
ctx.writeAndFlush(req);
break;
//登录
case Constant.LOGIN:
if(splits.length!=3){
System.out.println("指令错误,正确示范:login 用户名 密码");
handlerCommend(ctx);
}
req = buildLoginReq(splits[1],splits[2]);
ctx.writeAndFlush(req);
break;
case Constant.SEND:
if(splits.length!=3){
System.out.println("指令错误,正确示范:send 接收者 内容");
handlerCommend(ctx);
}
if(username.equals(splits[1])){
System.out.println("指令错误:接收者和发送者一样");
handlerCommend(ctx);
}
req = buildSendMsg(splits[1],splits[2]);
ctx.writeAndFlush(req);
break;
default:
System.out.println("指令错误");
System.out.println("注册指令示范:register 用户名 密码");
System.out.println("登录指令示范:login 用户名 密码");
System.out.println("发送指令示范:send 接收者(发送给所有人写all) 发送内容");
handlerCommend(ctx);
break;
}
}
private Msg.Request buildSendMsg(String receiver, String content) {
Msg.Request req = Msg.Request.newBuilder().
setUsername(username).//发送者
setType(MsgType.SEND_REQ.value()).
setReceiver(receiver).//接收者
setMsg(content).
build();
return req;
}
private Msg.Request buildLoginReq(String username, String pwd) {
Msg.Request req = Msg.Request.newBuilder().
setType(MsgType.LOGIN_REQ.value()).
setUsername(username).
setPassword(pwd).
setMsg("login").
setReceiver("server").
build();
return req;
}
private Msg.Request buildRegisterReq(String username, String pwd) {
Msg.Request req = Msg.Request.newBuilder().
setType(MsgType.REGISTER_REQ.value()).
setUsername(username).
setPassword(pwd).
setMsg("register").
setReceiver("server").
build();
return req;
}
}