用Socket实现广播聊天室

首先说明的是,本帖中的例子是来自网上的一个例子,经过了优化后的结果

实现以下功能:
1.在服务端提示所有客户端发来的消息以及当前的在线人数
2.服务端自动转发新上线用户的IP端口号消息给所有用户(当前用户除外)
3.服务端自动转发当前客户发给其他客户的消息
4.服务端自动转发离线客户的消息
5.服务端接收客户端的断开连接消息,可以断开当前连接
6.客户端连接指定的服务端端口
7.客户端向服务发出普通消息
8.客户端向服务端发出断开连接消息

目前只能实现群聊功能,还无法实现私聊

比如目前有ABC三个用户连接到服务端S,客户端都给服务端发消息,服务端都把在收到的消息广播给其他客户端

客户端代码:
import java.io.BufferedReader;   
import java.io.InputStreamReader;   
import java.io.PrintWriter;   
import java.net.Socket;   
import java.util.concurrent.ExecutorService;   
import java.util.concurrent.Executors;
import java.util.*;

public class ChatClient {   
    private static final int PORT = 8888;   
    private static ExecutorService exec = Executors.newCachedThreadPool();   
	private String userId; //用户ID:使用客户端的IP+端口
  
    public static void main(String[] args) throws Exception {   
        new ChatClient();
    }
  
    public ChatClient() {
		Socket socket = null;
		String msg;

        try {
            socket = new Socket("localhost", PORT);
			//客户端连接到服务端之后,启动一个线程用于接收命令行输入,并且发送到服务端
            exec.execute(new Sender(socket));
			userId = socket.getInetAddress() + ":"+socket.getLocalPort();

            println("[" + userId + "] 您好,欢迎来到阿飞聊天室!");
			
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));   
            
            while (null != (msg = br.readLine())){
					println(msg);
            }
			
        } catch (Exception e) { }
    }
  
    /**  
     * 客户端线程获取控制台输入消息,并且向服务发送消息
     */
    static class Sender implements Runnable {
        private Socket socket;
  
        public Sender(Socket socket) {
            this.socket = socket;
        }
  
        public void run() {
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));   
                PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);   
                String msg;

                while (true) {					
					
					//如果用户在命令行中按回车或输入空信息,则不发送到服务端
                    msg = br.readLine();
					if (msg.length()==0){
						print(socket.getLocalPort()+":>");
					}else{
						pw.println(msg);
						continue;
					}
  
					//客户端发bye退出
                    if (msg.trim().equals("bye")) {
                        pw.close();
                        br.close();
                        break;   
                    }
					
					//测试消息
					if (msg.equals("broadcast")){						
						msg = "这是来自"+socket.getInetAddress() + ":"+socket.getLocalPort() + " 的测试消息";
						pw.println(msg);	
					}
                }
				pw.close();
                br.close();
				socket.close();
				exec.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();   
            }
        }
    }

	public static void print(Object o){
		System.out.print(o);
	}

	public static void println(Object o){
		System.out.println(o);
	}
}  


服务端代码:

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.ArrayList;   
import java.util.List;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ChatServer {
	// 端口号
    private static final int PORT = 8888; 

	//创建一个线程安全的的Socket列表,保存Socket对象
    private static List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>());

	//线程池服务对象
    private ExecutorService exec;   
    private ServerSocket server;
  
    public static void main(String[] args) {   
        new ChatServer();   
    }   
	
    public ChatServer() {
        try {
            server = new ServerSocket(PORT);

			//启动一个线程池
            exec = Executors.newCachedThreadPool();
            println("阿飞聊天室服务器已启动,监听 "+server.getInetAddress()+":"+server.getLocalPort() +" 端口");   
  
            Socket client = null;
            while (true) {
				//接收客户连接,该套接字将被添加到Socket列表列表中,并且创建一个新的服务线程
                client = server.accept(); 
                socketList.add(client);	
                exec.execute(new ChatTask(client));   
            }   
        } catch (IOException e) {   
            e.printStackTrace();
        }
    }
  
   //为客户端服务的线程类,负责收发该socket对象的输入和输出信息
   class ChatTask implements Runnable {
        private Socket socket;
        private BufferedReader bufferReader;
        private PrintWriter writer;
        private String msg;
		private int isClosed=0;
		private String userId; //用户ID:使用客户端的IP+端口
  
        public ChatTask(Socket socket) throws IOException {
            this.socket = socket;
            bufferReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));   
			userId = this.socket.getInetAddress() +":"+this.socket.getPort();
            msg = "[" + userId + "]进入聊天室!当前聊天室有"  
                    + socketList.size() + "人";
  
            sendMessage(socket.getPort());//给所有人发消息
        }
  
        public void run() {
            try {
                while ( null != (msg = bufferReader.readLine())){
					
					//服务端收到bye,关闭与该用户的连接
                    if (msg.trim().equals("bye")) {
                        socketList.remove(socket);

                        msg = "[" + userId + "]离开聊天室!当前聊天室有" + socketList.size() + "人";                        
                        sendMessage(socket.getPort()); //给别人发
                        break;
                    } else {
                        msg = "[" + userId+ "]说: " + msg;
                        sendMessage(socket.getPort()); //给别人发
                    }

					try{
						Thread.sleep(10);
					}catch(Exception e){
						e.printStackTrace();
					}
                }
				//关闭服务,关闭的同时也就关闭了InputStream和outputStream,因此不必在上面关闭pw 和  br
				socket.close();
				bufferReader=null;
				writer=null;				
            } catch (IOException e) {
                //e.printStackTrace();
            }
        }   
  
        /**  
         * 群发消息给聊天室的其他人
         */  
        private void sendMessage(int selfPort) throws IOException {   //Socket selfSocket,boolean toSelf
            println(msg);
            for (Socket client : socketList) {
				if (client.getPort() != selfPort){
					writer = new PrintWriter(client.getOutputStream(), true);
					writer.println(msg);
				}
            }
        }
    }

	public static void println(Object o){
		System.out.println(o);
	}
}  


启动了服务端之后,然后再启动两个或多个客户端,在每个客户端窗口里直接输入要发送的消息按回车,该信息即可被广播到其他的客户端窗口

服务端图片:
用Socket实现广播聊天室

客户端图片:
用Socket实现广播聊天室

用Socket实现广播聊天室

你可能感兴趣的:(java,thread,.net,socket,ITeye)