JAVANIO在Socket 通讯中的应用
1 引言
用Java平台编写Socket(套接字)系统,因为输入输出都必须同步。这样,对于多客户端/ 服务器模式,不得不
使用多线程. 即为每个连接的客户都分配一个线程来处理输入输出,其线程与客户机之比几乎为1∶1,所以易受
到大量线程开销的影响,结果既导致了性能问题又缺乏可伸缩性。为解决这个问题,java平台的制订者引入了非
阻塞I/ O机制。
2 以前的Socket 编程
以前的Socket 编程从服务器端套接字开始,下面我们看一个典型的C/ S系统中服务器端的设计:
创建新的ServerSocket :
ServerSocket s=newServerSocket() ;
接着,接受传入调用。调用accept()完成接入:
Socket conn=s. accept() ; / / 程序在此阻塞,直到服务器接受了一个客户机请求一旦建立连接服务器开始与
客户端进行数据流交换。
while (true) {
Socket socket ;
socket = s. accept() ; / / 取得客户请求,如果没有线程在此处阻塞
printStreamos = newPrintStream(newBufferedOutputStream(socket. getOutputStream())) ;
BufferedReader is = newBufferedReader(newInputStreamReader(clientSocket. getInputStream())) ;
/ / 创建输入输出流,直到缓冲区满才成批的读取或发送数据
. . . . . . .
}
在此模式中,线程将在读或写时阻塞,一直到读或写操作彻底完成。如果在读的时候,数据尚未完全到达套
接字,则线程将在读操作上阻塞,一直到数据可用。我们一般是大量的使用线程来处理阻塞问题,但这个解决办
法会产生负效应:线程开销同时影响性能和可伸缩性,为此java的制订者推出了异步通讯机制来解决这些问题。
3 NIO结构
NIO(NewI/ O) 设计的原理是反应器设计模式(Reactor pattern) 。分布式系统中的服务器应用程序必须处理
收稿日期:2003204218
第18卷第3期
2003年9月
成 都 信 息 工 程 学 院 学 报
JOURNALOFCHENGDUUNIVERSITYOFINFORMATIONTECHNOLOGY
Vol. 18No. 3
Sep. 2003
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
多个向它们发送服务请求的客户机。然而,在调用特定的服务之前,服务器应用程序必须将每个传入请求多路分
用并分派到各自相应的服务提供者。反应器模式正好适用于这一功能,它允许事件驱动应用程序将服务请求多
路分用并进行分派,然后,这些服务请求被并发地从一个或多个客户机传送到应用程序。NIO就是根据此机理设
计而成。
NIO结构如图1所示:
图1 非阻塞Socket 结构
NIO实现了异步输入输出,这是指在进行输入输出处理时,它不必等到输入输出处理完毕才返回,就实现了
非阻塞。在服务器端,ServerSocketChannel 通过静态函数open()返回一个ServerSocketChannel 实例。然后调用
ServerSocketChannel. socket(). bind()绑定到服务器某端口,并调用register(Selector sel , SelectionKey.OP- ACCEPT)注
册OP- ACCEPT(接受连接)事件到一个选择器中(ServerSocketChannel 只可以注册OP- ACCEPT事件) 。当有客户
请求连接时,选择器就会通知该通道有客户连接请求,就可以进行相应的输入输出控制了;在客户端,客户端通道
实例注册自己感兴趣的事件后(可以是OP- CONNECT,OP- READ,OP- WRITE的组合) ,调用SocketChannel. connect
(InetSocketAddress )连接服务器然后进行相应处理。这里的连接是异步的,即不会等到服务器有相应立即返回而
继续执行后面的代码。
4 NIO的实现
4.1 创建NIO的连接
为了实现基础的非阻塞套接字读和写操作,首先我们要引入NIO包,接着建立连接。限于篇幅,我们仅列出
关键部分代码,客户端建立与服务器的连接:
Stringhost = 192.168.0.1;
InetSocketAddress socketAddress = newInetSocketAddress(host , 80) ;
SocketChannel channel = SocketChannel.open() ;/ / SocketChannel 执行实际读写操作
channel. connect(socketAddress) ;
channel. configureBlockingMethod(false) ;/ / 使通道成为非阻塞的
在非阻塞模式中,线程将读取已经可用的数据(不论多少) ,然后返回执行其它任务。如果将真(true)传递给
configureBlockingMethod() ,则通道的行为将与在Socket 上进行阻塞读或写时的行为完全相同。所不同的是这些阻
塞读和写可以被其它线程中断。
NIO中实现非阻塞I/ O数据的读取主要靠Selector 类的工作。
4.2 Selector的工作
在反应器模式情形中,Selector 类对多个SelectableChannels 的事件进行多路复用。每个Channel 向Selector 注
册事件。当事件从客户机处到来时,Selector 将它们多路分用并将这些事件分派到相应的Channel。
创建Selector 最简单的办法是使用open() 方法:
Selector selector = Selector.open() ;
9 5 2 第3期 王洁:JAVANIO在Socket 通讯中的应用
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
4.3 接受客户端的连接
要为每个客户机请求提供服务的Channel 创建一个连接。下面的代码创建称为Server 的ServerSocketChannel
并将它绑定到本地端口:
ServerSocketChannel serverChannel = ServerSocketChannel.open() ;
serverChannel. configureBlocking(false) ;
InetAddress ia = InetAddress. getLocalHost() ;
InetSocketAddress isa = newInetSocketAddress(ia, port ) ;
serverChannel. socket(). bind(isa) ;
每个要为客户机请求提供服务的Channel 都必须接着将自己向Selector 注册。Channel 应根据它将处理的事
件进行注册。接受传入连接的Channel 应这样注册:
SelectionKeyacceptKey = channel. register( selector,SelectionKey.OP- ACCEPT) ;
Channel 向Selector 的注册用SelectionKey对象表示。当Channel 被关闭,Selector 被关闭,调用Key的cancel()
时Key失效。
Selector 在select() 调用时阻塞。接着,它开始等待,直到建立了一个新的连接,或者另一个线程将它唤醒,或
者另一个线程将原来的阻塞线程中断。
4.4 服务器的工作
Server 是那个将自己向Selector 注册以接受所有传入连接的ServerSocketChannel :SelectionKeyacceptKey =
serverChannel. register(sel , SelectionKey.OP- ACCEPT) ;
while (acceptKey. selector(). select() > 0){
Server 被注册后,根据每个关键字(key)的类型以迭代方式对一组关键字进行处理。一个关键字被处理完成
后,就都被从就绪关键字(readykeys)列表中除去:
Set readyKeys = sel. selectedKeys() ;
Iterator it = readyKeys.iterator() ;
while (it. hasNext())
{
SelectionKeykey = (SelectionKey)it. next() ;
it. remove() ;
. . . .
}
如果关键字是可接受(acceptable)的,则接受连接,注册通道,以接受更多的事件(例如:读或写操作) 。如果关
键字是可读的(readable)或可写的(writable) ,则服务器会指示它已经就绪于读写本端数据:
SocketChannel socket ;
if (key.isAcceptable()) {
ServerSocketChannel schannel = (ServerSocketChannel) key. channel() ;
socket = (SocketChannel) schannel. accept() ;
socket. configureBlocking(false) ;
SelectionKeyakey = socket. register(sel ,SelectionKey.OP- READ| SelectionKey.OP- WRITE) ;
}
if (key.isReadable()) {
Stringtempstr = readline(key) ;
if (tempstr.length() > 0) {
0 6 2 成 都 信 息 工 程 学 院 学 报 第18卷
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
writeMessage(socket ,tempstr) ;
}
}
if (key.isWritable()) {
Stringtempstr = readline(key) ;
socket = (SocketChannel)key. channel() ;
if (result.length() > 0) {
writeline(socket ,tempstr) ;
}
}
5 结束语
NIO可以很好的解决以前Socket 编程中出现的问题,主要表现在有两方面:线程不再在读或写时阻塞,以及
Selector 能够处理多个连接,从而大幅降低了服务器应用程序开销。
分享到:
相关推荐
### JAVANIO在Socket通讯中的应用 #### 引言 在Java开发中,网络通信是常见需求之一,其中Socket编程是最基础也是最重要的技术之一。然而,在传统的Java Socket编程中,由于采用的是阻塞I/O模型,即所有的读写操作...
Java Socket 开发即时通讯服务器是构建实时通信系统的关键技术之一,尤其在企业级应用、在线游戏、聊天室等场景中广泛应用。本篇将深入探讨Java Socket在即时通讯服务器开发中的核心概念、步骤以及关键技术。 首先...
通过阅读和理解这些代码,你可以掌握如何在实际项目中应用Spring Boot进行Socket通讯,以及处理特定协议的技巧。 总之,将卫通星GPS定位器GT06与Java Spring Boot应用对接,涉及到了网络编程、协议解析、异步处理等...
在这个教程中,我们将深入理解Java Socket的基本概念,并通过一个实际的示例来阐述如何在Tomcat服务器上部署和运行一个简单的Socket即时通讯应用。 首先,Socket在Java中的主要类包括`java.net.Socket`(客户端)和...
8. **安全性**:在实际应用中,可能会涉及到SSL/TLS安全套接字,用于加密数据传输,保护信息安全。 9. **心跳机制**:在长连接中,为了检测连接是否依然活跃,常需要实现心跳机制,定期发送确认信息。 10. **网络...
在IT行业中,网络通信是软件开发中的重要组成部分,特别是在分布式系统和互联网应用中。本话题主要探讨了两种常用编程语言——Java和C#之间如何利用Socket进行通信。Socket是网络编程的基本接口,允许应用程序通过...
在这个"java_chat_program.rar"压缩包中,我们有一个基于Java Socket实现的简单即时通讯程序,用户既可以注册登录,也可以以游客身份使用,这为我们提供了一个理解Socket通信机制和实时聊天应用开发的实例。...
这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化Java应用程序的性能至关重要。 **1. 基于Java的BIO(Blocking I/O)** BIO是Java早期的I/O模型,它是最简单也是最直接的。在BIO模型中,每个...
Socket编程在Java中是网络通信的基础,主要用于实现客户端与服务器之间的连接。QQ作为一个即时通讯软件,其背后的原理也离不开Socket通信。在这个项目中,我们将学习如何利用Java的Socket API来模拟实现一个简单的QQ...
本压缩包中的"socket异步通讯实例"是一个具体的应用示例,旨在解释Java Socket如何实现异步通信。 首先,我们要了解什么是Socket。Socket在计算机网络中扮演着桥梁的角色,它连接了两台机器上的应用程序,允许它们...
在这个项目中,开发者将学习如何利用Java的Socket类来创建客户端和服务器端的连接,实现实时的数据传输,构建一个简单的聊天环境。 【描述】"TCP/IP通信,使用Socket编程,java即时聊天室" 揭示了项目的重点在于...
- 这种简单的图片传输机制适用于小型应用,如文件共享服务、即时通讯应用中的图片发送等。 - 对于大规模的、高性能的图片传输,可能需要更复杂的缓存策略、多线程处理和错误恢复机制。 通过学习和实践"Java ...
本篇文章将深入探讨Java Socket编程的基本概念、核心类、以及实际应用中的关键点。 一、Socket基本概念 Socket,通常被称为套接字,是进程间通信的一种方式,它允许不同计算机上的进程通过网络进行通信。在网络编程...
本文将深入探讨"异步和多线程socket通讯"这一主题,基于提供的描述和标签,我们将讨论如何利用多线程和异步机制来提升socket通信的效率和响应性。 首先,Socket是一种在应用程序与网络服务之间建立连接的接口,它...
Socket通讯框架是网络编程中的重要组成部分...以上就是Socket通讯框架的基本介绍,其核心在于通过TCP/IP协议实现进程间的可靠通信,而实际应用中往往结合多线程、并发处理、安全通信等技术,构建出高效稳定的网络服务。
本研究主要探讨了Java Socket在基础性应用中的原理、方法及实践,旨在帮助开发者深入理解如何利用Java Socket进行网络数据传输。 一、Java Socket概述 Java Socket是Java提供的网络通信桥梁,它允许两台计算机通过...
Java网络编程中的Socket是连接应用程序和网络协议的重要接口,它允许两个网络应用程序通过TCP/IP通信。在Java中,Socket类代表了客户端与服务器之间的连接,ServerSocket类则用于服务器端,监听并接受客户端的连接...
在实际应用中,为了处理并发连接,服务器通常会使用多线程或异步I/O模型,如Java的NIO(非阻塞I/O)或Python的asyncio库。 在Socket编程中,还需要注意以下关键知识点: - **TCP与UDP**:Socket可以基于TCP(传输...
在这个压缩包中,包含了“Java_NIO基础视频教程”和“MINA视频教程”,你可以通过观看这些教程,了解和学习NIO和Mina的基本用法。同时,“Netty快速入门视频(52im.net).txt”虽然不是直接与Mina相关的,但Netty也是...