`
ansjsun
  • 浏览: 199749 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

socket服务类.在csdn花了5分下载下来的

阅读更多
我当时花了5分下载下来的.在这里免费发布..有参考价值要给我留言啊..做人要有人品的

package test.sockettest;
/**
 * 
 * @author chenjd
 */
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class NBServer {
	int port = 8090;
	int BUFFERSIZE = 1024;
	Selector selector = null;
	ServerSocketChannel serverChannel = null;
	HashMap clientChannelMap = null;// 用来存放每一个客户连接对应的套接字和通道

	public NBServer(int port) {
		this.clientChannelMap = new HashMap();
		this.port = port;
	}

	public void initialize() throws IOException {
		// 初始化,分别实例化一个选择器,一个服务器端可选择通道
		this.selector = Selector.open();
		this.serverChannel = ServerSocketChannel.open();
		this.serverChannel.configureBlocking(false);
		InetAddress localhost = InetAddress.getLocalHost();
		InetSocketAddress isa = new InetSocketAddress(localhost, this.port);
		this.serverChannel.socket().bind(isa);// 将该套接字绑定到服务器某一可用端口
	}

	// 结束时释放资源
	public void finalize() throws IOException {
		this.serverChannel.close();
		this.selector.close();
	}

	// 将读入字节缓冲的信息解码
	public String decode(ByteBuffer byteBuffer) throws CharacterCodingException {
		Charset charset = Charset.forName("ISO-8859-1");
		CharsetDecoder decoder = charset.newDecoder();
		CharBuffer charBuffer = decoder.decode(byteBuffer);
		String result = charBuffer.toString();
		return result;
	}

	// 监听端口,当通道准备好时进行相应操作
	public void portListening(String data) throws IOException, InterruptedException {
		// 服务器端通道注册OP_ACCEPT事件
		SelectionKey acceptKey = this.serverChannel.register(this.selector,
				SelectionKey.OP_ACCEPT);
		// 当有已注册的事件发生时,select()返回值将大于0
		while (acceptKey.selector().select() > 0) {
			System.out.println("event happened");
			// 取得所有已经准备好的所有选择键
			Set readyKeys = this.selector.selectedKeys();
			// 使用迭代器对选择键进行轮询
			Iterator i = readyKeys.iterator();
			while (i.hasNext()) {
				SelectionKey key = (SelectionKey) i.next();
				i.remove();// 删除当前将要处理的选择键
				if (key.isAcceptable()) {// 如果是有客户端连接请求
					System.out.println("more client connect in!");
					ServerSocketChannel nextReady = (ServerSocketChannel) key
							.channel();
					// 获取客户端套接字
					Socket s = nextReady.accept().socket();
					// 设置对应的通道为异步方式并注册感兴趣事件
					s.getChannel().configureBlocking(false);
					SelectionKey readWriteKey = s.getChannel().register(
							this.selector,
							SelectionKey.OP_READ | SelectionKey.OP_WRITE);
					// 将注册的事件与该套接字联系起来
					readWriteKey.attach(s);
					// 将当前建立连接的客户端套接字及对应的通道存放在哈希表//clientChannelMap中
					this.clientChannelMap.put(s, new ClientChInstance(s
							.getChannel()));
				} else if (key.isReadable()) {// 如果是通道读准备好事件
					System.out.println("Readable");
					// 取得选择键对应的通道和套接字
					SelectableChannel nextReady = (SelectableChannel) key
							.channel();
					Socket socket = (Socket) key.attachment();
					// 处理该事件,处理方法已封装在类ClientChInstance中
					this.readFromChannel(socket.getChannel(),
							(ClientChInstance) this.clientChannelMap
									.get(socket));
				} else if (key.isWritable()) {// 如果是通道写准备好事件
					System.out.println("writeable");
					// 取得套接字后处理,方法同上
					Socket socket = (Socket) key.attachment();
					SocketChannel channel = (SocketChannel) socket.getChannel();
//					this.writeToChannel(channel, "This is from server!");
					this.writeToChannel(channel, data);
				}
			}
		}
	}

	// 对通道的写操作
	public void writeToChannel(SocketChannel channel, String message)
			throws IOException {
		ByteBuffer buf = ByteBuffer.wrap(message.getBytes());
		int nbytes = channel.write(buf);
	}

	// 对通道的读操作
	public void readFromChannel(SocketChannel channel,
			ClientChInstance clientInstance) throws IOException,
			InterruptedException {
		ByteBuffer byteBuffer = null;
		try{
			byteBuffer = ByteBuffer.allocate(BUFFERSIZE);
			int nbytes = channel.read(byteBuffer);
		}catch(Exception e){
			clientChannelMap.remove(channel.socket());
			channel.close();
			e=null;
			return;
		}
		byteBuffer.flip();
		String result = this.decode(byteBuffer);
		// 当客户端发出”@exit”退出命令时,关闭其通道
		if (result.indexOf("@exit") >= 0||result.indexOf("q")>=0) {
			channel.close();
		}
//		else if(result.indexOf("@close") >= 0){//关闭服务
//			channel.close();
//			this.finalize();
//		}
		else {
			clientInstance.append(result.toString());
			// 读入一行完毕,执行相应操作
			if (result.indexOf("\n") >= 0) {
				System.out.println("client input" + result);
				clientInstance.execute();
			}
		}
	}

	// 该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法
	public class ClientChInstance {
		SocketChannel channel;
		StringBuffer buffer = new StringBuffer();

		public ClientChInstance(SocketChannel channel) {
			this.channel = channel;
		}

		public void execute() throws IOException {
			String message = "This is response after reading from channel!";
			writeToChannel(this.channel, message);
			buffer = new StringBuffer();
		}

		// 当一行没有结束时,将当前字窜置于缓冲尾
		public void append(String values) {
			buffer.append(values);
		}
	}

	// 主程序
	public static void main(String[] args) {
		NBServer nbServer = new NBServer(8090);
		try {
			nbServer.initialize();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
		try {
			nbServer.portListening("This is from server!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
分享到:
评论
6 楼 dizhuang 2012-02-13  
我搞不懂为什么需要注册Write事件,我注册Read了,一边读取一边处理不就可以了。
5 楼 chasewade 2012-02-10  
多谢分享啊
4 楼 lsrjava 2011-11-10  
学习一下,感谢楼主的分享啊
3 楼 wupuyuan 2011-09-14  
谢谢分享,一定要顶下
2 楼 maenliang1989 2011-09-14  
好一个事件驱动模型
1 楼 qitongster 2011-08-17  
我不知道是否有参考价值,但是很感谢你的这种奉献精神,5分不便宜啊!

没有到用socket编程的环境和境界,有机会再参考吧。

相关推荐

    socketTool

    ★ 在一个程序内可进行多句柄/多类型的Socket的创建/删除/以及数据收发等操作 ★ 支持16进制的发送和16进制接收显示,支持汉字以及文本发送 ★ 用户可以方便的把接收到的数据保存下来 ★ 支持发送、接收字节...

    socket套接字编程

    网络编程中,通常使用socket套接字编程,那么该如何使用呢?接下来我们做一个最基本的小程序实现其功能。博客地址:http://blog.csdn.net/bingdianlanxin,有问题欢迎留言!

    Xsocket_V2_8_15.rar

    Xsocket_V2_8_15.rar 一个开源的基于TCP的Socket通信框架...内含开发包、源码和javadoc,javadoc用htmlParser(http://download.csdn.net/detail/liu149339750/4672852)从网站上抓下来的,源码也是从网站上抓下来的。

    vc++ 开发实例源码包

    使用了六个类五个模块类演示了atl的调用方法 class CDHtmlSinkHandler; // Events Sink Base class CDHtmlEventSink; // IHTMLDocument2 Events Sink // IDispatch class CDHtmlControlSink; // ActiveX Control ...

    RTSPServer_HI3516 测试完成

    源代码是CSDN上一位前辈的,我只做了代码整理和优化,测试下来四路D1同时放,延时约2s.用法流程如下: 1.InitRtspServer(); 2.udpfd = socket(AF_INET,SOCK_DGRAM,0);//UDP 3.SAMPLE_COMM_VENC_Sentjin(&stStream); ...

    Log4j日志管理系统简单使用说明

     Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG ,明白这一点很重要,这里Log4j有一个规则:假设Loggers级别为P,如果在Loggers中发生了一个级别Q比P高,则...

    vc++ 应用源码包_5

    CSDN免积分下载工具 源码 演示了使用CInternetSession去下载资源。 CStatic文字滚动 如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似...

    vc++ 应用源码包_1

    CSDN免积分下载工具 源码 演示了使用CInternetSession去下载资源。 CStatic文字滚动 如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似...

    vc++ 应用源码包_2

    CSDN免积分下载工具 源码 演示了使用CInternetSession去下载资源。 CStatic文字滚动 如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似...

    vc++ 应用源码包_6

    CSDN免积分下载工具 源码 演示了使用CInternetSession去下载资源。 CStatic文字滚动 如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似...

    vc++ 应用源码包_3

    CSDN免积分下载工具 源码 演示了使用CInternetSession去下载资源。 CStatic文字滚动 如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似...

    C#超级仿QQ

    虽然不是完整版,而且代码没有重构,但也不至于很乱,缺点是我把功能都放在服务端,这样做当然是不合理的,所以大家把代码看懂后可以自己改,资源绝对不是那些垃圾资源,我也很讨厌那种很贵然后下下来是垃圾的资源!...

    c++ 面试题 总结

    private 也被集成,只事派生类没有访问权限而已 virtual可加可不加 子类的空间里有父类的所有变量(static除外) 同一个函数只存在一个实体(inline除外) 子类覆盖它的函数不加virtual ,也能实现多态。 在子类的...

Global site tag (gtag.js) - Google Analytics