`
finux
  • 浏览: 202172 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

使用nio实现简单Echo服务

    博客分类:
  • Java
 
阅读更多

最近温习下nio API,无聊写个Echo服务,直接上代码了,有点懒,具体细节不解释,查阅API或源码吧,没有公开的src就反编译下。

 

EchoServer.java

 

package com.iteye.finux.echo;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 有关Selector的一些操作尽可能放同一个线程处理
 * @author zhu
 *
 */
public class EchoServer implements Runnable {
	private int port;
	private InetAddress host;
	private ServerSocketChannel channel;
	private Selector selector;
	private ByteBuffer buffer = ByteBuffer.allocate(1024);
	/**
	 * 若要保证所有信息都传回client, 这里可以把byte[]改为队列或其他容器
	 */
	private Map<SocketChannel, byte[]> messages = new HashMap<SocketChannel, byte[]>();
	
	public EchoServer(InetAddress host, int port) throws Exception {
		this.host = host;
		this.port = port;
		channel = ServerSocketChannel.open();
		channel.configureBlocking(false);
		selector = Selector.open();
	}
	
	/**
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		try {
			channel.socket().bind(new InetSocketAddress(host, port));
			channel.register(selector, SelectionKey.OP_ACCEPT);
			while (true) {
				int count = selector.select();
				if (count < 1) {
					continue;
				}
				Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
				while (iterator.hasNext()) {
					SelectionKey key = iterator.next();
					iterator.remove();
					if (!key.isValid()) {
						continue;
					}
					if (key.isAcceptable()) {
						SocketChannel ch = ((ServerSocketChannel)key.channel()).accept();
						ch.configureBlocking(false);
						ch.register(selector, SelectionKey.OP_READ);
					} else if (key.isReadable()) {
						read(key);
					} else if (key.isWritable()) {
						write(key);
					}
				}
			}
		} catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	
	/**
	 * 读操作
	 * @param key
	 * @throws IOException
	 */
	private void read(SelectionKey key) throws IOException {
		SocketChannel aChannel = (SocketChannel)key.channel();
		buffer.clear();
		int num = aChannel.read(buffer);
		if (num == -1) {
			key.cancel();
		} else if (num > 0) {
			buffer.flip();
			byte[] buf = Arrays.copyOfRange(buffer.array(), 0, num);
			messages.put(aChannel, buf);
			//将对应Channel注册写事件
			key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
			System.out.println("read from: " + aChannel.socket().getRemoteSocketAddress() + 
							   "; message: " + new String(buf));
		}
	}
	
	/**
	 * 写操作
	 * @param key
	 * @throws IOException
	 */
	private void write(SelectionKey key) throws IOException {
		SocketChannel aChannel = (SocketChannel)key.channel();
		byte[] buf = messages.get(aChannel);
		if (buf != null) {
			messages.remove(aChannel);
			key.interestOps(SelectionKey.OP_READ);
			buffer.clear();
			buffer.put(buf);
			buffer.flip();
			aChannel.write(buffer);
			System.out.println("write to: " + aChannel.socket().getRemoteSocketAddress() + 
							   "; message: " + new String(buf));
		}
	}
	
	public static void main(String[] args) throws Exception {
		EchoServer server = new EchoServer(InetAddress.getLocalHost(), 8080);
		EchoClient.threadStart(server);
	}
}

 

EchoClient.java

 

package com.iteye.finux.echo;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * @author zhu
 *
 */
public class EchoClient implements Runnable {
	private int port;
	private InetAddress host;
	private SocketChannel channel;
	private Selector selector;
	private ByteBuffer buffer = ByteBuffer.allocate(1024);
	private LinkedList<byte[]> messages = new LinkedList<byte[]>();
	
	public EchoClient(InetAddress host, int port) throws Exception {
		this.host = host;
		this.port = port;
		channel = SocketChannel.open();
		channel.configureBlocking(false);
		selector = Selector.open();
	}
	
	@Override
	public void run() {
		try {
			channel.connect(new InetSocketAddress(host, port));
			channel.register(selector, SelectionKey.OP_CONNECT);
			while (true) {
				synchronized (messages) {
					//检查队列是否有可写的数据
					if (!messages.isEmpty()) {
						SelectionKey key = channel.keyFor(selector);
						key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
					}
				}
				int count = selector.select();
				if (count > 0) {
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while (iterator.hasNext()) {
						SelectionKey key = iterator.next();
						iterator.remove();
						if (!key.isValid()) {
							continue;
						}
						
						if (key.isConnectable()) {
							channel.finishConnect();
							channel.register(selector, SelectionKey.OP_READ);
						} else if (key.isWritable()) {
							write(key);
						} else if (key.isReadable()) {
							read(key);
						}
					}
				}
			}
		} catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	
	/**
	 * 向服务端发送数据
	 * @param msg
	 */
	public void send(byte[] msg) {
		synchronized(messages) {
			messages.addLast(msg);
			//将阻塞中的select调用直接返回
			selector.wakeup();
		}
	}

	/**
	 * 写操作
	 * @param key
	 * @throws IOException
	 */
	private void write(SelectionKey key) throws IOException {
		SocketChannel aChannel = (SocketChannel)key.channel();
		synchronized(messages) {
			if (!messages.isEmpty()) {
				byte[] buf = messages.getFirst();
				messages.removeFirst();
				buffer.clear();
				buffer.put(buf);
				buffer.flip();
				aChannel.write(buffer);
				key.interestOps(SelectionKey.OP_READ);
				System.out.println("write to: " + aChannel.socket().getRemoteSocketAddress() + 
								   "; message: " + new String(buf));
			}
		}
	}
	
	/**
	 * 读操作
	 * @param key
	 * @throws IOException
	 */
	private void read(SelectionKey key) throws IOException {
		SocketChannel aChannel = (SocketChannel)key.channel();
		buffer.clear();
		int len = aChannel.read(buffer);
		if (len > 0) {
			byte[] buf = Arrays.copyOfRange(buffer.array(), 0, len);
			System.out.println("read from: " + aChannel.socket().getRemoteSocketAddress() + 
							   "; message: " + new String(buf));
		}
	}
	
	static void threadStart(Runnable runnable) {
		Thread thread = new Thread(runnable);
		thread.setName(runnable.getClass().getSimpleName());
		thread.start();
	}
	
	public static void main(String[] args) throws Exception {
		EchoClient client = new EchoClient(InetAddress.getLocalHost(), 8080);
		threadStart(client);
		CommandReader reader = new CommandReader(client);
		threadStart(reader);
	}
}

/**
 * 标准输入读取数据
 * @author zhu
 *
 */
class CommandReader implements Runnable {
	private EchoClient client;
	private byte[] buffer = new byte[1024];
	
	public CommandReader(EchoClient client) {
		this.client = client;
	}
	
	/**
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		try {
			while (true) {
				int len = System.in.read(buffer);
				if (len == -1) {
					break;
				} else if (len > 0) {
					byte[] buf = Arrays.copyOfRange(buffer, 0, len);
					client.send(buf);
				}
			}
		} catch(IOException ex) {
			ex.printStackTrace();
		}
	}
}
0
2
分享到:
评论
1 楼 albrich 2012-01-17  
不说话,不评论

相关推荐

    采用NIO实现一个Socket服务器

    本篇将基于给定的标题“采用NIO实现一个Socket服务器”来详细阐述如何使用NIO进行Socket服务端的开发。 首先,理解NIO的核心概念: 1. **通道(Channel)**:通道是连接到I/O设备的途径,可以读取或写入数据。常见的...

    使用UDP实现Echo服务.rar_Echo Echo_java udp

    在本教程中,我们将详细讨论如何使用Java编程语言实现一个基于UDP(User Datagram Protocol)的Echo服务。 UDP是传输层的一个无连接协议,与TCP相比,它不提供诸如确认、流量控制或重传等机制。这意味着UDP通信更轻...

    NIO实现网络通信,直接就能跑

    本示例通过两个类——EchoServer和EchoClient,展示了如何使用NIO实现基于TCP/IP协议的网络通信。 首先,我们来看`EchoServer`。这个类通常扮演服务端的角色,监听指定端口并接收客户端连接。在Java NIO中,服务器...

    ServerBootstrap实现nio.rar_NIO_ServerBootstrap_heart8w9_java nio

    - 在"java nio实现简单的回射服务器.java" 文件中,可能会展示如何创建一个回射服务器,它简单地将接收到的数据原封不动地返回给客户端。这有助于测试网络连接和数据传输的有效性。 6. **ServerBootstrap实现nio....

    java-nio.rar_java nio_nio 对象实例化

    总结来说,这个压缩包的内容可能涵盖了如何在Java NIO中实例化和使用通道、缓冲区、选择器,以及如何实现一个简单的多线程服务器,利用选择器来监听和处理来自多个客户端的非阻塞I/O请求。这些内容对于理解和使用...

    NIO与传统IO代码区别实例

    相比之下,NIO服务器的实现方式会有所不同,它使用选择器来管理多个连接,并且只用一个线程来处理所有连接。不过,由于这个示例的压缩包中并未包含NIO服务器的代码,因此无法提供具体的NIO代码示例。但你可以查阅...

    java io 与java nio区别

    在给定的部分代码示例中,可以看到一个简单的Java IO Echo Server实现。这个例子展示了如何使用传统的Java IO来实现一个服务器端的应用程序,它可以接收客户端发送的消息,并将接收到的信息原样返回给客户端。这里...

    《Netty实战》中的 echo 代码-netty-echo.zip

    在"echo"代码示例中,Netty展示了如何实现一个简单的回显服务器,该服务器接收到客户端发送的数据后,会原封不动地将数据返回给客户端。这是一个基础但非常重要的概念,它帮助我们理解网络通信的基本原理,并为构建...

    小型Web服务器实现

    - **性能优化**:例如使用NIO(非阻塞I/O)提高服务器处理能力,或者实现连接池管理客户端连接。 - **日志记录**:用于追踪和诊断服务器的运行情况。 通过分析这些文件,我们可以学习到如何从零开始构建一个简单的...

    Java Socket编程实例(四)- NIO TCP实践

    通过以上分析,我们可以看到Java NIO在TCP编程中的强大之处,以及如何通过`EchoProtocol`接口和`TCPEchoSelectorProtocol`类实现一个简单的回显服务器。在实际应用中,这种模型可以扩展到更复杂的网络服务,例如聊天...

    Netty 框架学习 —— 第一个 Netty 应用(csdn)————程序.pdf

    在本篇关于“Netty框架学习——第一个Netty应用”的文章中,我们将深入理解如何使用Netty构建一个简单的Echo服务器和客户端。Netty是一个高性能、异步事件驱动的网络应用程序框架,广泛应用于Java领域的服务器开发。...

    Netty4EchoDemo

    Netty4EchoDemo是一个基于Netty 4框架实现的简单回显客户端(echo client)和服务器(echo server)示例。这个项目适用于那些想要学习如何使用Netty进行网络编程的开发者,尤其是对Java NIO(非阻塞I/O)感兴趣的...

    Java NIO深入分析

    真正的NIO实现会使用`ByteBuffer`和`SocketChannel`的read/write方法进行数据交换。 **总结**: Java NIO为开发者提供了更灵活的I/O操作方式,特别是对于需要处理大量并发连接的网络应用,如聊天服务器、大型游戏...

    基于Socket的简单聊天室

    在实际项目中,我们还可以考虑优化和扩展,例如引入线程池来管理客户端连接,使用NIO(非阻塞I/O)提高性能,或者增加用户身份验证、消息加密等功能,提升聊天室的安全性和用户体验。 总的来说,通过这个基于Socket...

    java多线程Socket简单实现

    Java多线程Socket实现是网络编程中的重要概念,它结合了Java的并发处理能力和Socket通信技术,用于构建...同时,为了提高性能,可以使用NIO(非阻塞I/O)或者异步I/O(AIO)进行优化,但这些技术超出了本次讨论的范围。

    Java Socket编程实例(五)- NIO UDP实践

    本文将深入探讨如何使用NIO与UDP结合,实现一个简单的回显服务器,即UDPEchoSelectorProtocol。 首先,我们来看一下`EchoProtocol`接口。这个接口定义了处理Socket通道中接受、读取和写入操作的方法。`handleAccept...

    Netty学习笔记_Springboot实现自定义协议.docx

    在本文中,我们将使用Springboot框架来实现一个简单的服务端和客户端程序,并使用Netty框架来处理网络通信。 首先,我们需要添加Netty依赖项到我们的Springboot项目中。我们可以在pom.xml文件中添加以下依赖项: `...

    java文件传输[归类].pdf

    - 使用Java NIO的`ServerSocketChannel`和`SocketChannel`来处理服务器和客户端的连接,`Selector`和`SelectionKey`用于实现非阻塞特性,确保高效率的并发处理。 - `Buffer`类作为数据的临时存储,`FileChannel`则...

    服务端基于MINA2的UDP双向通信Demo演示(MINA2服务端)

    综上,这个示例代码应该包含了如何使用MINA2构建一个基于UDP的Echo服务器,以及如何在MINA2框架下实现双向通信的详细步骤。通过学习和分析这段代码,开发者可以更好地理解和应用MINA2框架,特别是在UDP通信场景中。

    netty的入门经典例子的使用

    在学习 Netty 的过程中,通常会从创建一个简单的 Echo 客户端和服务器开始。Echo 服务器会接收客户端发送的数据,然后原样返回。这个例子能帮助理解 Channel、EventLoop、Pipeline 和 Handler 的工作原理。 压缩包...

Global site tag (gtag.js) - Google Analytics