人生就是不断的转圈子——一个最简单的jboss netty chat测试程序

这几天,研究网络和分布式——我想弄一个可自由扩展的高效率的围棋系统。
有几个问题是要必须得解决的:
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 Set<Channel> channels =Collections.synchronizedSet(new HashSet<Channel>());
    
    @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());
	}
	
}



我知道我又回到了老地方,我在不断的绕着圈子,不过这个圈子是螺旋上升的。
每一次,我都会在稍微高一点的地方看原来的问题,这也许就是生命智力的有限和无奈啊!
如果我一开始就可以看穿这一切,那么,我不就可以省了很多的功夫了吗?!

你可能感兴趣的:(java,jboss,erlang,swing,socket)