java nio socket通信简单入门示例

      

      基本的Java套接字对于小规模系统可以很好地运行,但当涉及到要同时处理上千个客户端的服务器时,可能就会产生一些问题.由于创建、维护和切换线程需要的系统开销,一客户一线程方式在系统扩展性方面受到了限制。使用线程池可以节省那种系统开销,同时允许实现者利用并行硬件的优势。但对于连接生存期比较长的协议来说,线程池的大小仍然限制了系统可以同时处理的客户端数量。考虑一个在客户端之间传递消息的即时消息服务器(Instant Messaging)。客户端必须不停地连接服务器以接收即时消息,因此线程池的大小限制了系统可以同时服务的客户端总数。如果增加线程池的大小,将带来更多的线程处理开销,而不能提升系统的性能,因为在大部分的时间里客户端是处于闲置状态的。


      如果这就是所有问题,可能NIO还不是必要的。不幸的是,在使用线程的扩展性方面还涉及一些更加难以把握的挑战。其中一个挑战就是程序员几乎不能对什么时候哪个线程将获得服务进行控制。你可以设置一个线程实例的优先级(priority)(高优先级的线程相对于低优先级的线程有优先权),但是这个优先级只是一种"建议"--下一个选择执行的线程完全取决于具体实现。因此,如果程序员想要保证某些连接优先获得服务,或想要指定一定的服务顺序,线程可能就很难做到。


    我们需要一种方法来一次轮询一组客户端,以查找哪个客户端需要服务。这正是NIO中将要介绍的Selector和Channel抽象的关键点。一个Channel实例代表了一个"可轮询的(pollable)"I/O目标,如套接字(或一个文件、设备等)。Channel能够注册一个Selector类的实例。Selector的select()方法允许你询问"在一组信道中,哪一个当前需要服务(即,被接受,读或写)?"大量的细节将在后文中介绍,但这就是使用Selector和Channel的基本动机。这两个类都包含在java.nio.channels包中。

摘自《java tcp/ip socket编程》

下面自己实现了一个单线程的通信。

server:

import java.io.BufferedReader;
import java.io.InputStreamReader;
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.Iterator;

/*
 * Server
 */
public class NioTcpServer1
{
	public static void main(String[] args) throws Exception
	{
		//open ServerSocketChannel
		ServerSocketChannel server = ServerSocketChannel.open();
		// bind port
		server.bind(new InetSocketAddress(10000));
		//set noblocking
		server.configureBlocking(false);
		//open selector
		Selector selector = Selector.open();
		//register accept event
		server.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("=======server start=======");
		while (true)
		{
			while (selector.select() > 0)
			{
				Iterator<SelectionKey> iter = selector.selectedKeys()
						.iterator();
				while (iter.hasNext())
				{
					SelectionKey key = iter.next();
					//avoid duplication
					iter.remove();
					//accept
					if (key.isAcceptable())
					{
						SocketChannel channel = ((ServerSocketChannel) (key
								.channel())).accept();
						channel.configureBlocking(false);
						//register read and write
						channel.register(selector, SelectionKey.OP_READ
								| SelectionKey.OP_WRITE);
						System.out.println("server accept client");
						 channel.write(ByteBuffer.wrap("server already \r\n".getBytes()));
					}
					//read
					if (key.isReadable())
					{
					
						SocketChannel channel = (SocketChannel) key.channel();
						ByteBuffer buffer = ByteBuffer.allocate(20);
						int len = 0;
						while (0 != (len = channel.read(buffer)))
						{

							System.out.println(new String(buffer.array(), 0,
									len));
							buffer.clear();
						}
					}
					//write
					if (key.isWritable())
					{
						System.out.print("server#: ");
						BufferedReader read = new BufferedReader(
								new InputStreamReader(System.in));

						String line = read.readLine();

						SocketChannel channel = (SocketChannel) key.channel();
						//send some data
						channel.write(ByteBuffer.wrap((line + "\r\n").getBytes()));
					}
					//set network delay
					  Thread.sleep(2000);
				}
			}
		}

	}
}


client:

import java.io.BufferedReader;
import java.io.InputStreamReader;
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.Iterator;
/*
 * Client
 */
public class NioTcpClient1
{
	public static void main(String[] args)throws Exception
	{
		//get socketchannel
		SocketChannel client = SocketChannel.open();
		//set no blocking
		client.configureBlocking(false);
		//connect to remote address
		client.connect(new InetSocketAddress("localhost", 10000));
		//open selector
		Selector selector = Selector.open();
		//register connection event
		client.register(selector, SelectionKey.OP_CONNECT);
		
		System.out.println("=====client start====");
		
		while(true)
		{
			if(selector.select()>0)
			{
				Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
				
				while(iter.hasNext())
				{
					SelectionKey key = iter.next();
					//avoid duplication
					iter.remove();
					//obtain current channel
				   SocketChannel channel = (SocketChannel) key.channel(); 
				   //connect
				   if(key.isConnectable())
				   {
					   //register read and write
					   channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
					   //finish connect
					   channel.finishConnect();
					   System.out.println("client connection server");
					   channel.write(ByteBuffer.wrap("client prepare \r\n".getBytes()));
				   }
				   //read
				   if(key.isReadable())
				   {
					   ByteBuffer buffer = ByteBuffer.allocate(20);
					   int len = -1;
					   while(0 != (len = channel.read(buffer)))
					   {
						   System.out.println(new String(buffer.array(), 0, len));
						   buffer.clear();
					   }
				   }
				   //write
				   if(key.isWritable())
				   {
					   System.out.print("client#: ");
					   BufferedReader read = new BufferedReader(
							new InputStreamReader(System.in));

						String line = read.readLine();
						//send some data
						channel.write(ByteBuffer.wrap((line + "\r\n").getBytes()));  
				   }
				   //set network delay
				   Thread.sleep(2000);
				}
				
			}
			
		}
		
	}
}


效果:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值