java类似QQ的聊天室程序的实现(下)(服务器端程序)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 聊天室客户端
 * @author~~
 */

public class Server {
	/*
	 * java.net.ServerScoket
	 * 运行在服务端的ServerSocket有两个作用
	 * 1:申请服务端口(客户端通过该端口与服务端建立链接)
	 * 2 监听端口:一旦客户通过该端口链接后,会创建一个Scoket实例与该客户进行通讯
	 */
	private ServerSocket server;
	// 保存所有客户端的流
	private List allOut;
	public Server() throws IOException{
		/*
		 *  创建ServerScoket同时需要申请服务端口
		 *  这个端口不能与其他使用TCP协议的应用程序冲突
		 *  否测 会抛出异常
		 * 
		 */
		server=new ServerSocket(8088);
		allOut =new ArrayList();
		
	}
	private synchronized void  addOut(PrintWriter pw){
		/*
		 * 将指定的客户端的输出流从共享的集合中删除
		 * @param pw
		 */
		allOut.add(pw);
	}
	private  synchronized void  removeOut(PrintWriter pw){
		allOut.remove(pw);
	}
	/*
	 * 广播消息 将给定的消息通过遍历共享集合将该消息发送给没有个客户端
	 */
	
	private synchronized  void sendMessagage(String message){
		for(PrintWriter pw:allOut){
			pw.println(message);
		}
	}
	public void start() throws IOException{
		while(true){
		System.out.println("等待客户端链接...");
		/*
		 * Socket accept()
		 * serversocket提供了accept方法用来监听打开的服务端口 
		 * 一旦一个客户端通过该端口请求时 就会创建一个socket并返回
		 * 通过该socket就可以与客户端进行交互了
		 * 该方法是一个阻塞方法
		 * 直到客户端连接才会有返回值
		 */
		Socket socket=server.accept();
		ClientHandler hander=new ClientHandler(socket);
		Thread t=new Thread(hander);
		t.start();
		}
	
	}
	public static void main(String[] args) {
		try{
			Server server=new Server();
			server.start();
		}catch(Exception  e){
			e.printStackTrace();
		}
	}
	/*
	 * 该类十一个线程的任务,负责与指定客户端进行交互
	 * 
	 */
	
	private class ClientHandler implements Runnable{
		/*
		 * 当前线程需要需要处理的针对客户端socket
		 */
		private Socket socket;
		private String host;
		
		
		public ClientHandler(Socket socket){
			this.socket=socket;
			InetAddress address=socket.getInetAddress();
			host=address.getHostAddress();
			}
		@Override
		public void run() {
			PrintWriter pw=null;
		try{
			//sendMessagage(host+" 上线了"+allOut.size()+"人在线");
			//System.out.println(host+"上线了!");
			//创建输出流 用来将消息发送至客户端
			OutputStream out=socket.getOutputStream();
			OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");
			//PrintWriter pw=new PrintWriter(osw,true);
			pw=new PrintWriter(osw,true);
			//将该客户端的输出流存入共享集合
			addOut(pw);
			sendMessagage(host+" 上线了"+allOut.size()+"人在线");
			/*
			 * 	InputStream getInputStream()
			 * socket 提供的该方法可以获取一个输入流,
			 * 通过该输入流可以读取远端计算机发送过来的数据
			 */
			//Thread thead=Thread.currentThread();
			InputStream in=socket.getInputStream();
			InputStreamReader inr=new InputStreamReader(in,"UTF-8");
			BufferedReader buf=new BufferedReader(inr);
			String message=null;
			while((message=buf.readLine())!=null){
				/*
				 * 使用br.readLine方法读取远端计算机发送过来的数据时,由于客户端操作系统不同,当断开连接时这里的反应也不相同。
				 * 当linux的客户端断开连接:会返回null
				 * 当windows客户端断开时:会抛出异常
				 */
				//	System.out.println(host+"说:"+message);
				//	pw.println(host+"说:"+message);
				sendMessagage(host+" 说 :"+message);
				//sendMessagage(host+)
				
			}
		
		}catch(IOException e){
			e.printStackTrace();
		} finally{
			//客户端断开链接处理
			//将噶客户端的输出流从从共享集合中删除
			removeOut(pw);
			//System.out.println(host+"下线了");
			sendMessagage(host+"下线了"+"还剩多少人在线"+allOut.size());
			try{
				socket.close();
			}catch(IOException  e){
				e.printStackTrace();
			}
		}
	}
}}

你可能感兴趣的:(初级篇---Java)