作为一只刚毕业、在校学业也不好的的新手小白,来公司报道的第二天老板就Duang的一下丢来一本netty教材,对此我觉得压力山大啊,超后悔在学校没有多学点东西。但是,苏轼他老爸苏老泉二十七岁才好好学习并且为时不晚,我现在开始努力也是来得及的。
按照我自己的理解,聊天的原理是这样的:客户机与服务器之间制定一个传输数据的规则,客户机将用户期望的操作按照这个规则传输给服务器,服务器再按照用户的期望进行操作,即客户机A想要将数据传输给客户机B,那么,客户机A先将数据传输给服务器,服务器读取数据中内容后,按照期望的操作将数据传输给客户机B,客户机B接收数据。
接下来就是实际的编写阶段了。
首先是传输规则的制定,在ChatRoomUserTalk里,设定了三个变量,talk存储了会话内容,toUser存储了收信人,fromUser存储了寄信人,由于基于netty的信息传输要遵循netty自身的设定,因此要有一个信息加密、解密的过程。
以下是信息加密解密,都是重写了netty本身就有的方法。
ChatRoomMessageDecoder MessageToMessageDecoder<ByteBuf> { decode(ChannelHandlerContext ctx, ByteBuf msg,List<Object> out) Exception { [] array; length = msg.readableBytes(); array = [length]; msg.getBytes(msg.readerIndex(), array, , length); MessagePack msgpack=MessagePack(); ChatRoomUserTalk userTalk=msgpack.read(array,ChatRoomUserTalk.); out.add(userTalk); } }
ChatRoomMessageEncoder MessageToByteEncoder<Object> { encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) Exception { MessagePack msgpack = MessagePack(); { [] raw = msgpack.write(msg); out.writeBytes(raw); } (Exception e) { System..println(); e.printStackTrace(); } } }
在ChatRoomClientHandler里并没有什么过多的功能。
channelRead(ChannelHandlerContext ctx, Object msg) { ChatRoomUserTalk userTalk=(ChatRoomUserTalk)msg;.append( userTalk.getTalk());}
在ChatRoomClient中写了一个简单丑陋的窗口用来收发信息,相关配置信息不多说。
JTextArea =JTextArea(); JTextField =JTextField(); JTextField =JTextField(); JTextField =JTextField(); JTextField =JTextField(); JButton =JButton(); Container ;
field.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ChatRoomUserTalk userTalk = new ChatRoomUserTalk(); userTalk.setTalk(field.getText()); userTalk.setToUser(toUserName.getText()); userTalk.setFromUser(fromUser.getText()); if (channelFuture.channel().isOpen()) { channelFuture.channel().write(userTalk); channelFuture.channel().flush(); } area.append(fromUser.getText() + ":" + userTalk.getTalk() + '\n'); area.setSelectionEnd(area.getText().length()); field.setText(""); } }); closeChannel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(closeChannel.getText()=="关闭连接") { channelFuture.channel().close(); closeChannel.setText("打开连接"); } }
以上是客户端方面。
在服务器方面,由于要对客户机发来的信息进行判断,所以内容相对较多(虽然事实是我写的东西也并没有多少)。
public class ChatRoomServerHandler extends ChannelHandlerAdapter static final Map<String,Channel> channelMap= Collections.synchronizedMap(new HashMap<String, Channel>());
创建一张哈希表用来存储登陆用户,通过用户名以及用户使用的channel来进行信息传送操作。
channelRead(ChannelHandlerContext ctx, Object msg)Exception { ChatRoomUserTalk userTalk=(ChatRoomUserTalk)msg; (!.containsKey(userTalk.getFromUser())) { .put(userTalk.getFromUser(),ctx.channel()); } String cutArry[]=userTalk.getToUser().split(); (i=;i<cutArry.;i++) { (.get(cutArry[i]) != ) { String temp=((ChatRoomUserTalk) msg).getTalk(); ((ChatRoomUserTalk) msg).setTalk(((ChatRoomUserTalk) msg).getFromUser() + + temp+); .get(cutArry[i]).write(msg); ctx.flush(); } { (i = ; i < cutArry.; i++) { ((ChatRoomUserTalk) msg).setTalk(cutArry[i] + + + ); ctx.writeAndFlush(userTalk); } } } (!ctx.channel().isOpen()){ .remove(userTalk.getFromUser()); } }
至此,这个简单粗陋而且并没有什么卵用的聊天程序的主要代码都在这里啦,尽管大部分都是参照老大写的例子来的,但是对于我这个大学四年没怎么写过程序成天酱油的孩子而言,不管怎么说,这至少是一个好的开端不是……虽然其实聊天的信息是乱的,嘛,好歹是个进步
PS、实际聊天的时候,因为是在textField里面按回车发送信息,不按回车就没有动作,所以A给B发信息后,B要先发出一个信息才能看见A发的信息,这个问题要怎么办呀OTZ,有没有大牛教教我怎么改掉(……好吧其实我废话这么多最主要就是想问这个,害羞飘走)