有几个问题是要必须得解决的:
1,协议的设计,也就是通信
2,服务器端的架构,比如是阻塞还是事件io之类的支持,包括集群
3,基本网络架构的选择,java nio的框架,实在是有点复杂。
我参考了几个东西:
1,jboss netty一个很不错的基础框架,很干净,我很喜欢
2,apache mina和jboss netty有亲戚,不过我觉得有点乱
3,jcsp这个东西很好,让我对于通讯和计算有了更加深入一点的了解,很漂亮的模型(CSP)
4,java jini,以前我就看过jini实在是那时候,水平太低,没明白,现在大概清楚它是啥东西了——比较高层,sun真的比较超前
5,erlang,我一直犹豫,是不是该用erlang一个搞定所有的问题得了,但是,erlang把你限定的太死了,你没了选择,当然,它很好,直到现在,我还是一头雾水。
我用jboss netty做了一个聊天的程序(主要是测试一下netty的功能),我发现很简单,可是,对于协议的设计,我始终不够自信,我觉得肯定还有什么问题。我的现在的方法只是单向消息对象,只是发消息,收消息,处理消息,其他的一概不理。我觉得不够严谨,到底应该怎么做,我不知道。
现在把代码贴一下,做个纪念吧!
这个程序主要参照了jboss netty里的一个securechat的例子,我去掉了secure的功能,同时加上了swing界面。
package orange; import java.awt.BorderLayout; import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; /** * swing 的client! */ public class OrangeClient { private JTextField input=new JTextField(20); private JTextField output=new JTextField(20); OrangeClientHandler handler; public OrangeClient(){ String host="localhost"; int port=8081; ChannelFactory factory= new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ClientBootstrap bootstrap=new ClientBootstrap(factory); handler=new OrangeClientHandler(output); bootstrap.setPipelineFactory(new OrangePipelineFactory(handler)); bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); bootstrap.connect(new InetSocketAddress(host, port)); } public void init(){ JFrame frame=new JFrame("Orange Client!"); Container container=frame.getContentPane(); frame.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e){ System.exit(0); } }); JPanel pInput=new JPanel(); pInput.setLayout(new FlowLayout()); JLabel inputLabel=new JLabel("input:"); JButton inputButton=new JButton("To Server!"); inputButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { Channel mych=handler.getMyChannel(); if(mych.isOpen()){ ChannelFuture f=mych.write(input.getText()+'\n'); f.addListener(new ChannelFutureListener(){ @Override public void operationComplete(ChannelFuture future) throws Exception { System.out.println("ok!"); } }); } } }); pInput.add(inputLabel); pInput.add(input); pInput.add(inputButton); JPanel pOutput=new JPanel(); pOutput.setLayout(new FlowLayout()); JLabel outputLabel=new JLabel("output:"); pOutput.add(outputLabel); pOutput.add(output); container.setLayout(new BorderLayout()); container.add(BorderLayout.NORTH,pInput); container.add(BorderLayout.SOUTH,pOutput); frame.setLocation(400, 400); frame.pack(); frame.setVisible(true); } public static void main(String[] args){ OrangeClient client=new OrangeClient(); client.init(); } } package orange; import javax.swing.JTextField; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** * client handler */ @ChannelPipelineCoverage("one") public class OrangeClientHandler extends SimpleChannelHandler { private Channel myChannel; private JTextField myout; public OrangeClientHandler(JTextField out){ this.myout=out; } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { setMyChannel(e.getChannel()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { String data=(String) e.getMessage(); myout.setText(data); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { e.getChannel().close(); } public Channel getMyChannel() { return myChannel; } public void setMyChannel(Channel myChannel) { this.myChannel = myChannel; } } package orange; import static org.jboss.netty.channel.Channels.pipeline; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder; /** *这个PipelineFactory很重要,它定义了用serialize object通讯 *定义了编码和解码,以及client 和 server的handler的指定 */ public class OrangePipelineFactory implements ChannelPipelineFactory { private ChannelHandler handler; public OrangePipelineFactory(ChannelHandler handler){ this.handler=handler; } @Override public ChannelPipeline getPipeline(){ ChannelPipeline pipeline = pipeline(); pipeline.addLast("decoder", new ObjectDecoder());//up pipeline.addLast("encoder", new ObjectEncoder());//down pipeline.addLast("myhandler", handler);//my handler include up and down return pipeline; } } package orange; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; /** * server */ public class OrangeServer { public static void main(String[] args) throws Exception{ ChannelFactory factory= new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ServerBootstrap bootstrap=new ServerBootstrap(factory); OrangeServerHandler handler=new OrangeServerHandler(); bootstrap.setPipelineFactory(new OrangePipelineFactory(handler)); bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive",true); bootstrap.bind(new InetSocketAddress(8081)); } } package orange; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** *server side handler,它可以说是最主要的处理事情的地方,我现在只是把所有的channel *放在集合里,有对象来的时候,就告诉大家 */ @ChannelPipelineCoverage("all") public class OrangeServerHandler extends SimpleChannelHandler { static final Setchannels =Collections.synchronizedSet(new HashSet ()); @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { Channel ch=e.getChannel(); channels.remove(ch); ch.close(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { // Convert to a String first. String request = (String) e.getMessage(); // Send the received message to all channels but the current one. for (Channel c: channels) { if (c != e.getChannel()) { c.write("[" + e.getChannel().getRemoteAddress() + "] " + request + '\n'); } } // Close the connection if the client has sent 'bye'. if (request.toLowerCase().equals("bye")) { e.getChannel().close(); } } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { channels.add(e.getChannel()); } }
我知道我又回到了老地方,我在不断的绕着圈子,不过这个圈子是螺旋上升的。
每一次,我都会在稍微高一点的地方看原来的问题,这也许就是生命智力的有限和无奈啊!
如果我一开始就可以看穿这一切,那么,我不就可以省了很多的功夫了吗?!