最近温习下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();
}
}
}
分享到:
相关推荐
本篇将基于给定的标题“采用NIO实现一个Socket服务器”来详细阐述如何使用NIO进行Socket服务端的开发。 首先,理解NIO的核心概念: 1. **通道(Channel)**:通道是连接到I/O设备的途径,可以读取或写入数据。常见的...
在本教程中,我们将详细讨论如何使用Java编程语言实现一个基于UDP(User Datagram Protocol)的Echo服务。 UDP是传输层的一个无连接协议,与TCP相比,它不提供诸如确认、流量控制或重传等机制。这意味着UDP通信更轻...
本示例通过两个类——EchoServer和EchoClient,展示了如何使用NIO实现基于TCP/IP协议的网络通信。 首先,我们来看`EchoServer`。这个类通常扮演服务端的角色,监听指定端口并接收客户端连接。在Java NIO中,服务器...
- 在"java nio实现简单的回射服务器.java" 文件中,可能会展示如何创建一个回射服务器,它简单地将接收到的数据原封不动地返回给客户端。这有助于测试网络连接和数据传输的有效性。 6. **ServerBootstrap实现nio....
总结来说,这个压缩包的内容可能涵盖了如何在Java NIO中实例化和使用通道、缓冲区、选择器,以及如何实现一个简单的多线程服务器,利用选择器来监听和处理来自多个客户端的非阻塞I/O请求。这些内容对于理解和使用...
相比之下,NIO服务器的实现方式会有所不同,它使用选择器来管理多个连接,并且只用一个线程来处理所有连接。不过,由于这个示例的压缩包中并未包含NIO服务器的代码,因此无法提供具体的NIO代码示例。但你可以查阅...
在给定的部分代码示例中,可以看到一个简单的Java IO Echo Server实现。这个例子展示了如何使用传统的Java IO来实现一个服务器端的应用程序,它可以接收客户端发送的消息,并将接收到的信息原样返回给客户端。这里...
在"echo"代码示例中,Netty展示了如何实现一个简单的回显服务器,该服务器接收到客户端发送的数据后,会原封不动地将数据返回给客户端。这是一个基础但非常重要的概念,它帮助我们理解网络通信的基本原理,并为构建...
- **性能优化**:例如使用NIO(非阻塞I/O)提高服务器处理能力,或者实现连接池管理客户端连接。 - **日志记录**:用于追踪和诊断服务器的运行情况。 通过分析这些文件,我们可以学习到如何从零开始构建一个简单的...
通过以上分析,我们可以看到Java NIO在TCP编程中的强大之处,以及如何通过`EchoProtocol`接口和`TCPEchoSelectorProtocol`类实现一个简单的回显服务器。在实际应用中,这种模型可以扩展到更复杂的网络服务,例如聊天...
在本篇关于“Netty框架学习——第一个Netty应用”的文章中,我们将深入理解如何使用Netty构建一个简单的Echo服务器和客户端。Netty是一个高性能、异步事件驱动的网络应用程序框架,广泛应用于Java领域的服务器开发。...
Netty4EchoDemo是一个基于Netty 4框架实现的简单回显客户端(echo client)和服务器(echo server)示例。这个项目适用于那些想要学习如何使用Netty进行网络编程的开发者,尤其是对Java NIO(非阻塞I/O)感兴趣的...
真正的NIO实现会使用`ByteBuffer`和`SocketChannel`的read/write方法进行数据交换。 **总结**: Java NIO为开发者提供了更灵活的I/O操作方式,特别是对于需要处理大量并发连接的网络应用,如聊天服务器、大型游戏...
在实际项目中,我们还可以考虑优化和扩展,例如引入线程池来管理客户端连接,使用NIO(非阻塞I/O)提高性能,或者增加用户身份验证、消息加密等功能,提升聊天室的安全性和用户体验。 总的来说,通过这个基于Socket...
Java多线程Socket实现是网络编程中的重要概念,它结合了Java的并发处理能力和Socket通信技术,用于构建...同时,为了提高性能,可以使用NIO(非阻塞I/O)或者异步I/O(AIO)进行优化,但这些技术超出了本次讨论的范围。
本文将深入探讨如何使用NIO与UDP结合,实现一个简单的回显服务器,即UDPEchoSelectorProtocol。 首先,我们来看一下`EchoProtocol`接口。这个接口定义了处理Socket通道中接受、读取和写入操作的方法。`handleAccept...
在本文中,我们将使用Springboot框架来实现一个简单的服务端和客户端程序,并使用Netty框架来处理网络通信。 首先,我们需要添加Netty依赖项到我们的Springboot项目中。我们可以在pom.xml文件中添加以下依赖项: `...
- 使用Java NIO的`ServerSocketChannel`和`SocketChannel`来处理服务器和客户端的连接,`Selector`和`SelectionKey`用于实现非阻塞特性,确保高效率的并发处理。 - `Buffer`类作为数据的临时存储,`FileChannel`则...
综上,这个示例代码应该包含了如何使用MINA2构建一个基于UDP的Echo服务器,以及如何在MINA2框架下实现双向通信的详细步骤。通过学习和分析这段代码,开发者可以更好地理解和应用MINA2框架,特别是在UDP通信场景中。
在学习 Netty 的过程中,通常会从创建一个简单的 Echo 客户端和服务器开始。Echo 服务器会接收客户端发送的数据,然后原样返回。这个例子能帮助理解 Channel、EventLoop、Pipeline 和 Handler 的工作原理。 压缩包...