论坛首页 Java企业应用论坛

java多线程控制台聊天室

浏览 23761 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-11   最后修改:2009-04-11
用java多线程实现一个控制台聊天室,呵呵,好玩!

聊天室服务器端
package tf.thread;

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

public class ChatServer {
	private static final int PORT = 8888; // 端口号
	private static List<Socket> list = 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();
			System.out.println("服务器已启动!");

			Socket client = null;
			while (true) {
				client = server.accept(); // 接收客户连接
				list.add(client);
				exec.execute(new ChatTask(client));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	static class ChatTask implements Runnable {
		private Socket socket;
		private BufferedReader br;
		private PrintWriter pw;
		private String msg;

		public ChatTask(Socket socket) throws IOException {
			this.socket = socket;
			br = new BufferedReader(new InputStreamReader(socket
					.getInputStream()));
			msg = "【" + this.socket.getInetAddress() + "】进入聊天室!当前聊天室有【"
					+ list.size() + "】人";

			sendMessage();
		}

		public void run() {
			try {
				while ((msg = br.readLine()) != null) {
					if (msg.trim().equals("bye")) {
						list.remove(socket);
						br.close();
						pw.close();
						msg = "【" + socket.getInetAddress() + "】离开聊天室!当前聊天室有【"
								+ list.size() + "】人";
						socket.close();

						sendMessage();
						break;
					} else {
						msg = "【" + socket.getInetAddress() + "】说:" + msg;
						sendMessage();
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		/**
		 * 群发消息给聊天室的所有人
		 */
		private void sendMessage() throws IOException {
			System.out.println(msg);
			for (Socket client : list) {
				pw = new PrintWriter(client.getOutputStream(), true);
				pw.println(msg);
			}
		}
	}
}



聊天室客户端(输入bye可退出聊天室)
package tf.thread;

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;

public class ChatClient {
	private static final int PORT = 8888;
	private static ExecutorService exec = Executors.newCachedThreadPool();

	public static void main(String[] args) throws Exception {
		new ChatClient();
	}

	public ChatClient() {
		try {
			Socket socket = new Socket("192.168.1.120", PORT);
			exec.execute(new Sender(socket));
			System.out
					.println("【" + socket.getInetAddress() + "】您好,欢迎来到阿飞聊天室!");

			BufferedReader br = new BufferedReader(new InputStreamReader(socket
					.getInputStream()));
			String msg;
			while ((msg = br.readLine()) != null) {
				System.out.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();
					pw.println(msg);

					if (msg.trim().equals("bye")) {
						pw.close();
						br.close();
						exec.shutdownNow();
						break;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

   发表时间:2009-04-12  
mina 几句就搞定了的
0 请登录后投票
   发表时间:2009-04-13  
fjlyxx 写道
mina 几句就搞定了的

哈哈,实现功能的代码确实没多少,我只是加了一些进入聊天室提醒或离开聊天室提醒以及清除资源的代码,所以显得多了。见笑了!
0 请登录后投票
   发表时间:2009-04-15  
SOCKET 写一个聊天室也蛮有意思的!加油!
0 请登录后投票
   发表时间:2009-04-15  
lvp 写道
SOCKET 写一个聊天室也蛮有意思的!加油!

是挺有意思的,看你写的聊天室,很不错呢
向你学习!
0 请登录后投票
   发表时间:2009-04-15  

LZ,

private static List<Socket> list = new ArrayList<Socket>(); // 保存连接对象

服务器端有多个线程都会读list,貌似并非线程安全...

 

0 请登录后投票
   发表时间:2009-04-15  
finux 写道

LZ,

private static List<Socket> list = new ArrayList<Socket>(); // 保存连接对象

服务器端有多个线程都会读list,貌似并非线程安全...

 


恩,确实应该考虑同步问题,可以用 CopyOnWriteArrayList替换ArrayList
0 请登录后投票
   发表时间:2009-04-16  
呵呵,给你个建议.你可以这样写.当前一个线程拥有这个SOCKET,如果有请求那么这个拥有SOCKET的线程去现场池里面找一条可以用的线程并且把SOCKET给他,这样的话你就避免了线程的问题.如果要群发的话那么你应该考虑用消息通信机制,避免让消息去驱动连接.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics