本文转自:http://www.blogjava.net/jake1036/archive/2010/08/01/327703.html
作者:jake1036
1 非阻塞(Nonblocking)体系结构
在这一部分,我将从理论的角度来解释非阻塞体系的结构及其工作原理。这部“喜剧”(当然,如果你喜欢的话也可以称做戏剧)的“人物”如下:
●服务器端:接收请求的应用程序。
●客户端:向服务器端发出请求的应用程序。
●套接字通道:客户端与服务器端之间的通信通道。它能识别服务器端的IP地址和端口号。数据以Buffer中元素的形式通过套接字通道传送。
●选择器:所有非阻塞技术的主要对象。它监视着已注册的套接字通道,并序列化服务器需要应答的请求。
●关键字:选择器用来对对象的请求进行排序。每个关键字代表一个单独的客户端子请求并包含识别客户端和请求类型的信息。
2 SocketChannel 类
SocketAddress rama = new SocketAddress("localhost" , 8888) ;
利用静态工厂方法得到SocketChannel的实例。
SocketChannel client = SocketChannel.open(rama) ;
如果这是传统的套接字,那么就会寻求得到socket的输入或者输出流,利用通道,我们可以直接写入通道本身,
不是写入字节数组,而是要写入ByteBuffer对象,将此对象写入 client的read 方法。
客户端应用程序同时执行对服务器端的请求,接着选择器将其集中起来,创建关键字,然后将其发
送至服务器端。这看起来像是阻塞(Blocking)体系,因为在一定时间内只处理一个请求,但事实并非如此。
实际上,每个关键字不代表从客户端发至服务器端的整个信息流,仅仅只是一部分。我们不要忘了选择器能
分割那些被关键字标识的子请求里的数据。因此,如果有更多连续地数据发送至服务器端,那么选择器就会
创建更多的根据时间共享策略(Time-sharing policy)来进行处理的关键字。强调一下,在图一中关键字的颜色
与客户端的颜色相对应。
服务器端非阻塞(Server Nonblocking)
客户端和服务器端是两个Java应用程序。套接字通道是SocketChannel类的实例,这个类允许通过网络传送数据。
它们能被Java程序员看作是一个新的套接字。SocketChannel类被定义在java.nio.channel包中。
选择器是一个Selector类的对象。该类的每个实例均能监视更多的套接字通道,进而建立更多的连接。
当一些有意义的事发生在通道上(如客户端试图连接服务器端或进行读/写操作),选择器便会通知应用程序处理请求。
选择器会创建一个关键字,这个关键字是SelectionKey类的一个实例。每个关键字都保存着应用程序的标识及请求的类型。
其中,请求的类型可以是如下之一:
基本上,服务器端的实现是由选择器等待事件和创建关键字的无限循环组成的。根据关键字的类型,及时的执行操作。
关键字存在以下4种可能的类型。
Acceptable: 相应的客户端要求连接。
Connectable:服务器端接受连接。
Readable:服务器端可读。
Writeable:服务器端可写。
一个通用的实现非阻塞服务器的算法如下:
create SocketChannel;
create Selector
associate the SocketChannel to the Selector
for(;;) {
waiting events from the Selector;
event arrived; create keys;
for each key created by Selector {
check the type of request;
isAcceptable:
get the client SocketChannel;
associate that SocketChannel to the Selector;
record it for read/write operations
continue;
isReadable:
get the client SocketChannel;
read from the socket;
continue;
isWriteable:
get the client SocketChannel;
write on the socket;
continue;
}
}
3 下面为一个实例
(1)客户端
package cn.bupt.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import cn.bupt.constant.Default;
public class ChargenClient {
public static int DEFAULT_PORT = 8778 ;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
if(args.length == 0)
{
System.out.println("please input the port");
return ;
}
int port ;
port = DEFAULT_PORT ;
SocketAddress address = new InetSocketAddress(args[0] , port) ;
try {
SocketChannel client = SocketChannel.open(address) ;
ByteBuffer buffer = ByteBuffer.allocate(74) ;
WritableByteChannel out = Channels.newChannel(System.out) ;
while(client.read(buffer) != -1)
{
buffer.flip() ;
out.write(buffer) ;
buffer.clear() ;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(2) 服务器端
package cn.bupt.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.Iterator;
import java.util.Set;
public class ChargenServer {
public static final int DEFAULT_PORT = 8778 ;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int port ;
port = DEFAULT_PORT ;
byte[] rotation = new byte[95 * 2 ] ;
for(byte i = ' ' ; i < '~' ;i++)
{
rotation[i - ' '] = i ;
rotation[i + 95 - ' '] = i ;
}
ServerSocketChannel serverChannel = null ;
Selector selector = null;
/**
* 先建立服务器端的通道
*
*/
try {
serverChannel = ServerSocketChannel.open() ;
ServerSocket ss = serverChannel.socket() ;
InetSocketAddress address = new InetSocketAddress(port) ;
ss.bind(address) ;
serverChannel.configureBlocking(false) ;
selector = Selector.open() ;
serverChannel.register(selector, SelectionKey.OP_ACCEPT) ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true)
{
try {
selector.select() ;
} catch (IOException e) {
e.printStackTrace();
}
Set readyKeys = selector.selectedKeys() ;
Iterator iter = readyKeys.iterator() ;
while(iter.hasNext())
{
SelectionKey key = (SelectionKey) iter.next() ;
iter.remove() ;
if(key.isAcceptable())
{
ServerSocketChannel server = (ServerSocketChannel) key.channel() ;
try {
SocketChannel client = server.accept() ;
System.out.println("Accept connection from " + client) ;
client.configureBlocking(false) ;
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE) ;
ByteBuffer buffer = ByteBuffer.allocate(74) ;
buffer.put(rotation , 0 , 72) ;
buffer.put((byte)'\r') ;
buffer.put((byte)'\n') ;
buffer.flip() ;
key2.attach(buffer) ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
if(key.isWritable())
{
/**
* 建立客户端通道
*
*/
SocketChannel client = (SocketChannel)key.channel() ;
ByteBuffer buffer = (ByteBuffer) key.attachment() ;
if(!buffer.hasRemaining())
{
buffer.rewind() ;
int first = buffer.get() ;
buffer.rewind() ;
int position = first - ' ' + 1 ;
buffer.put(rotation , position , 72) ;
buffer.put((byte) '\r') ;
buffer.put((byte) '\n');
buffer.flip() ;
}
try {
client.write(buffer) ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
key.cancel() ;
try {
key.channel().close() ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
分享到:
相关推荐
11. **NIO(非阻塞I/O)** - **java.nio包**:引入了通道(Channel)和缓冲区(Buffer)的概念,提供异步I/O操作。 - **Selector**:用于多路复用,监控多个通道的事件。 12. **工具类** - **PrintStream**:...
在NIO模型中,`ServerSocketChannel`和`SocketChannel`等类被用来替代传统的`Socket`,它们支持非阻塞模式的I/O操作。下面的代码示例展示了如何使用非阻塞模式接收并处理客户端请求: 1. **创建Selector对象**:`...
在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O模型**:在传统的Java IO编程中,当我们调用`read()`或`write()`方法时,...
- NIO(非阻塞I/O):讲解Java的非阻塞I/O模型,如Selector和Channel,以及其在高并发环境中的优势。 通过这本书,读者将能够全面了解Java在TCP/IP网络编程中的应用,无论是构建简单的通信应用,还是开发复杂的Web...
通过示例演示了如何使用Socket和ServerSocket建立基本的网络通信方式,涵盖了基于TCP的阻塞I/O、非阻塞I/O以及UDP广播/多播的内容。同时讨论了高级话题中的多路复用技术和NIO的优势,并详细解析了Socket在聊天室构建...
从简单的Socket通信到复杂的多线程和非阻塞I/O处理,Java为我们提供了丰富的工具和支持。此外,在实际应用中还需要考虑网络安全性和性能优化等问题,这些都是网络编程中不可或缺的部分。希望通过对这些知识点的学习...
Java NIO(New IO)提供了一套非阻塞I/O接口,如`Selector`,它可以在没有数据可读时检查多个通道的状态,而不是在一个通道上等待,从而提高了多路复用的效率。然而,非阻塞I/O需要更复杂的编程模式来处理可能的“空...
Java 2还包括丰富的API,如Swing库用于构建图形用户界面(GUI),I/O和NIO(非阻塞I/O)库用于高效的数据传输,以及XML处理API等。这些高级主题会帮助开发者构建功能丰富的应用程序。 最后,本书可能还会涉及Java的...
Java Socket详解:深入理解网络传输 Java Socket编程是Java网络编程的基础,它允许两台计算机通过网络进行数据交换。在Java中,Socket是实现客户端-服务器通信的关键接口,位于`java.net`包中,提供了简单易用的API...
### Java Socket 图片传输知识点详解 #### 一、TCP协议简介 传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在互联网的应用中,TCP协议提供了一种...
此外,还可以使用NIO(非阻塞I/O)或异步Socket API来提高性能和并发性。 总之,Java中的Socket编程涉及到TCP/IP通信的基础,理解和掌握Socket编程对于开发网络应用程序至关重要。通过创建Socket和ServerSocket对象...
Java NIO(非阻塞I/O)Socket编程是此工具的核心技术之一。传统的Java Socket编程是基于阻塞I/O,当一个线程进行读写操作时,若数据未准备好,线程会被阻塞。而NIO引入了选择器和通道的概念,允许多个通道的并发读写...
- **非阻塞I/O(Non-blocking I/O)**:Java NIO(New I/O)提供了一种选择,允许在数据未准备好时返回,避免阻塞。 - **多路复用I/O(Multiplexing I/O)**:Java NIO的Selector机制,允许多个套接字的事件被单一...
7. **Java I/O与NIO**:从传统的I/O模型到非阻塞I/O模型(New IO,即NIO),包括Channels、Buffers和Selectors的使用。 8. **反射API**:Java反射允许在运行时检查类、接口、字段和方法的信息,动态创建对象并调用...
- **四种模型**: 阻塞I/O、非阻塞I/O、多路复用I/O(如NIO中的Selector机制)、异步I/O。 - **NIO (New IO)**: - `Selector`: 用于监听多个通道的就绪状态。 - `Channel`: 数据传输的通道。 - `Buffer`: 数据...
在《Scalable IO in Java》这篇文章中,作者Doug Lea深入探讨了如何利用Java NIO(非阻塞I/O)技术实现可扩展的网络服务。随着互联网应用和服务的日益增长,对服务器端I/O处理能力的需求也在不断提高。传统的同步...
### Java Socket编程入门知识点详解 #### 一、Java Socket编程基础概述 1. **平台无关性**:Java...随着实践经验的积累,读者可以进一步探索更高级的主题和技术,如多线程、非阻塞I/O以及网络编程中的安全性问题等。
总之,非阻塞式通信是Java网络编程中的一个重要概念,它改变了传统阻塞式I/O的局限,为开发者提供了更高效、更灵活的网络编程模型。通过理解和掌握`java.nio`包中的关键类与接口,可以有效提升Java网络应用的性能和...