java 聊天室

来源:互联网 发布:有效沟通 知乎 编辑:程序博客网 时间:2024/05/20 19:29

java 聊天室 :在线人员列表显示,广播和私聊,经过测试,还有一点小bug。请多指教了!

package socketForm;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Container;import java.awt.Dimension;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.io.IOException;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;import javax.swing.DefaultListModel;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JList;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.ListSelectionModel;import javax.swing.border.LineBorder;import javax.swing.border.TitledBorder;public class Client extends JFrame implements ActionListener {private static String HOST = "127.0.0.1";private static int PORT = 9090;private JTextField username;private DefaultListModel lm;private JList list;private JTextField msg;private JTextArea allMsg = new JTextArea();private Socket client; // 声明一个客户端的连接private PrintWriter pw;public Client() throws Exception {System.err.println("-----------client-------------");addJMenuBar();username = new JTextField(10);JPanel p = new JPanel();p.add(new JLabel("用户标识:"));p.add(username);JButton conn = new JButton("连接");conn.setActionCommand("c");conn.addActionListener(this);p.add(conn);JButton exitBtn = new JButton("退出");exitBtn.setActionCommand("exit");exitBtn.addActionListener(this);p.add(exitBtn);p.setBorder(new LineBorder(Color.GRAY));// 以下是中间的面板JPanel center = new JPanel(new BorderLayout());lm = new DefaultListModel();list = new JList(lm);lm.addElement("全部");list.setSelectedIndex(0); // 默认选中全部list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);list.setVisibleRowCount(2);JScrollPane jc = new JScrollPane(list);jc.setBorder(new TitledBorder("在线"));jc.setPreferredSize(new Dimension(70, center.getHeight()));center.add(jc, BorderLayout.EAST);JPanel send = new JPanel();send.add(new JLabel("消息:"));msg = new JTextField(20);send.add(msg);JButton sendBtn = new JButton("发送");sendBtn.setActionCommand("send");sendBtn.addActionListener(this);send.add(sendBtn);center.add(send, BorderLayout.SOUTH);allMsg.setEditable(false);center.add(new JScrollPane(allMsg));Container c = getContentPane();// layout 布局位置c.add(p, BorderLayout.NORTH);c.add(center, BorderLayout.CENTER);addWindowListener(new WindowAdapter() { // 当用户退出时,先要通知所有人,有人退出public void windowClosing(WindowEvent arg0) {sendExitMsg();}});setBounds(300, 300, 400, 300);setVisible(true);}public static void main(String[] args) throws Exception {// 提供window装饰// JFrame.setDefaultLookAndFeelDecorated(true);new Client();}@Overridepublic void actionPerformed(ActionEvent e) {if (e.getActionCommand().equals("c")) {System.err.println("连接...");connecting();} else if (e.getActionCommand().equals("send")) {// [1]接受者 [2]content [3] senderString msg = "on@#" + list.getSelectedValue() + "@#"+ this.msg.getText() + "@#" + username.getText();System.err.println(">发出的消息为:" + msg);pw.println(msg);pw.flush();} else if (e.getActionCommand().equals("exit")) { // 用户要退出sendExitMsg();}}private void connecting() {try {System.err.println(HOST + "," + PORT);client = new Socket(HOST, PORT);String userName = this.username.getText(); // 获取用户标识pw = new PrintWriter(client.getOutputStream(), true);pw.println(userName);pw.flush();this.setTitle("用户[" + userName + "]在线...");new ClientThread().start();} catch (Exception e) {e.printStackTrace();}}/** * 添加菜单,控制选项,可以设置服务器及端口号 */private void addJMenuBar() {JMenuBar bar = new JMenuBar();JMenu m = new JMenu("选项");JMenuItem mi = new JMenuItem("设置");JMenuItem help = new JMenuItem("帮助");mi.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {final JDialog set = new JDialog(Client.this, true);set.setBounds(Client.this.getX(), Client.this.getY(), 300, 100);set.setLayout(new FlowLayout());JButton btn = new JButton("设置");final JTextField host = new JTextField(10);host.setText("127.0.0.1");final JTextField port = new JTextField(5);port.setText("9090");btn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Client.HOST = host.getText();Client.PORT = Integer.parseInt(port.getText());System.err.println(Client.HOST);set.dispose();// 关闭且销毁}});set.add(new JLabel("服务器:"));set.add(host);set.add(new JLabel(":"));set.add(port);set.add(btn);set.setVisible(true);}});help.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {JDialog set = new JDialog(Client.this, true);set.setBounds(Client.this.getX(), Client.this.getY(), 300, 100);JLabel jl = new JLabel("版权所有@李杰.2012-3-6,QQ:270819589");set.add(jl);set.setVisible(true);}});bar.add(m);m.add(mi);m.add(help);this.setJMenuBar(bar);}/** * 发送退出的消息 pw client.getOutputStream() */private void sendExitMsg() {if (client == null) {System.exit(0);return;}String msg = "exit@#全部@#null@#" + username.getText();System.err.println("退出:" + msg);pw.println(msg);pw.flush();System.exit(0);}/** * 用以下线程来读取服务器发送来的信息 */class ClientThread extends Thread {public void run() {try {// lm = new DefaultListModel();Scanner sc = new Scanner(client.getInputStream());while (sc.hasNextLine()) {String str = sc.nextLine();System.err.println("客户端接收到的消息 :" + str);String[] msg = str.split("@#");if (msg[0].equals("msg")) { // 开头不是msg就是cmd命令if (msg[1].equals("server")) {str = "[通知]:" + msg[2];} else {str = "[" + msg[1] + "]说:" + msg[2];}allMsg.append("\r\n" + str);} else if (msg[0].equals("cmdAdd")) {// 说明有人登录System.err.println("add------------" + msg[2]);System.err.println(lm.size());lm.addElement(msg[2]);} else if (msg[0].equals("cmdRed")) { // 说明有人退出lm.removeElement(msg[2]);}System.err.println(list);}} catch (IOException e) {e.printStackTrace();}}}}

package socketForm;import java.awt.BorderLayout;import java.awt.Dimension;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyEvent;import java.io.IOException;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import java.util.Scanner;import java.util.Set;import javax.print.attribute.standard.Severity;import javax.swing.DefaultListModel;import javax.swing.JFrame;import javax.swing.JList;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.KeyStroke;import javax.swing.border.TitledBorder;public class Server extends JFrame {private static final int PORT = 9090;private JTextArea area;private DefaultListModel lm;//显示在线人员列表private static Map<String,Object> usersMap = new HashMap<String,Object>();public Server() throws Exception {area = new JTextArea();area.setEditable(true);lm = new DefaultListModel();getContentPane().add(new JScrollPane(area));JList list = new JList(lm);JScrollPane jc = new JScrollPane(list);jc.setPreferredSize(new Dimension(100, this.getHeight()));jc.setBorder(new TitledBorder("在线"));getContentPane().add(jc,BorderLayout.EAST);JMenuBar bar = new JMenuBar();JMenu m = new JMenu("控制");bar.add(m);m.setMnemonic('C');//ALT+C,助记符final JMenuItem run = new JMenuItem("启动");run.setAccelerator(KeyStroke.getKeyStroke('R',KeyEvent.CTRL_MASK));//Server 实现了ActionListener接口,在一个接口中响应不同的button事件,cmd用于区分谁触发的run.setActionCommand("run");m.add(run);m.addSeparator();JMenuItem exit = new JMenuItem("退出");exit.setAccelerator(KeyStroke.getKeyStroke('E',KeyEvent.CTRL_MASK));exit.setActionCommand("exit");m.add(exit);setJMenuBar(bar);ActionListener al = new ActionListener(){//添加一个内部类,以启动服务器public void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("run")){startServer();run.setEnabled(false);}else{System.exit(0);}}};run.addActionListener(al);exit.addActionListener(al);final int winWidth = 500;final int winHeight = 400;java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();//获取屏幕大小int width = (int) toolkit.getScreenSize().getWidth();int height = (int) toolkit.getScreenSize().getHeight();setTitle("这是服务器");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗口显示位置setBounds(width/2-winWidth/2,height/2-winHeight/2,winWidth, winHeight);setVisible(true);//pack();}private void startServer() {try {System.out.println("启动服务...");ServerSocket server = new ServerSocket(PORT);area.append("启动服务:"+server);new ServerThread(server).start();} catch(Exception e) {e.printStackTrace();}}public static void main(String args[]) throws Exception {//JFrame.setDefaultLookAndFeelDecorated(true);new Server();}/* * 一个server线程,负责启动服务器 socket,监听连接 */class ServerThread extends Thread {private ServerSocket server;public ServerThread(ServerSocket server) {this.server = server;}public void run() {try {while(true) {Socket socketClient = server.accept();System.err.println("--------server thread run-------");Scanner sc = new Scanner(socketClient.getInputStream());if(sc.hasNextLine()) {String userName = sc.nextLine();area.append("\r\n用户:["+userName+"]登录,"+socketClient);//增加在线人员 名字lm.addElement(userName);//开启一个客户端线程new ClientThread(socketClient);//更新 已经登录的人  的在线列表,增加当前的这个socket人msgAll(userName);//更新当前登录的人 的在线列表msgSelf(socketClient);//保存 当前的这个 客户端连接usersMap.put(userName,socketClient);}}} catch(Exception e) {e.printStackTrace();}}}/* * 负责与 客户端 交互 */class ClientThread extends Thread {private Socket client;public ClientThread(Socket client) {System.err.println("初始。。。。。。。。。");this.client = client;//构造的时候 就启动start();}public void run() {System.err.println("一个线程启动成功。。。。");try {Scanner sc = new Scanner(client.getInputStream());while(sc.hasNextLine()) {String msg = sc.nextLine();System.err.println(msg);String[] msgs = msg.split("@#");if(msgs[0].equals("exit")) {System.err.println("退出人:"+msg);//usersMap<String,Object>usersMap.remove(msgs[3]);//去掉在线 人姓名 从显示列表中lm.removeElement(msgs[3]);area.append("\r\n用户["+msgs[3]+"] 退出了。");sendExitMsgToAll(msgs);break;} else {sendMsgToSb(msgs); //发消息给某人}}} catch(Exception e) {e.printStackTrace();}}}/** * 通知所有人,有人登录 * 写出信息的类型为: * 类型:通知(cmd)|消息(msg)@#发送者SomeBody@#消息文本MSG */private void msgAll(String userName){/** * Set set = map.entrySet(); * Iterator it = set.iterator(); *  * while(it.hasNext()) * Map.Entry<String,Object> entry = it.next(); *  *  *///Iterator<Object> it = usersMap.values().iterator();Iterator<String> names = usersMap.keySet().iterator();for(Map.Entry<String,Object> entry : usersMap.entrySet()) {//遍历 拿到客户端 各自 的socketSocket s = (Socket) entry.getValue();try {PrintWriter pw = new PrintWriter(s.getOutputStream(),true);String msg = "msg@#server@#用户["+userName+"]登录了.";pw.println(msg);pw.flush();msg = "cmdAdd@#server@#"+userName;pw.println(msg);pw.flush();} catch (IOException e) {e.printStackTrace();}}}/** * 通知   当前登录的人   有多少人在线 * 显示在线用户姓名 */private void msgSelf(Socket client){try{PrintWriter pw = new PrintWriter(client.getOutputStream(),true);Iterator<String> it = usersMap.keySet().iterator();while(it.hasNext()){//key 用户名String msg = "cmdAdd@#server@#"+it.next();pw.println(msg);pw.flush();}}catch(IOException e){e.printStackTrace();}}/** * 发消息给某人 */private void sendMsgToSb(String[] msgs) throws IOException{if(msgs[1].equals("全部")){//发消息给所有人Iterator<String> userNames = usersMap.keySet().iterator();while(userNames.hasNext()){String userName = userNames.next();if(!userName.equals(msgs[3])){//如果不是自己Socket s = (Socket)usersMap.get(userName);PrintWriter pw = new PrintWriter(s.getOutputStream(),true);String str = "msg@#"+msgs[3]+"@#"+msgs[2];pw.println(str);pw.flush();}}}else{Socket s = (Socket)usersMap.get(msgs[1]);PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//msg[3]---username msg[2]----contentString str = "msg@#"+msgs[3]+"@#"+msgs[2];pw.println(str);pw.flush();}}/** * 通知所有人有人退出 */private void sendExitMsgToAll(String[] msgs) throws IOException{Iterator<String> userNames = usersMap.keySet().iterator();while(userNames.hasNext()){String userName = userNames.next();//拿到用户名对应的socketSocket s = (Socket)usersMap.get(userName);PrintWriter pw = new PrintWriter(s.getOutputStream(),true);String str = "msg@#server@#用户["+msgs[3]+"]退出了。";pw.println(str);pw.flush();str = "cmdRed@#server@#"+msgs[3];pw.println(str);pw.flush();}}}


原创粉丝点击