nio java tcp_java分布式开发TCP/IP NIO无阻塞 Socket((基于消息方式实现系统间的通信) )...

在java中可以基于java.nio.channels中的Channel和Selector的相关类来实现TCP/IP+NIO方式的系统间通信。

用于系统间通信依靠SocketChannel和ServerSocketChannel,SocketChannel用于建立连接,监听事件及操作读写,ServerSocketChannel用于监听端口及监听连接事件,可通过Selector来获取是否有要处理的事件。

服务端java代码:

package com.java.distributed.message.tcpip;

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.nio.charset.Charset;

public class NIOServer {

/**

* @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

int port =7889;

//打开选择器

Selector selector=Selector.open();

//打开服务器套接字通道

ServerSocketChannel ssc=ServerSocketChannel.open();

//检索与此通道关联的服务器套接字

ServerSocket serverSocket=ssc.socket();

//将 ServerSocket 绑定到特定地址(IP 地址和端口号)

serverSocket.bind(new InetSocketAddress(port));

System.out.println("server listen on port:"+port);

//调整通道的阻塞模式

ssc.configureBlocking(false);

//向给定的选择器注册此通道,返回一个选择键。SelectionKey.OP_ACCEPT--用于套接字接受操作的操作集位

ssc.register(selector, SelectionKey.OP_ACCEPT);

while(true){

//timeout:为正,则在等待某个通道准备就绪时最多阻塞 timeout 毫秒;如果为零,则无限期地阻塞;必须为非负数

int nKeys=selector.select(1000);

if(nKeys>0){

for(SelectionKey key:selector.selectedKeys()){

/*测试此键的通道是否已准备好接受新的套接字连接--

* 如果此键的通道不支持套接字接受操作,则此方法始终返回 false

* */

if(key.isAcceptable()){

ServerSocketChannel server=(ServerSocketChannel) key.channel();

SocketChannel sc=server.accept();

if(sc==null){

continue;

}

sc.configureBlocking(false);

sc.register(selector, SelectionKey.OP_READ);

}else if(key.isReadable()){

//分配一个新的字节缓冲区

ByteBuffer buffer=ByteBuffer.allocate(1024);

SocketChannel sc=(SocketChannel) key.channel();

int readBytes=0;

String message=null;

try{

int ret;

try{

while((ret=sc.read(buffer))>0){

readBytes +=ret;

}

}catch(Exception e ){

readBytes=0;

//ignore

}finally{

//反转此缓冲区。首先对当前位置设置限制,然后将该位置设置为零

buffer.flip();

}

if(readBytes>0){

message=Charset.forName("UTF-8").decode(buffer).toString();

buffer=null;

}

}finally{

if(buffer!=null)

buffer.clear();

}

if(readBytes>0){

System.out.println("message from client:"+message);

if("quit".equalsIgnoreCase(message.trim())){

sc.close();

selector.close();

System.out.println("Server has been shutdown!");

System.exit(0);

}

String outMessage="server response:"+message;

sc.write(Charset.forName("UTF-8").encode(outMessage));

}

}

}

selector.selectedKeys().clear();

}

}

}

}

客户端java代码:

package com.java.distributed.message.tcpip;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.InetSocketAddress;

import java.net.SocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.SocketChannel;

import java.nio.charset.Charset;

public class NIOClient {

/**

* @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

int port =7889;

SocketChannel channel=SocketChannel.open();

channel.configureBlocking(false);

SocketAddress target=new InetSocketAddress("127.0.0.1",port);

channel.connect(target);

Selector selector=Selector.open();

//用于套接字连接操作的操作集位

channel.register(selector, SelectionKey.OP_CONNECT);

BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));

while(true){

if(channel.isConnected()){

String command=systemIn.readLine();

channel.write(Charset.forName("UTF-8").encode(command));

if(command==null||"quit".equalsIgnoreCase(command.trim())){

systemIn.close();

channel.close();

selector.close();

System.out.println("Client quit !");

System.exit(0);

}

}

int nKeys=selector.select(1000);

if(nKeys>0){

for(SelectionKey key:selector.selectedKeys()){

if(key.isConnectable()){

SocketChannel sc=(SocketChannel) key.channel();

sc.configureBlocking(false);

sc.register(selector, SelectionKey.OP_READ);

sc.finishConnect();

}else if(key.isReadable()){

ByteBuffer buffer=ByteBuffer.allocate(1024);

SocketChannel sc=(SocketChannel) key.channel();

int readBytes=0;

try{

int ret=0;

try{

while((ret=sc.read(buffer))>0){

readBytes+=ret;

}

}finally{

buffer.flip();

}

if (readBytes > 0) {

System.out.println(Charset.forName("UTF-8")

.decode(buffer).toString());

buffer = null;

}

}finally {

if (buffer != null) {

buffer.clear();

}

}

}

}

selector.selectedKeys().clear();

}

}

}

}

分享到:

18e900b8666ce6f233d25ec02f95ee59.png

72dd548719f0ace4d5f9bca64e1d7715.png

2011-11-07 13:32

浏览 17850

评论

1 楼

mars914

2011-11-07

channel,Buffer,selector。Java 标准IO中基于流进行数据交互,java NIO中给出了许多Buffer,基于数据块进行操作,通过channel(通道)进行交互。Channel同时支持异步的读和写。且主要与buffer进行数据读写。

Selector也是Java NIO提供的类,能够监听网络IO中Channel的事件,检查Channel是否准备好可读/可写,以及连接(connect),accept。一个Selector可支持监听多个Channel的事件。这样NIO中可以一个线程可以支持多个请求发送。

同样,考虑客户端发送多个请求,NIO方式相比BIO可以做到不阻塞,因此客户端可以采用连接复用的方式,即每个SocketChannel在发送消息后,不用等待响应可继续发送其他消息。这样可以降低连接池带来的资源争抢问题,对系统性能有帮助。

对于服务器接受多个连接请求,通常采用的是有一个线程来监听连接事件,另一个线程来监听网络流的读写事件。

当有网络流的读写事件时,在放入一个线程池中处理。这种方式比TCP/IP+BIO的好处是在于可接受很多连接,而这些连接只有在有真正的与服务器进行(请求)交互才会创建线程进行处理。这网上被称为:一请求一连接。

当连接数不多,或者连接数很多而且连接上的请求比较频繁是,TCP/IP NIO方式不会带相比TCP/IP+BIO理论上不会有太大的优势。

综上,TCP/IP+NIO对于高访问量的系统来说,服务器端可以支撑更多的连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值