1,好友聊天模式

1.1,简介

思想:服务器开启ServerSocket等待客户端连接,获取双方的输入输出流,之后进入while循环,不断的接收来自客户端的消息(消息由客户端发送到内存,服务器从内存中获取信息,每次获取完,服务器处于等待状态,类似于消费者等待生产者,处于while中。)客户端同样等待服务器发送的消息,通过Button按钮发送到内存消息。

流程图:

java开源聊天系统 java 聊天系统_java

java开源聊天系统 java 聊天系统_java开源聊天系统_02

效果图:

java开源聊天系统 java 聊天系统_开发语言_03

java开源聊天系统 java 聊天系统_开发语言_04

1.2,界面代码

服务器端代码

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class qqinpage extends JFrame {
    private JLabel ipLabel, userLabel, serverLabel, meanLabel;
    private JButton inButton, outButton;
    private JTextField userField, serverField;
    private JRadioButton meanButton, mean2Button;
    private JPanel ipPanel, userPanel, serverPanel, meanPanel, lastPanel;
    private JPasswordField ipField;

    public qqinpage() {
        userLabel = new JLabel("请 输 入 管 理 员 用 户 名:");
        ipLabel = new JLabel("请  输  入  管 理 员 密  码:");
        serverLabel = new JLabel("请输入你 要开放的 端 口:");
        meanLabel = new JLabel("聊    天    方    式:");

        inButton = new JButton("开启服务器");
        outButton = new JButton("退出");
        meanButton = new JRadioButton("双人");
        mean2Button = new JRadioButton("多人");
        ButtonGroup bg = new ButtonGroup();
        bg.add(meanButton);
        bg.add(mean2Button);
        meanButton.setSelected(true);
        ipField = new JPasswordField(20);
        userField = new JTextField(20);
        serverField = new JTextField(20);

        userPanel = new JPanel(new FlowLayout());
        serverPanel = new JPanel(new FlowLayout());
        meanPanel = new JPanel(new FlowLayout());
        lastPanel = new JPanel(new FlowLayout());
        ipPanel = new JPanel(new FlowLayout());

        userPanel.add(userLabel);
        userPanel.add(userField);
        serverPanel.add(serverLabel);
        serverPanel.add(serverField);
        meanPanel.add(meanLabel);
        meanPanel.add(meanButton);
        meanPanel.add(mean2Button);
        lastPanel.add(inButton);
        lastPanel.add(outButton);
        ipPanel.add(ipLabel);
        ipPanel.add(ipField);
        addListener();

        Container container = getContentPane();
        container.setLayout(new GridLayout(5, 1));
        container.add(userPanel);
        container.add(ipPanel);
        container.add(serverPanel);
        container.add(meanPanel);
        container.add(lastPanel);

        setBounds(600, 200, 500, 250);
        setTitle("管理员登录");
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void addListener() {
        outButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        inButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (userField.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "请输入用户名", "提示", JOptionPane.INFORMATION_MESSAGE);
                } else if (ipField.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "请输入用户名", "提示", JOptionPane.INFORMATION_MESSAGE);
                } else if (!meanButton.isSelected() && !mean2Button.isSelected()) {
                    JOptionPane.showMessageDialog(null, "请选择聊天方式", "提示", JOptionPane.INFORMATION_MESSAGE);
                } else if (userField.getText().equals("root") && ipField.getText().equals("123456")) {
                    if (mean2Button.isSelected()) {
                        dispose();
                        new Server(Integer.parseInt(serverField.getText()));
                    } else {
                        dispose();
                        JOptionPane.showMessageDialog(null, "服务器已打开", "提示", JOptionPane.INFORMATION_MESSAGE);
                        new ServerTPC(Integer.parseInt(serverField.getText()));
                    }

                } else {
                    JOptionPane.showMessageDialog(null, "密码错误\n程序退出", "提示", JOptionPane.INFORMATION_MESSAGE);
                    System.exit(1);
                }
            }

        });
    }

    public static void main(String[] args) {
        qqinpage a = new qqinpage();
        a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}

客户端代码 

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class qqinpage2 extends JFrame {
	private JLabel ipLabel, userLabel, serverLabel, meanLabel;
	private JButton inButton, outButton;
	private JTextField ipField, userField, serverField;
	private JRadioButton meanButton, mean2Button;
	private JPanel ipPanel, userPanel, serverPanel, meanPanel, lastPanel;

	public qqinpage2() {
		ipLabel = new JLabel("请输入你要连入的IP地址:");
		userLabel = new JLabel("请  输  入  你  的  用 户 名:");
		serverLabel = new JLabel("请输入你 要接入的 端 口:");
		meanLabel = new JLabel("请选择你需要的聊天方式:");

		inButton = new JButton("连接");
		outButton = new JButton("退出");
		meanButton = new JRadioButton("双人");
		mean2Button = new JRadioButton("多人");
		ButtonGroup bg = new ButtonGroup();
		bg.add(meanButton);
		bg.add(mean2Button);
		meanButton.setSelected(true);

		ipField = new JTextField(20);
		ipField.setText("127.0.0.1");
		userField = new JTextField(20);
		serverField = new JTextField(20);

		ipPanel = new JPanel(new FlowLayout());
		userPanel = new JPanel(new FlowLayout());
		serverPanel = new JPanel(new FlowLayout());
		meanPanel = new JPanel(new FlowLayout());
		lastPanel = new JPanel(new FlowLayout());

		ipPanel.add(ipLabel);
		ipPanel.add(ipField);
		userPanel.add(userLabel);
		userPanel.add(userField);
		serverPanel.add(serverLabel);
		serverPanel.add(serverField);
		meanPanel.add(meanLabel);
		meanPanel.add(meanButton);
		meanPanel.add(mean2Button);
		lastPanel.add(inButton);
		lastPanel.add(outButton);
		addListener();

		Container container = getContentPane();
		container.setLayout(new GridLayout(5, 1));
		container.add(ipPanel);
		container.add(userPanel);
		container.add(serverPanel);
		container.add(meanPanel);
		container.add(lastPanel);
		setBounds(600, 200, 500, 250);
		setTitle("客户端");
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	private void addListener() {
		outButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		inButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (ipField.getText().equals("")) {
					JOptionPane.showMessageDialog(null, "请输入ip", "提示", JOptionPane.INFORMATION_MESSAGE);
				} else if (userField.getText().equals("")) {
					JOptionPane.showMessageDialog(null, "请输入用户名", "提示", JOptionPane.INFORMATION_MESSAGE);
				} else if (!meanButton.isSelected() && !mean2Button.isSelected()) {
					JOptionPane.showMessageDialog(null, "请选择聊天方式", "提示", JOptionPane.INFORMATION_MESSAGE);
				} else if (serverField.getText().equals("")) {
					JOptionPane.showMessageDialog(null, "请输入接口", "提示", JOptionPane.INFORMATION_MESSAGE);
				} else if (mean2Button.isSelected()) {
					dispose();
					new ClientFrame(userField.getText(), ipField.getText(), Integer.parseInt(serverField.getText()));
				} else if (meanButton.isSelected()) {
					dispose();
					new ClientTPC(userField.getText(), ipField.getText(), Integer.parseInt(serverField.getText()));
				}
			}
		});
	}

	public static void main(String[] args) {
		qqinpage2 a = new qqinpage2();
		a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

}

1.3,后台代码

import java.io.*;

import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ServerTPC extends JFrame {
	private JTextField enterField;
	private JTextArea displayArea;
	private ObjectOutputStream output;
	private ObjectInputStream input;
	private ServerSocket server;
	private Socket connection;
	private JButton but;
	private JPanel panel;
	public ServerTPC(int i) {
		super("管理员");
		panel = new JPanel(new FlowLayout());
		but = new JButton("发送");
		Container container = getContentPane();
		enterField = new JTextField(20);
		enterField.setEditable(false);
		enterField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendData(e.getActionCommand());
				enterField.setText("");
			}
		});
		but.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendData(e.getActionCommand());
				enterField.setText("");
			}
		});
		try {
			server = new ServerSocket(i, 100);
		} catch (IOException e1) {
			JOptionPane.showMessageDialog(null, "端口被占用请 重新选择", "提示", JOptionPane.INFORMATION_MESSAGE);
		}
		panel.add(enterField);
		panel.add(but);
		container.add(panel, BorderLayout.SOUTH);
		displayArea = new JTextArea();
		displayArea.setEditable(false);

		container.add(new JScrollPane(displayArea), BorderLayout.CENTER);
		setBounds(600, 200, 500, 250);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		Thread a = new Thread(new Roll());
		a.start();
	}

	private void waitForConnection() throws IOException {
		displayMessage("等待用户接入");
		connection = server.accept();
	}

	private void getStreams() throws IOException {
		output = new ObjectOutputStream(connection.getOutputStream());
		output.flush();
		input = new ObjectInputStream(connection.getInputStream());
	}

	private void processConnection() throws IOException {
		String message = "连接成功";
		sendData(message);
		setTextFieldEditable(true);
		try {
			do {
				message = (String) input.readObject();
				displayMessage("\n" + message);
			} while (true);
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "好友已下线", "提示", JOptionPane.INFORMATION_MESSAGE);
		}
	}
	
	private void closeConnection() {
		displayMessage("对话结束\n");
		setTextFieldEditable(false);
		try {
			output.close();
			input.close();
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void sendData(String message) {
		try {
			Date date = new Date();
			SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
			output.writeObject("管理员:" + sf.format(date) + "\n" + message);
			output.flush();
			displayMessage("\n管理员:" + sf.format(date) + "\n" + message);
		} catch (Exception e) {
			displayArea.append("\n发生错误");
		}
	}

	private void displayMessage(final String messageToDisplay) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				displayArea.append(messageToDisplay);
				displayArea.setCaretPosition(displayArea.getText().length());
			}
		});
	}

	private void setTextFieldEditable(final boolean editable) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				enterField.setEditable(editable);
			}
		});
	}

	class Roll implements Runnable {
		public void run() {
			try {
				while (true) {
					try {
						waitForConnection();
						getStreams();
						processConnection();
					} catch (EOFException e) {
						System.out.println("这里发生了错误请及时修复");
					} finally {
						closeConnection();
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ClientTPC extends JFrame{
	private JTextField enterField;
	private JTextArea displayArea;
	private ObjectOutputStream output;
	private ObjectInputStream input;
	private String message="";
	private String chatServer,userName;
	private Socket client;
	private JButton but;
	private JPanel panel;
	private int server;
	public ClientTPC(String username,String ip,int i) {
		super("客户");
		but=new JButton("发送");
		panel=new JPanel(new FlowLayout());
		chatServer=ip;
		server=i;
		userName=username;
		Container c=getContentPane();
		enterField=new JTextField(20);
		enterField.setEditable(false);
		enterField.addActionListener(
				new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						sendData(e.getActionCommand());
						enterField.setText( "" );
					}
				});
		panel.add(enterField);
		panel.add(but);
		c.add(panel,BorderLayout.SOUTH);
		displayArea=new JTextArea();
		displayArea.setEditable(false);
		c.add(new JScrollPane(displayArea),BorderLayout.CENTER);
		setBounds(600, 200, 500, 250);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		Thread a=new Thread(new Roll());
		a.start();
	}

	private void connectionToServer() throws IOException{
		displayMessage("尝试连接");
		client=new Socket(InetAddress.getByName(chatServer),server);
	}
	private void getStreams() throws IOException{
		output=new ObjectOutputStream(client.getOutputStream());
		output.flush();
		input=new ObjectInputStream(client.getInputStream());
	}
	private void processConnection()throws IOException{
		setTextFieldEditable(true);
		try {
			do {
				message=(String)input.readObject();
				displayMessage("\n"+message);
			} while (true);
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "服务器已关闭", "提示", JOptionPane.INFORMATION_MESSAGE);
		}
	}
	private void closeConnection() { 
		displayMessage("\n断开连接");
		setTextFieldEditable(false);
		try {
			output.close();
			input.close();
			client.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private void sendData(String message) {
		try {
			Date date = new Date();
			SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
			output.writeObject(userName+":"+sf.format(date)+"\n"+message);
			output.flush();
			displayMessage("\n"+userName+":"+sf.format(date)+"\n"+message);
		} catch (Exception e) {
			displayArea.append("\n发生了错误");
		}
	}
	private void displayMessage(final String messageToDisplay) {
		SwingUtilities.invokeLater(
				new Runnable() {
					public void run() {
						displayArea.append(messageToDisplay);
						displayArea.setCaretPosition(displayArea.getText().length());
					}
				});
	}
	private void setTextFieldEditable(final boolean editable) {
		SwingUtilities.invokeLater(
				new Runnable() {
					public void run() {
						enterField.setEditable(editable);
					}
				});
	}
	class Roll implements Runnable{
		public void run() {
			try {
				connectionToServer();
				getStreams();
				processConnection();
			} catch (EOFException e1) {
				System.out.println("客户断开连接");
			} catch(IOException e2) {
				e2.printStackTrace();
			} finally {
				closeConnection();
			}
		}
	}
}

2,多人聊天模式

2.1,简介

思想:服务器作为一个独立线程,开启ServerSocket,通过while循环,不断的等待用户接入,每接入一个用户将它的socket放入HashSet,HashSet中的所有socket即是我们的用户。服务器开启子线程,传入新的socket对象,子线程run方法中获取输入流,通过while循环读取消息并发送给所有的socket。

流程图:

java开源聊天系统 java 聊天系统_java开源聊天系统_05

java开源聊天系统 java 聊天系统_开发语言_06

效果图:

java开源聊天系统 java 聊天系统_服务器_07

java开源聊天系统 java 聊天系统_开发语言_08

2.2,后台逻辑代码

前端代码同1.2

服务端代码

import java.io.*;

import java.net.*;
import java.util.*;

import javax.swing.JOptionPane;

public class Server {
    private ServerSocket serverSocket;
    private HashSet<Socket> allSockets;

    public Server(int i) {
        try {
            serverSocket = new ServerSocket(i);
            JOptionPane.showMessageDialog(null, "服务器已启动\n请运行客户端", "提示", JOptionPane.INFORMATION_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
        }
        allSockets = new HashSet<Socket>();
        try {
            startService();
        } catch (IOException e) {
            System.out.println("错误");
        }
    }

    public void startService() throws IOException {
        while (true) {
            Socket s = serverSocket.accept();
            System.out.println("用户已进入聊天室");
            allSockets.add(s);
            new ServerThread(s).start();
        }
    }

    private class ServerThread extends Thread {
        Socket socket;

        public ServerThread(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (true) {
                    String str = br.readLine();
                    sendMessageTOAllClient(str);
                }
            } catch (Exception e) {
                System.out.println("用户退出聊天室");
            }
        }

        public void sendMessageTOAllClient(String message) throws IOException {
            for (Socket s : allSockets) {
                PrintWriter pw = new PrintWriter(s.getOutputStream());
                pw.println(message);
                pw.flush();
            }
        }
    }

}

客户端代码

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.*;
import javax.swing.border.EmptyBorder;

import javafx.scene.control.ScrollPane;

public class ClientFrame extends JFrame {
	private JPanel contentPane,panel;
	private JTextField tfMessage;
	private JButton btnSend;
	private JTextArea textArea;
	private String userName;
	private ChatRoomClient client;
	public ClientFrame(String userName,String ip,int i) {
		textArea=new JTextArea(10,10);
		textArea.setEditable(false);
		tfMessage =new JTextField(20);
		btnSend = new JButton("发送");
		try {
			client = new ChatRoomClient(ip, i);
			textArea.setText("连接成功\n");
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e2) {
			e2.printStackTrace();
		}
		setTitle("客户端");
		tfMessage.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Date date = new Date();
				SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
				client.sendMessage(userName + ":" + sf.format(date) + ":\n" + tfMessage.getText());
				tfMessage.setText("");
			}
		});
		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Date date = new Date();
				SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
				client.sendMessage(userName + ":" + sf.format(date) + ":\n" + tfMessage.getText());
				tfMessage.setText("");
			}
		});
		
		this.userName = userName;
		ReadMessageThread messageThread = new ReadMessageThread();
		messageThread.start();	
		
		Container c=getContentPane();
		contentPane = new JPanel();
		contentPane.setLayout(new BorderLayout());
		panel = new JPanel();
		panel.setLayout(new FlowLayout());
		
		contentPane.add(new JScrollPane(textArea),BorderLayout.CENTER);
		panel.add(tfMessage);
		panel.add(btnSend);
		contentPane.add(panel,BorderLayout.SOUTH);
		c.add(contentPane);
		
		setBounds(100, 100, 450, 300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		
	}
	private class ReadMessageThread extends Thread {
		public void run() {
			while (true) {
				String str = client.reciveMessage();
				textArea.append(str + "\n");
			}
		}
	}

}import java.io.*;
import java.net.*;

public class ChatRoomClient {
	private Socket socket;
	private BufferedReader bufferReader;
	private PrintWriter pWriter;

	public ChatRoomClient(String host, int port) throws UnknownHostException, IOException {
		socket = new Socket(host, port);
		bufferReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		pWriter = new PrintWriter(socket.getOutputStream());
	}

	public void sendMessage(String str) {
		pWriter.println(str);
		pWriter.flush();
	}

	public String reciveMessage() {
		try {
			return bufferReader.readLine();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public void close() {
		try {
			socket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}