`

Java Socket学习---nio实现阻塞多线程通信

阅读更多

本次使用nio实现socket客户端和服务端的通信,并且在服务端为每一个新建的连接创建一个线程负责维持和客户端的通信。

使用nio实现的阻塞的socket与普通方式实现的通信相比较仅仅是实现方式不同,其实质的运行原理是一样的。在此仅仅作为一个nio的入门示例。

nio来做socket主要用到两个类ServerSocketChannel(服务器socket)和SocketChannel(客户端socket)。

 

Channel的简单介绍:ServerSocketChannel和SocketChannel。Java NIO的通道类似流,但又有些不同:

 1. 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。

 2. 通道可以异步地读写。

 3. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

 

Server端程序:

package com.henushang.socket.chapter4nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.henushang.socket.util.SocketUtils;

public class EchoServer {

	private int port = 8000;
	private ServerSocketChannel serverSocketChannel;
	private ExecutorService executorService;
	private final int POOL_SIZE = 4;

	public EchoServer() throws Exception {
		executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
				.availableProcessors() * POOL_SIZE);
		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		System.out.println("等待连接...");
	}

	public void service() {
		SocketChannel socketChannel = null;
		while (true) {
			try {
				System.out.println("waitting for connect...");
				socketChannel = serverSocketChannel.accept();
				System.out.println("get the connect...");
				Thread.sleep(500);
				executorService.execute(new Handler(socketChannel));
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}

	public static void main(String[] args) throws Exception {
		new EchoServer().service();
	}

	class Handler implements Runnable {
		private SocketChannel socketChannel = null;

		public Handler(SocketChannel socketChannel) {
			this.socketChannel = socketChannel;
		}

		@Override
		public void run() {
			handler(socketChannel);
		}

		private void handler(SocketChannel socketChannel) {
			System.out.println("new connection accepted:"
					+ socketChannel.socket().getInetAddress() + ":"
					+ socketChannel.socket().getPort());
			try {
				BufferedReader reader = SocketUtils
						.getReader(this.socketChannel);
				PrintWriter pw = SocketUtils.getWriter(this.socketChannel);
				String msg = null;
				while (true) {
					if ((msg = reader.readLine()) != null) {
						try {
							Thread.sleep(20000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.out.println(msg);
//						pw.write(SocketUtils.echo(msg)+"\r\n");
						pw.println(SocketUtils.echo(msg));
						pw.flush();
						if ("bye".equals(msg)) {
							break;
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				SocketUtils.close(socketChannel);
			}
		}
	}
}

 

Client端程序:

package com.henushang.socket.chapter4nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;

import com.henushang.socket.util.SocketUtils;

public class EchoClient {
	
	private SocketChannel socketChannel;
	private int port = 8000;
	
	public EchoClient() throws Exception {
		socketChannel = SocketChannel.open();
		InetAddress inetAddress = InetAddress.getLocalHost();
		InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
		socketChannel.connect(inetSocketAddress);
		System.out.println("准备连接服务器");
	}
	
	public static void main(String[] args) throws Exception {
		new EchoClient().talk();
	}
	
	public void talk() {
		try {
			BufferedReader reader = SocketUtils.getReader(socketChannel.socket());
			PrintWriter pw = SocketUtils.getWriter(socketChannel.socket());
			BufferedReader localreaderReader = new BufferedReader(new InputStreamReader(System.in));
			String msg = null;
			while ((msg = localreaderReader.readLine()) != null) {
				System.out.println(msg);
				pw.println(msg);
				pw.flush();
				System.out.println(reader.readLine());
				if ("bye".equals(msg)) {
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			SocketUtils.close(socketChannel);
		}
		
	}
}

 

 

SocketUtils:(与以前的一样)

package com.henushang.socket.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.channels.SocketChannel;

public class SocketUtils {
	
	public static PrintWriter getWriter(Socket socket) throws IOException {
		OutputStream os = socket.getOutputStream();
		return new PrintWriter(os);
	}
	
	public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException {
		return getWriter(socketChannel.socket());
	}
	
	public static BufferedReader getReader(Socket socket) throws IOException{
		InputStream is = socket.getInputStream();
		return new BufferedReader(new InputStreamReader(is, "UTF-8"));
	}
	
	public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{
		return getReader(socketChannel.socket());
	}
	
	public static void close(Socket socket) {
		try {
			if (socket != null) {
				socket.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void close(SocketChannel socketChannel) {
		try {
			if (socketChannel != null) {
				socketChannel.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static String echo(String msg) {
		return "echo:" + msg;
	}
}

 

 

 

 

0
1
分享到:
评论

相关推荐

    NIO-实践-多线程实例

    NIO用于高性能Socket编程由来已久,网络也有较为丰富的原理和源代码。我这里主要介绍几点经验总结: ...本文粘贴多线程在NIO环境下的基本运用示例代码,同时演示了一个线程如何对多个连接进行读写的操作。

    java解读NIOSocket非阻塞模式.zip

    jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU...

    基于javatcpsocket通信的拆包和装包源码-niochatroom:基于Javanio的聊天室

    阻塞的原因在于:操作系统允许的线程数量是有限的,多个 socket 申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。 BIO方式适用于连接数目比较小且固定的...

    01-VIP-BIO,NIO,AIO精讲1

    1、IO代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源 2、如果线程很多,会导致服务器线程太多,压力太大 1、channel 类

    Java NIO原理和使用

    Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能...通过仔细阅读这个例程,相信你已经大致了解NIO的原理和使用方法,下一篇,我们将使用多线程来处理这些数据,再搭建一个自己的Reactor模式。

    基于javatcpsocket通信的拆包和装包源码-NettyTree:网状树

    基于java tcp socket通信的拆包和装包源码 NettyTree 搭建一个基于Netty的通信框架 NIO:非阻塞式IO ...有一个专门的NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求;   有一个NIO线程池,

    java高手真经 光盘源码

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    JAVA上百实例源码以及开源项目源代码

     Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...

    Java高手真经(编程基础卷)光盘全部源码 免积分

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    基于Nio的多人聊天Demo

    NIO的目的就是实现一个线程处理多个连接。实现多人聊天消息转发,用户发送消息同步到服务中的其他客户端,运用到了nio中buffer、socket、selector。 1、Channel,管道。Channel可以理解为连接,与BIO中Sokcet类似,...

    基于javatcpsocket通信的拆包和装包源码-Netty-practice:Netty学习实践

    NIO+主从多线程Reactor模型 总结 阻塞IO和非阻塞IO的区别就在于:应用程序的调用(等待数据准备阶段)是否立即返回! 同步IO和异步IO的区别就在于:数据访问(等待数据复制阶段)的时候进程是否阻塞! 再往深了说,可以...

    Java高手真经(编程基础卷)光盘全部源码

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    JAVA上百实例源码以及开源项目

     Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...

    物联网netty对接socket设备-netty定义

    NIO中的特性之一就是零拷贝,在Java中,内存分为堆和栈以及字符串常量值等等,如果有一些数据从IO中读取并且放到堆里面,中间会经过一些缓冲区。 具体来讲,如果要从IO中读取数据,分为两个步骤: (1)从IO流中读取...

    Java CP/IP Socket编程

    4.1.1 Java 多线程..........78 4.1.2 服务器协议..........80 4.1.3 一客户一线程..........84 4.1.4 线程池..........86 4.1.5 系统管理调度:Executor接口..........89 4.2 阻塞和超时..........91 4.2.1 ...

Global site tag (gtag.js) - Google Analytics