此题综合了,最近两周学习的IO流、进程、网络传输等知识,基本实现了多人聊天的功能。经过修改封装,有较好的可读性。
设计思路:
1、建立一个进程类Monitor,其成员变量包括Socket的引用、读和写的引用、客户端的编号名字。为每一个客户端建立Monitor的对象并将其放在静态ArrayList中;
2、通过对ArrayList的枚举实现信息的群发和转发;
3、通过匿名类不类分别建立读和写的进程,并以temp2为开关;
4、在主方法中开启进程clossAll(),并通过枚举ArrayList监控对象的开关temp2。当temp2=false时,关闭当前对象的所有通道、进程,同时从ArrayList上删除;
5、服务器有较好的通用性,只需要客户端具有read和write的能力变可以实现通讯;
6、关于乱码,当编码完全采用GBK编码时,可以解决键盘输入乱码的问题。客户端编码必须同服务器编码保持一致。
类Monitor:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
public class Monitor extends Thread {
/** 用于存放Socket连接的对象所在的Monitor */
static ArrayList list = new ArrayList();
/** 避免nums重复的计数器 */
static int cout = 0;
/** 服务器全局输入对象 */
static Scanner line = new Scanner(System.in);
/** 端口编号,用cout进行赋值便于确定对象 */
int nums;
Socket socket;
BufferedReader read;
PrintWriter write;
String name;
boolean temp2 = true;
/**
* 构造方法
*/
public Monitor(Socket socket) {
this.socket = socket;
cout++;
nums = cout;
try {
read = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
write = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
System.out.println(nums + "端口错误!");
}
this.start();
}
/**
* 开启通道进程
*/
public void run() {
names();
reads();
writes();
}
/**
*转发连接用户的信息,实现信息同步
*/
void sendMessage(String str) {
for (int i = 0; i < list.size(); i++) {
if (nums != list.get(i).nums) {
list.get(i).write.println(str);
list.get(i).write.flush();
}
}
}
/**
* 服务台发送信息
*/
static void sendTo(String str) {
if (str != null) {
str = "帅的飞起说:" + str;
for (int i = 0; i < list.size(); i++) {
list.get(i).write.println(str);
list.get(i).write.flush();
}
}
}
/**
* 读取客户端名字
*/
void names() {
write.println("请输入您的名字!");
write.flush();
boolean temp3 = true;
while (temp3) {
try {
Thread.sleep(100);
String str2 = read.readLine();
if (str2 != null) {
name = str2;
temp3 = false;
String str4 = "欢迎" + name + "加入聊天室";
System.out.println(str4);
sendTo(str4);
}
} catch (IOException e) {
System.out.println("录入客户端名字出错");
temp2 = false;
temp3 = false;
} catch (InterruptedException e) {
System.out.println("录入客户端名字出错");
temp2 = false;
temp3 = false;
}
}
}
/**
* 进程,读取信息并且将信息群发给在线其他人
*/
void reads() {
new Thread(new Runnable() {
public void run() {
while (temp2) {
try {
sleep(100);
String str = name + "说:" + read.readLine();
if (!str.equals(name + "说:")) {
System.out.println(str);
sendMessage(str);
}
} catch (IOException e) {
System.out.println(name + "读取错误");
temp2 = false;
} catch (InterruptedException e1) {
System.out.println(name + "read读入异常");
temp2 = false;
}
}
}
}).start();
}
/**
* 进程,群发信息
*/
void writes() {
new Thread(new Runnable() {
public void run() {
while (temp2) {
String str1 = null;
try {
str1 = line.nextLine();
} catch (Exception e) {
}
sendTo(str1);
}
}
}).start();
}
/**
* 关闭当前对象所有进程:当temp2为false时关闭各种进程
*/
static void closeAll() {
new Thread(new Runnable() {
public void run() {
boolean temp = true;
while (temp) {
int i = 0;
try {
sleep(100);
for (; i < list.size(); i++) {
if (list.get(i).temp2 == false) {
if (list.get(i).read != null) {
list.get(i).read.close();
}
if (list.get(i).write != null) {
list.get(i).write.close();
}
if (list.get(i).socket != null) {
list.get(i).socket.close();
}
String str5 = list.get(i).name + "已退出聊天!";
list.remove(i);
System.out.println(str5);
sendTo(str5);
}
}
} catch (IOException e) {
System.out.println("关闭进程" + list.get(i).nums + "出错");
} catch (InterruptedException e1) {
System.out.println("结束程序:等待错误!");
}
}
}
}).start();
}
}
主方法:
import java.io.IOException;
import java.net.ServerSocket;
/**
* 实现多人聊天功能的服务器,主方法类
*/
public class Server {
/** 当temp1为false时停止服务器 */
static boolean temp1 = true;
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(7845);
Monitor.closeAll();//开启监控程序用于删除在list上过期的对象
while (temp1) {
Monitor.list.add(new Monitor(server.accept()));//监视等待信号
}
} catch (IOException e) {
System.out.println("端口错误!");
}
}
}
一个简易的客户端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class SerCient {
public static void main(String[] args) {
try {
Scanner str = new Scanner(System.in);
Socket socket = new Socket("localhost", 7845);
final BufferedReader read = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter write = new PrintWriter(new OutputStreamWriter(socket
.getOutputStream()));
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(100);
String str2 = read.readLine();
if (str2 != null) {
System.out.println( str2);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str3 = str.next();
while (!str3.equals("88")) {
write.println(str3);
write.flush();
str3 = str.next();
}
read.close();
write.close();
str.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}