java socket nio 多线程_网络NIO-基于socket的服务端多线程模式

本文代码来源于《实战java高并发程序设计》葛一鸣 郭超 著

学习这本书的过程中,感觉这一部分比较重要,自己做下总结,也希望能给大家提供些帮助。

本代码模拟简单的Echo服务器,对于Echo服务器,他会读取客户端的一个输入,并将这个输入原封不动地返回给客户端。虽然实例很简单,但麻雀虽小五脏俱全,需要一套完整的Socket处理机制。适合拿来学习。下面贴出本例代码。

首先补充网络编程的基础。

ServerSocket 类表示 Socket 服务器端,Socket 类表示 Socket 客户端,两者之间的交互过程如下:

服务器端创建一个 ServerSocket(服务器端套接字),调用 accept() 方法等待客户端来连接。

客户端程序创建一个 Socket,请求与服务器建立连接。

服务器接收客户的连接请求,同时创建一个新的 Socket 与客户建立连接,服务器继续等待新的请求。

调用 accept() 方法会返回一个和客户端 Socket 对象相连接的 Socket 对象,服务器端的 Socket 对象使用 getOutputStream() 方法获得的输出流将指定客户端 Socket 对象使用 getInputStream() 方法获得那个输入流。同样,服务器端的 Socket 对象使用的 getInputStream() 方法获得的输入流将指向客户端 Socket 对象使用的 getOutputStream() 方法获得的那个输出流。也就是说,当服务器向输出流写入信息时,客户端通过相应的输入流就能读取。

简而言之,如何进行消息的传递 见下图

ba9992700961b9cc4e6815f808112384.png

1、服务端代码:

服务器会为每一个客户端连接启动一个线程,这个新的线程会全心全意为这个客户端服务。同时,为了接受客户端连接,服务器还会额外使用一个派发线程,如上图:

package socket.demo;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

@author FHY

多线程应用的服务端代码

*

*/

public class MultiThreadEchoServer {

//创建一个线程池,不限制连接的线程数量

public static ExecutorService tp = Executors.newCachedThreadPool();

static class HandleMsg implements Runnable{

Socket clientSocket;

public HandleMsg(Socket clientSocket){

this.clientSocket = clientSocket;

}

@Override

public void run() {

BufferedReader is = null;

PrintWriter os = null;

try{

//输入流 (使用了装饰模式)

is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

//输出流

os = new PrintWriter(clientSocket.getOutputStream(), true);

String inputLine = null;

long b = System.currentTimeMillis();

while ((inputLine = is.readLine())!= null ){

os.println(inputLine);

}

long e = System.currentTimeMillis();

System.out.println("Spend: "+(e-b));

}catch(IOException e){

e.printStackTrace();

}finally{

try{

if(is != null) is.close();

if(os != null) os.close();

clientSocket.close();

}catch(Exception e){

e.printStackTrace();

}

}

}

}

public static void main(String[] args) {

ServerSocket echoSocket = null;

Socket clientSocket = null;

try{

//设置服务端的端口号

echoSocket = new ServerSocket(8000);

}catch(IOException e){

System.out.println(e);

}

while(true){

try{

//接受客户端

clientSocket = echoSocket.accept();

System.out.println(clientSocket.getRemoteSocketAddress() + " connet!");

tp.execute(new HandleMsg(clientSocket));

}catch(IOException e){

System.out.println(e);

}

}

}

}

这就是一个支持多线程的服务端的核心内容。它的特点是,在相同可支持的线程范围内,可以尽量多地支持客户端的数量,同时和单线程服务器相比,它可以更好的使用多核CPU。

2、客户端代码:

package socket.demo;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.InetSocketAddress;

import java.net.Socket;

import java.net.UnknownHostException;

/**

@author FHY

多线程应用的客户端代码

*

*/

public class ClientSocketDemo {

public static void main(String[] args) {

Socket client = null;

PrintWriter writer = null;

BufferedReader reader = null;

try{

client = new Socket();

//客户端连接到服务端

client.connect(new InetSocketAddress("localhost", 8000), 1000*6);

writer = new PrintWriter(client.getOutputStream(), true);

writer.println("Hello!");

writer.flush();

reader = new BufferedReader(new InputStreamReader(client.getInputStream()));

System.out.println("from server:" +reader.readLine());

}catch(UnknownHostException e){

e.printStackTrace();

}catch (IOException e) {

e.printStackTrace();

}finally {

try{

if(writer != null) writer.close();

if(reader != null) reader.close();

if(client != null) client.close();

}catch(IOException e){

System.out.println(e);

}

}

}

}

总结:这种多线程的服务器开发模式是及其常用的,对于绝大多数应用来说,这种模式可以很好地工作,但是如果你想让程序工作地更加有效,就必须知道这种模式的一个重大弱点——那就是它倾向于让CPU进行IO等待。

使用java的NIO就可以将上面的网络IO等待时间从业务处理线程中抽取出来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值