一.分析要求
服务器端
1.启动。
2.循环监听客户端是否连接到服务器,如果连接到多个客户端,吧多个客户端的Socket存储起来。
3.每个连接到服务器端的Socket要监听对应的客户端有没有发送消息。
4.一旦对应的客户端发送聊天内容,在服务器端将接受到的消息转发给其他客户端。
5.服务器端应当添加一个控制窗口。
6.点击启动按钮,才能真正启动服务器。
7.点击关闭按钮,可以关闭服务器。
8.应当显示在线人数。
9.管理员可以给群聊中的每个人发送公告。
客户端
1.登录,输入账号。
2.建立客户端与服务器端,连接成功打开聊天窗口。
3.输入聊天内容,点击发送按钮发送内容。
4.接受其他客户端发来的消息。
5.为每一个连接到服务器的Socket创建一个专门用来监听的线程。
6。设置客户退出时,点击关闭按钮时,弹出确认按钮,防止客户误触导致程序关闭。
二.代码实现
客户端
import javafx.event.EventDispatchChain;
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
ArrayList<Socket> sockets=new ArrayList<>();
boolean flag=true;
public void startserver(){
try {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器等待连接");
while(flag){
Socket socket=serverSocket.accept();
System.out.println("客户连接了服务器");
sockets.add(socket);
System.out.println(sockets);
Thread thread = new Thread(new ReceiveThread(socket));
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器的端口号被占用");
}
}
public static void main(String[] args) {
Server server = new Server();
server.startserver();
}
class ReceiveThread extends Thread {
DataInputStream dataInputStream;
Socket socket;
public ReceiveThread(Socket socket) throws IOException {
this.socket = socket;
dataInputStream = new DataInputStream(socket.getInputStream());
}
@Override
public void run() {
while(flag){
try {
String s = dataInputStream.readUTF();
System.out.println(s);
for(Socket sock:sockets){
if(!sock.isClosed()){
DataOutputStream dataOutputStream=new DataOutputStream(sock.getOutputStream());
dataOutputStream.writeUTF(s);
}else
sockets.remove(sock);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("发送失败");
}
}
}
}
}
客户登录端
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.Socket;
public class LoginFrame extends JFrame {
public LoginFrame() throws HeadlessException {
this.setSize(250, 300);
this.setTitle("非凡五组聊天窗口");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
Panel wolcomepanel = new Panel();
Panel idpanel = new Panel();
Panel passwardpanel = new Panel();
Panel dlpanel=new Panel();
Panel panel = new Panel(new GridLayout(4,1));
JLabel wolcomeLabel = new JLabel("欢迎登录");
JLabel idLabel=new JLabel("账号");
JTextField idTextField = new JTextField(15);
JLabel passwardLabel=new JLabel("密码");
JPasswordField jPasswordField = new JPasswordField(15);
JButton jButton1=new JButton("登录");
JButton jButton2=new JButton("注册");
wolcomepanel.add(wolcomeLabel);
idpanel.add(idLabel);
idpanel.add(idTextField);
passwardpanel.add(passwardLabel);
passwardpanel.add(jPasswordField);
dlpanel.add(jButton1);
dlpanel.add(jButton2);
panel.add(wolcomepanel);
panel.add(idpanel);
panel.add(passwardpanel);
panel.add(dlpanel);
this.add(panel);
jButton1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(idTextField.getText().length()==0){
JOptionPane.showMessageDialog(null,"请输入用户名");
return;
}
if(!idTextField.getText().matches("[\\da-zA-Z]*")){
JOptionPane.showMessageDialog(null,"账号只能由数字和字母组成");
return;
}
char[] c=jPasswordField.getPassword();
String s=new String(c);
if(s.length()==0){
JOptionPane.showMessageDialog(null,"请输入密码");
return;
}
try {
//连接服务器
Socket socket=new Socket("127.0.0.1",9999);
//关闭窗口
dispose();
//打开聊天页面
new chat(idTextField.getText(),socket);
} catch (IOException ioException) {
ioException.printStackTrace();
JOptionPane.showMessageDialog(null,"服务器连接失败");
}
}
});
}
public static void main(String[] args) {
LoginFrame dengLuJFrame = new LoginFrame();
dengLuJFrame.setVisible(true);
}
}
客户聊天室
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.net.Socket;
public class chat extends JFrame {
boolean flag=true;
Socket socket;
OutputStream outputStream;
public chat(String name,Socket socket) throws HeadlessException {
this.socket=socket;
this.setSize(400,400);
this.setTitle("欢迎"+name+"来到聊天室");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
Panel panel = new Panel(new BorderLayout());
Panel panel1 = new Panel();
JTextArea jTextArea = new JTextArea();
JScrollPane jScrollPane = new JScrollPane(jTextArea);
JTextArea jTextArea1 = new JTextArea(2,15);
JScrollPane jScrollPane1 = new JScrollPane(jTextArea1);
JButton jButton=new JButton("发送");
panel.add(jScrollPane,BorderLayout.CENTER);
panel1.add(jScrollPane1);
panel1.add(jButton);
panel.add(panel1,BorderLayout.SOUTH);
this.add(panel);
this.setVisible(true);
Receive receive = new Receive();
Thread thread = new Thread(receive);
thread.start();
jButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(jTextArea1.getText().length()==0){
JOptionPane.showMessageDialog(null,"发送内容不能为空");
}
try {
//给服务器发送信息
String s=DateUtil.dateToString("yyyy-MM-dd HH:mm:ss");
String ss=s+"\n"+name+": "+jTextArea1.getText();
outputStream= socket.getOutputStream();
DataOutputStream dataOutputStream=new DataOutputStream(outputStream);
dataOutputStream.writeUTF(ss);
} catch (IOException ioException) {
ioException.printStackTrace();
System.out.println("发送失败");
}
}
});
}
public static void main(String[] args) {
}
class Receive extends Thread{
@Override
public void run() {
//接收服务器的信息
DataInputStream dataInputStream;
while(flag){
try {
dataInputStream = new DataInputStream(socket.getInputStream());
String s1= dataInputStream.readUTF();
System.out.println(s1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
记录发送时间
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
自定义日期工具类
*/
public class DateUtil {
/**
* 将指定的日期转为指定格式的字符串
* @param date
* @param p
* @return
*/
public static String dateToString(Date date,String p){
SimpleDateFormat sdf = new SimpleDateFormat(p);
String str = sdf.format(date);
return str;
}
/**
* 返回当前时间指定格式的字符串
* @param p
* @return
*/
public static String dateToString(String p){
SimpleDateFormat sdf = new SimpleDateFormat(p);
String str = sdf.format(new Date());
return str;
}
public static Date stringToDate(String str,String p) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(p);
return sdf.parse(str);
}
public static void main(String[] args) {
Date d = new Date();
DateUtil.dateToString(d,"YYYY-MM-dd");
try {
Date date = DateUtil.stringToDate("2022-1-1", "yyyy-MM-dd");
System.out.println(date);
//(new Date().getTime() - date.getTime())/1000/3600/24
} catch (ParseException e) {
e.printStackTrace();
}
}
}