服务端
package chatTest;
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.HashMap;
import java.util.Map;
public class Server2 {
public ServerSocket server;
//私聊用map,key为昵称,value是对应消息,广播则遍历value
private Map<String,PrintWriter> pri_map;
// 初始化服务端
public Server2() throws Exception {
// 初始化的同时申请端口号
server = new ServerSocket(8798);
//初始化用于保存客户端输出流的Map集合
pri_map = new HashMap<String,PrintWriter>();
}
//将客户端发送过来的信息以键值对形式存入map集合,(昵称,对应输出流)
private void putIn(String key,PrintWriter value){
pri_map.put(key,value);
}
//将给定的消息发送给私聊的客户端
private synchronized void sendMessageToOne(String name,String message) {
//将对应客户端的聊天信息取出作为私聊内容发送出
PrintWriter pw=pri_map.get(name); //此处name为键,get(name)获取其值,即目标客户端的输出流(写)
if (pw!=null){
pw.println(message); //如果目标输出流对象存在,将信息写入该流
}
}
//将指定的输出流从共享集合map中删除
private synchronized void remove(String key) {
pri_map.remove(key);
}
//服务端开始工作的方法
public void start(){
try {
while(true) {
System.out.println("等待客户端连接...");
//侦听并接受想连接到此套接字的客户端连接
Socket socket = server.accept();
//获取客户端ip地址
InetAddress address = socket.getInetAddress();
System.out.println("客户端:" + address.getHostAddress() + "连接成功! ");
//创建一个实现Runnale接口的线程处理与客户端的交互
ClientHandler handler= new ClientHandler(socket);
Thread t = new Thread(handler);
//启动线程
t.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//ClientHandler:处理与客户端的交互
class ClientHandler implements Runnable{
//该线程处理的客户端的Socket
private Socket socket;
// 客户端的地址信息,区分不同客户端(ip地址)
private String host;
//当前客户端用户昵称
private String nickName;
//消息接收者昵称
private String targetName;
//构造方法
public ClientHandler(Socket socket) {
this.socket = socket;
}
//线程的run()方法
public void run() {
try {
//服务端的输入流br读取客户端发送的消息
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in,"UTF-8");
BufferedReader br = new BufferedReader(isr);
//通过Socket创建输出流pw用于将消息发送给客户端
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
PrintWriter pw = new PrintWriter(osw,true);
//首先读取一行字符串为昵称
nickName = br.readLine();
//将当前客户端昵称和其所说的内容存入共享集合HashMap中
putIn(nickName,pw);
//读取消息接收者客户端的昵称
targetName = br.readLine();
System.out.println(nickName+"的消息接收者:"+targetName);
//将当前客户端输入的消息发送给消息接收者
String message = null;
while((message = br.readLine()) != null) {
message=nickName+":"+message;//发送的消息格式: 发送者昵称:消息
sendMessageToOne(targetName, message);
}
} catch (Exception e) {
}finally {
//处理当前客户端断开后的逻辑
//将该客户端的输出流pw从共享集合中删除
remove(nickName);
sendMessageToOne(targetName,nickName+"下线了!");
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
try {
Server2 server2 = new Server2();
server2.start(); //执行服务端start方法
} catch (Exception e) {
e.printStackTrace();
System.out.println("服务端建立联系失败!");
}
}
}
客户端
package chatTest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class Client2 {
private Socket socket;
public Client2() throws Exception {
//创建一个套接字并将其连接到指定主机上的指定端口号
socket = new Socket("localhost",8798);
}
//客户端开始工作的方法
public void start() {
try {
//创建Scanner类,用于获取用户输入
Scanner scanner = new Scanner(System.in);
//用户输入昵称
String nickName = null;
while(true) {
System.out.println("请输入昵称:");
nickName = scanner.nextLine();
if(nickName.length()>0) {
break;
}
System.out.println("输入有误");
}
//输入消息接收者昵称
String targetName = null;
while(true) {
System.out.println("请输入消息接收者昵称");
targetName = scanner.nextLine();
if(targetName.length()>0) {
break;
}
System.out.println("输入有误");
}
System.out.println("开始聊天吧!!!");
//输出流(发送内容到服务端)
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
//第二参数为true会行刷新,
PrintWriter pw = new PrintWriter(osw,true);
//先将昵称和接受者发给服务器
pw.println(nickName);
pw.println(targetName);
//启动"读取服务端发送过来的消息"的线程
ServerHandler handler = new ServerHandler();
Thread t = new Thread(handler);
t.start();
//发送信息到服务端处理
while(true) {
pw.println(scanner.nextLine());
}
} catch (Exception e) {
e.printStackTrace();
}
}
//该线程用来读取通过服务器端发送来的消息,并输出到客户端控制台
class ServerHandler implements Runnable {
//线程run方法
public void run() {
try {
//输入流(读)
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in,"UTF-8");
BufferedReader br = new BufferedReader(isr);
String message = null;
//读取信息
while ((message = br.readLine())!=null) {
System.out.println(message);
}
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
try {
Client2 client2 = new Client2();
client2.start();
}catch(Exception e) {
e.printStackTrace();
System.out.println("客户端启动失败!");
}
}
}