目录
需要掌握的知识
TCP通信
Swing界面设计
IO流
多线程
异常
源码
服务端
package com.cww.chatRoomGUI;
import javax.swing.*;
import java.awt.*;
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.*;
/**
* 服务器
*/
public class Server {
private PrintWriter writer;
private BufferedReader reader;
private static List<Socket> socketList = new ArrayList<>();
private static ExecutorService pool = new ThreadPoolExecutor(2, 3, 5, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
private JFrame jFrame = new JFrame("服务器");
private JPanel online = new MyPanel();
private JPanel jPanel = new JPanel();
private JTextArea jTextArea = new JTextArea(20, 50);
Socket socket;
/**
* 显示在线人数
*/
class MyPanel extends JPanel{
@Override
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,600,400);
g.setColor(Color.BLACK);
g.setFont(new Font("宋体",Font.BOLD,20));
g.drawString("当前在线人数:"+socketList.size(),210,30);
}
}
/**
* 初始化各种组件
*/
public void init() {
jTextArea.setLineWrap(true);
jTextArea.setWrapStyleWord(true);
jTextArea.setEditable(false);
JScrollPane jScrollPane = new JScrollPane(jTextArea);
jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jPanel.add(jScrollPane);
online.repaint();
jFrame.add(online);
jFrame.add(jPanel,BorderLayout.SOUTH);
jFrame.setSize(600, 420);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(3);
}
public static void main(String[] args) {
Server s = new Server();
s.init();
s.work();
}
/**
* 建立TCP连接
*/
public void work() {
try {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
socket = serverSocket.accept();
socketList.add(socket);
online.repaint();
jTextArea.append(socket.getRemoteSocketAddress() + "已上线\n");
pool.execute(new ServerRunnable(socket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 开启线程处理消息的输入输出
*/
class ServerRunnable implements Runnable {
private Socket socket;
public ServerRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while ((msg = reader.readLine()) != null) {
sendToAll(msg, socket);
}
} catch (IOException e) {
socketList.remove(socket);
online.repaint();
for (Socket allSocket : socketList) {
try {
writer = new PrintWriter(allSocket.getOutputStream(), true);
writer.println(socket.getRemoteSocketAddress() + "已离线\n");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
jTextArea.append(socket.getRemoteSocketAddress() + "已离线\n");
}
}
private void sendToAll(String msg, Socket socket) throws IOException {
String[] split = socket.getRemoteSocketAddress().toString().split(":");
int port = Integer.valueOf(split[1]);
jTextArea.append(port + ":" + msg + "\n");
for (Socket allSocket : socketList) {
writer = new PrintWriter(allSocket.getOutputStream(), true);
writer.println(port + ":" + msg);
}
}
}
}
客户端
package com.cww.chatRoomGUI;
import javax.swing.*;
import java.io.*;
import java.net.Socket;
import java.util.concurrent.*;
/**
* 客户端
* 注意要编辑配置,打开多个实例,才能实现多开客户端
*/
public class Client {
JFrame jFrame = new JFrame("客户端");
JPanel jPanel = new JPanel();
JTextArea receive = new JTextArea(20, 30);
JTextArea send = new JTextArea(12, 30);
JButton jButton = new JButton("发送");
JScrollPane j1 = new JScrollPane(receive);
JScrollPane j2 = new JScrollPane(send);
PrintWriter writer;
BufferedReader reader;
Socket socket;
private static ExecutorService pool = new ThreadPoolExecutor(2, 3, 5,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public void init() {
receive.setEditable(false);
receive.setWrapStyleWord(true);
receive.setLineWrap(true);
j1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
j1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
send.setWrapStyleWord(true);
send.setLineWrap(true);
j2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
j2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jPanel.add(j1);
jPanel.add(j2);
jPanel.add(jButton);
jFrame.add(jPanel);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(3);
jFrame.setSize(380, 620);
}
/**
* 给发送按钮注册监听
*/
public void actionListener() {
jButton.addActionListener(e -> {
String text = send.getText();
send.setText("");
send.requestFocus();
try {
writer = new PrintWriter(socket.getOutputStream(), true);
writer.println(text);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
);
}
public static void main(String[] args) {
Client c = new Client();
c.init();
c.actionListener();
c.work();
}
/**
* 与服务器建立连接
*/
private void work() {
try {
socket = new Socket("127.0.0.1", 8888);
pool.execute(new ClientRunnable(socket));
} catch (Exception e) {
receive.append("您已与服务器失去连接!\n");
}
}
/**
* 接收服务器传来的消息,并反馈在聊天面版上
*/
class ClientRunnable implements Runnable {
private Socket socket;
public ClientRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while ((msg = reader.readLine()) != null) {
receive.append(msg + "\n");
}
} catch (IOException e) {
receive.append("您已与服务器失去连接!\n");
}
}
}
}
效果展示
服务器接收所有客户端的消息,并显示在线人数
客户端两个文本框,一个接收消息,一个发送消息
显示上下线
注意事项
1.客户端多开需要打开idea的编辑配置-修改选项-实现多个实例。
2.如果需要实现私聊功能,可以在
while ((msg = reader.readLine()) != null) { sendToAll(msg, socket); }里面添加方法,仿造sendTOAll方法实现对单个端口的回复。
如果觉得对您有用,敬请关注!!!