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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值