欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

利用线程池实现ServerSocket的多客户端连接

程序员文章站 2024-03-22 23:35:34
...

**利用线程池实现ServerSocket的多客户端连接**------------------------------

实际应用中,对于Socket通信而言基本都是多个客户端连接服务器端,因此简单的ServerSocket/Socket组合就无法满足要求了,而老是新开线程的话又太浪费资源,这里就用到Java自带的线程池ThreadPoolExcutor技术来实现多客户端连接服务端**

ThreadPoolExcutor类**

对原理很感兴趣的朋友可以直接看JDK源码,如果跟我一样对于纯英文的JDK看着头疼也可以度娘关于ThreadPoolExcutor类的源码解释,缺点就是不排除翻译可能不准确,所以看中文翻译版解释时注意仅作为参考,以实践为准,这里贴出一个解释的比较好的博客:

> http://www.cnblogs.com/zhanjindong/p/java-concurrent-package-ThreadPoolExecutor.html

获取ThreadPoolExcutor类的实例:

ThreadPoolExecutor pool=new ThreadPoolExecutor(5,10,3,TimeUnit.SECONDS,new ArrayBlockingQueue(1000));

四个参数的含义:

第一个,核心池大小;

第二个:最大线程数量,当线程数已经达到了核心池数量时,新添加的任务就会额外的开启新线程去运行,但不能超过第二个参数值,

第三个参数就是空闲线程休眠时间最大值,其单位就是第四个参数,超过这个最大值的空闲线程会被关掉,但总数量不会小于核心池大小;

第五个就是组塞队列,想要了解的可以度娘。

关于Socket就不详细的讲了,只贴出应用:

以下代码想看成效的只需要复制粘贴修改包名即可用,先开启服务类,然后开启第二个类,由于客户端代码一致,因此可以再建一个类把ClientSocket的代码复制一遍,然后运行,这样就模拟了两个客户端跟服务端的同时通信

第一个类,ServSocket:

package Chapter9;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

//双向聊天应该建立在同样的端口,且由服务器发起,如果要由客户端发起,可以另开端口,客户端做服务器
//由于没有制作swing界面,因此在此处不提供由服务器端同时向多个客户端进行聊天的代码,但也实现了单个客户端连接时的双向聊天
public class ServSocket {
	
	public static void main(String[] args) {
		ServerSocket serverSocket;
		ThreadPoolExecutor pool=new ThreadPoolExecutor(5,10,3,TimeUnit.SECONDS,new ArrayBlockingQueue(1000));
		try {
			Socket socket=null;
			serverSocket = new ServerSocket(12001);
			for(int i=0;i<2;i++){
			socket=serverSocket.accept();
			System.out.println("---"+(i+1)+"号客户端连接成功");
			if(i==1){
				i=0;//这里的作用在于保证即使客户端主动断开了连接,服务器也可以一直处于等待状态(不跳出循环),否则出了循环socket就将关闭
			}
			pool.execute(new ReaderHandle(socket));
			}
			
			
			new Thread(new WriteHandle(socket)).start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}
class ReaderHandle implements Runnable{
	public Socket socket;
	public ReaderHandle(Socket socket) {
		// TODO Auto-generated constructor stub
		this.socket=socket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			
			System.out.println("等待用户接入:");
			InputStreamReader in=new InputStreamReader(socket.getInputStream());
			BufferedReader buffer=new BufferedReader(in);
			String read="";
			try{
			while((read=buffer.readLine())!="quit"){//如果用户没有输入quit或者强行中断控制台,那么就可以保持持续连接
				System.out.println(Thread.currentThread().getName()+"处理"+read);
			}
			}catch (SocketException e) {
				// TODO: handle exception
				System.out.println("客户端主动断开连接");//当用户强行中断控制台时会抛出SokcetException
			}
			socket.close();
			in.close();
			buffer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}
class WriteHandle implements Runnable{//这个类的作用是向Socket里面写入数据,想用的话只需要连接单个客户端即可
	public Socket socket;
	public WriteHandle(Socket socket) {
		// TODO Auto-generated constructor stub
		this.socket=socket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			
			OutputStream out=socket.getOutputStream();
			PrintWriter printWriter=new PrintWriter(out);
			System.out.println("正在与客户端聊天:");
			BufferedReader buffer=new BufferedReader(new InputStreamReader(System.in));
			while(true){//保证服务端可以一直跟客户端聊天
			String str=buffer.readLine();
			System.out.println("     你:"+str);
			printWriter.println("来自服务器的消息:"+str);
			printWriter.flush();
			}
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}

第二个类:ClientSocket:

package Chapter9;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class ClientSocket {

	public static void main(String[] args) {
		try {
			Socket socket=new Socket("localhost", 12001);
			//new Thread(new ReadHandle(socket)).start();
			new Thread(new WrteHandle(socket)).start();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		}

}
//这里我关闭了从服务器的管道里读取流的类,毕竟没有很好的实现多客户端条件下的服务-客户单对单的聊天
/*
class ReadHandle implements Runnable{
	public Socket socket;
	public ReadHandle(Socket socket) {
		// TODO Auto-generated constructor stub
		this.socket=socket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			
			InputStreamReader in=new InputStreamReader(socket.getInputStream());
			BufferedReader buffer=new BufferedReader(in);
			String read="";
			while((read=buffer.readLine())!="quit"){
				
				System.out.println(read);
			}
			socket.close();
			in.close();
			buffer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}
*/
class WrteHandle implements Runnable{
	public Socket socket;
	public WrteHandle(Socket socket) {
		// TODO Auto-generated constructor stub
		this.socket=socket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			
			OutputStream out=socket.getOutputStream();
			PrintWriter write=new PrintWriter(out);
			System.out.println("你想说:");
			BufferedReader buffer=new BufferedReader(new InputStreamReader(System.in));
			while(true){
			String str=buffer.readLine();
			System.out.println("    你:"+str);
			write.println("来自客户端的消息:"+str);
			write.flush();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
		
	}
	
}