import java.io.*;
import java.net.Socket;
//聊天室客户机:发送消息、接收别人发送的消息
public class Client {
public static void clientRequest() throws IOException {
//建立客户机,与服务器建立连接
Socket client = new Socket("localhost", 8888);
//创建一个线程用于接收消息
new Thread(new Receive(client)).start();
//本线程专用于送发消息
send.clientSend(client);
}
//封装内部类:发送消息
private static class send{
private static void clientSend(Socket client) throws IOException {
boolean isRunning = true;
String msg;
System.out.println("已连接服务");
//利用IO流进行数据传输
//从键盘获取输入
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
//并将获取到的内容发送出去
DataOutputStream os = new DataOutputStream(client.getOutputStream());
while (isRunning) {
try {
msg = is.readLine();
os.writeUTF(msg);
} catch (IOException e) {
isRunning = false;
System.out.println("服务被停止,发送失败!");
is.close();
os.close();
client.close();
}
}
}
}
//封装内部类:接收消息
private static class Receive implements Runnable{
Socket client;
DataInputStream dis;
boolean isRunning = true;
//构造器
private Receive(Socket client) {
this.client = client;
}
//run方法:具体操作
@Override
public void run() {
//具体操作:接收消息
String result;
while(isRunning){
try {
dis = new DataInputStream(client.getInputStream());
result = dis.readUTF();
System.out.println(result);
} catch (IOException e) {
isRunning = false;
}
}
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.net.Socket;
//用户类:保存一个客户机的用户名和Socket
public class User{
String userName;
Socket userSocket;
public User(String name, Socket client){
this.userName = name;
this.userSocket = client;
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
//聊天室服务器:转发客户机发送的消息
public class Server {
//群聊容器
private static CopyOnWriteArrayList<User> all = new CopyOnWriteArrayList<User>();
public static void serverResponse() throws IOException {
boolean isRunning = true;
//建立服务器
ServerSocket server = new ServerSocket(8888);
System.out.println("服务启动");
//监听端口,随时等待客户机连接,当一个客户机连接后,建立一条线程为其服务,随后继续监听端口
while(isRunning){
try{
Socket client = server.accept();
new Thread(new Channel(client)).start();//为这个客户机建立单独的消息转发服务
System.out.println("一个客户机进行了连接");
} catch (IOException e) {
isRunning = false;
System.out.println("服务停止!");
server.close();
}
}
}
//封装内部类:转发器 提供消息转发服务:将客户机发送的消息转发给其他客户机
private static class Channel implements Runnable{
DataInputStream sis;
DataOutputStream sos;
Socket client;
String name;
//构造器
private Channel(Socket client){
try {
//利用IO流进行数据传输
this.client = client;
sis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//群聊
private void group(String msg) throws IOException {
for (User c : all) {//一个客户机发送消息后,遍历容器将该条消息转发给其他客户机
if (c.userSocket != this.client) {
sos = new DataOutputStream(c.userSocket.getOutputStream());
sos.writeUTF(msg);
}
}
}
//run方法:具体操作
@Override
public void run() {
//具体操作:获取用户名,并将用户类存入群聊容器
try {
boolean flag = true;
while(flag){
sos = new DataOutputStream(client.getOutputStream());
sos.writeUTF("请输入您的用户名:");
name = sis.readUTF();
int i = 1;
for (User c : all) {//遍历容器验证用户名是否存在
if (c.userName.equals(name)) {
sos.writeUTF("用户名已存在!");
break;
}else{
i++;
}
}
if(i > all.size())
flag = false;
}
User user = new User(name, client);
all.add(user);
group("欢迎"+name+"加入聊天!");
} catch (IOException e) {
e.printStackTrace();
}
String msg;
boolean isRunning = true;
//具体操作:转发消息
while(isRunning) {
try {
msg = sis.readUTF();
//转发私聊消息:@xxx:msg
if(msg.startsWith("@")) {
int idx = msg.indexOf(":");
String targetName = msg.substring(1, idx);//获取该条消息所@的用户的用户名
msg = "来自"+name+"的私聊:"+msg.substring(idx+1);
for (User c : all) {//遍历容器找到该条消息所@的用户后转发消息
if (c.userName.equals(targetName)) {
sos = new DataOutputStream(c.userSocket.getOutputStream());
sos.writeUTF(msg);
break;
}
}
//转发公共群聊消息
}else{
msg = (name + ":" + msg);
group(msg);
}
} catch (IOException e) {//客户机断开连接以后会进行以下操作
isRunning = false;//停止对该客户机的转发服务
all.removeIf(c -> c.userSocket == client);//将该客户机从容器中移除
System.out.println("一个客户机断开了连接");
}
}
try {
//释放资源,随后该线程结束
sis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}