Java基础案例 — 控制台群聊版聊天室(IO流、Socket)

一、案例需求

  1. 一个在线聊天室的建立,首先需要能够发出信息的客户端。
  2. 一个能够收到并转发的服务器端。
  3. 模拟聊天,客户端应该能够一直收取信息,发送信息不影响收取信息。
  4. 服务器端收到客户端信息后,应该是直接转发至群聊聊天室,即在线的每个客户端都能收到。

二、客户端代码实现

  1. 客户端需要在控制台中读取需要发送的信息。
  2. 客户端发送信息不影响收取信息,因此收取信息的功能是一个单独的线程来实现。
  3. 为保证能够让服务器能够区分客户端(客户端有很多,也为之后私聊功能实现),在创建客户端的同时,在发送信息之前,要先给服务器发送客户端名称(控制台输入)。
package day0710_ChatRoom_Multi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
	private Socket s;
	private String name;
	BufferedReader br;
	PrintWriter pw;
	
	public Client(String ip, int port, String name) {
		try {
			s = new Socket(ip, port);
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			pw = new PrintWriter(s.getOutputStream(), true);//客户端只有一个Socket对象,因此构造方法中即可初始化IO流
		
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.name = name;
		sendMessage(name);
	}
	
	public void sendMessage(String message) {
		pw.println(message);
	}
	
	//客户端接收方法只需要单向接收就行,有就接,没有就不接,创建一个单独的线程
	public void receiveMessage() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				while(true) {
					try {
						String message = br.readLine();
						System.out.println(message);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			
		}).start();
	}
	
	public static void main(String[] args) {
		System.out.println("请输入用户名:");
		Scanner sc = new Scanner(System.in);
		String cName = sc.nextLine();
		Client c = new Client("localhost", 8888, cName);
		c.receiveMessage();
		while(true) {
			c.sendMessage(sc.nextLine());
		}
	}
}

三、服务器端代码实现

  1. 服务器端因要持续不断地提供服务,需要单独线程实现,并在收到客户端用户名的时候,提示新用户上线提醒,收到客户端信息的同时转发给所有在线客户端。
package day0710_ChatRoom_Multi;

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

public class Server {
	private ServerSocket ss;
	private Map<String, Socket> map;
	
	public Server(int port) {
		try {
			ss = new ServerSocket(port);
			map = new HashMap<String, Socket>();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void startService() {
//		ExecutorService pool = Executors.newCachedThreadPool();
		while(true) {
			try {
				Socket s = ss.accept();
				//接收客户端名
				String name = receiveMessage(s);
				//存入map
				map.put(name, s);
				//提示新用户上线
				System.out.println("新用户上线了!聊天室目前共有" + map.size() + "人在线");
				
				new ServerThread(s, name).start();
				
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
	//接收信息的功能
	public String receiveMessage(Socket s) {
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			return br.readLine();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	//发送信息的功能
	public void sendMessage(Socket s, String message) {
		try {
			PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
			pw.println(message);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private class ServerThread extends Thread{
		Socket s;
		String name;
		
		public ServerThread(Socket s, String name) {
			this.s = s;
			this.name = name;
		}
		public void run() {
			String message = null;
			while((message = receiveMessage(s)) != null) {//s客户端为null,即断开连接,message也是null
				Set<Entry<String,Socket>> entrySet = map.entrySet();
				for(Entry<String,Socket> entry : entrySet) {
					if(entry.getKey().equals(name)) {
						sendMessage(entry.getValue(), "我说:" + message);
					}else {
						sendMessage(entry.getValue(), name + "说:" + message);
					}
				}
			}
			
			map.remove(name);
			Set<Entry<String,Socket>> entrySet = map.entrySet();
			for(Entry<String, Socket> entry : entrySet) {
				sendMessage(entry.getValue(), name + "下线了");
			}
			
			try {
				s.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
		
	}
	
	public static void main(String[] args) {
		new Server(8888).startService();
	}
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值