现在的位置: 首页 > 综合 > 正文

Java之Socket简单聊天实现(QQ续二)

2018年01月30日 ⁄ 综合 ⁄ 共 2624字 ⁄ 字号 评论关闭

今天跟大家分享一下我那QQ小项目中服务器与客户端的核心代码,并谈谈一些我的建议和看法,希望大家多多支持,你们的支持,就是我继续分享的动力,哈哈!

        一、服务器,好了,废话不多说,我们先来看看服务器部分,我这里用到线程池,至于为什么用线程池,不知道的童鞋可以去我的另一篇blog看看:http://blog.csdn.net/weidi1989/article/details/7930820。当一个用户连接上之后,我们马上将该用户的socket丢入已经建好的线程池中去处理,这样可以很快腾出时间来接受下一个用户的连接,而线程池中的这个线程又分支为两个线程,一个是读消息线程,一个是写消息线程,当然,因为我这个聊天是用来转发消息的,所以还以单例模式建了一个Map用来存放每个用户的写消息线程(如果用户多的话,这是相当消耗资源的),以便在转发消息的时候,通过Map的key就可以取出对应用户的写消息线程,从而达到转发消息的目的。具体下面再说

 

package server;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Server { 
	private ExecutorService threadPool; //线程池
	private ServerSocket serverSocket; //服务器套接字
	private Socket socket; //客户端套接字
	private boolean isStarted; //是否循环读取消息
	private String ip;
	private int serverPort; //端口号
	private int size = 50;
	
	public Server() {
		try {
			int cpuNum = Runtime.getRuntime().availableProcessors();
			// 创建线程池,池中具有(cpu个数*50)条线程    
			threadPool = Executors.newFixedThreadPool(cpuNum * this.size);
			serverSocket = new ServerSocket(this.serverPort);
			
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	/**
	 * 启动服务器
	 */
	public void service() {
		long beginTime = System.currentTimeMillis();
		long endTime;
		System.out.println("=====开始启动服务器===" + beginTime);
		try {
			while (isStarted) {
				//从ServerSocket中取出一个客户端连接
				//侦听并接受到此套接字的连接。
				socket = serverSocket.accept();
				ip = socket.getInetAddress().toString();
				System.out.println(" 用户:" + ip + " 已建立连接");
				
				//为支持多用户并发访问,采用线程池管理每一个用户的连接请求
				if (socket.isConnected()) {
					// 添加到线程池 
					threadPool.execute(new SocketTask(socket));
				}
				
				//循环结束后,记得关闭socket,释放资源
				if (socket != null) {
					socket.close(); 
				}
				
				if (serverSocket != null) {
					serverSocket.close();
				}
				endTime = System.currentTimeMillis();
				System.out.println("=====服务器启动成功===耗费时间:" + (endTime - beginTime) +"毫秒 ");
			}
		} catch (Exception e) {
			// isStarted = false;   
			e.printStackTrace(); 
		}
	  
	}
	
	/**
	 * 服务器退出
	 */
	public void quit() {
		try {
			this.isStarted = false;  
			serverSocket.close(); 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	 
	public void setSize(int size) {
		this.size = size;
	}
	
	/**
	 * 功能说明
	 *     服务器的套接字任务
	 * @author Administrator
	 *
	 */
	private class SocketTask implements Runnable {
		private Socket socket;
		private InputThread in;
		private OutputThread out;
		private OutputThreadBuffer buffer; 
		
		public SocketTask(Socket socket) {
			this.socket = socket;
			this.buffer = OutputThreadBuffer.getInstance();  
		}

		@Override
		public void run() { 
	
			out = new OutputThread(socket, buffer);
			// 先实例化写消息线程,(把对应用户的写线程存入map缓存器中)   
	        in = new InputThread(socket, out, buffer); // 再实例化读消息线程   
	        out.setStart(true);  
	        in.setStart(true);  
	        in.start();  
	        out.start(); 
		}
		
	}
}

二、服务器写消息线程,接下来,我们来看看写消息线程,很简单的一段代码,有注释,我就不多说了:

抱歉!评论已关闭.