package com.socketForm;
import java.awt.BorderLayout;
import java.awt.Dimension;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyEvent;import java.io.IOError;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.Scanner;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.JSplitPane;import javax.swing.JTextArea;import javax.swing.KeyStroke;import javax.swing.ListModel;import javax.swing.border.TitledBorder;/** * 聊天程序服务器窗口 * dingzhen * 2016-03-09 */public class ServerForm extends JFrame{ private static final long serialVersionUID = 1L; private static final int PORT = 9090; //端口号 private JTextArea area; //用户放用户信息的显示区 private DefaultListModel lm; //列表对像,用户保存用户登录信息 private Map<String,Object> usersMap = new HashMap<String, Object>(); //保存所有在线用户的名称和Socket public ServerForm() throws Exception{ area = new JTextArea(); area.setEditable(false); 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'); final JMenuItem run = new JMenuItem("开启"); run.setAccelerator(KeyStroke.getKeyStroke('R',KeyEvent.CTRL_MASK)); //设置快捷键 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; Toolkit toolkit = 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); } public static void main(String[] args) throws Exception { JFrame.setDefaultLookAndFeelDecorated(true); new ServerForm(); } /** * 启动服务器 */ public void startServer(){ try{ System.err.println("启动服务..."); ServerSocket server = new ServerSocket(PORT); area.append("启动服务:"+server); new ServerThread(server).start(); }catch(Exception e){ e.printStackTrace(); } } /** * 启动服务的线程 */ class ServerThread extends Thread{ private ServerSocket server; public ServerThread(ServerSocket server) { this.server = server; } public void run() { try{ while(true){ Socket socketClient = server.accept(); //等待获取客户端的连接 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); //启动这个线程 msgAll(userName); //通知所有人有人登录 msgSelf(socketClient); //通知当前登录的人,有多少人在线 usersMap.put(userName,socketClient); System.err.println("一个线程已经启动...."); } } }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("退出人:"+msgs[3]); //还要通知甩有人有人退出,并删除所有人列表中的自己 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){ try{ Iterator<Object> it = usersMap.values().iterator(); while(it.hasNext()){ Socket s = (Socket)it.next(); try{ PrintWriter pw = new PrintWriter(s.getOutputStream(),true); String msg = "@#用户["+userName+"]登录了."; pw.println(msg); pw.flush(); msg = "; pw.println(msg); pw.flush(); }catch(IOException e){ e.printStackTrace(); } } }catch(Exception 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()){ String msg = "(); pw.println(msg); } }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 = "]; pw.println(str); pw.flush(); } } }else{ Socket s = (Socket)usersMap.get(msgs[1]); PrintWriter pw = new PrintWriter(s.getOutputStream(),true); String str = "]; 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(); Socket s = (Socket)usersMap.get(userName); PrintWriter pw = new PrintWriter(s.getOutputStream(),true); String str = "@#用户["+msgs[3]+"]退出了。"; pw.println(str); pw.flush(); str = "]; pw.println(str); pw.flush(); } }}
package com.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;/** * 客户端程序 * @author dingzhen * @version 2016-03-09 */public class ClientForm extends JFrame implements ActionListener{ private static final long serialVersionUID = 1L; 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(); //收消息框 public ClientForm() throws Exception { 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(); 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 { JFrame.setDefaultLookAndFeelDecorated(true); new ClientForm(); } public void actionPerformed(ActionEvent e) { if(e.getActionCommand().equals("c")){ System.err.println("连接..."); connecting(); }else if(e.getActionCommand().equals("send")){ String msg = "(); System.err.println(">发出的消息为:"+msg); pw.println(msg); pw.flush(); }else if(e.getActionCommand().equals("exit")){ //用户要退出 sendExitMsg(); } } /** * 发送退出的消息 */ 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); } /** * 创建一个用户连接 */ private Socket client; //声明一个客户端的连接 private PrintWriter pw; 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); this.setTitle("用户["+userName+"]在线..."); new ClientThread().start(); }catch(Exception e){ e.printStackTrace(); } } /** * 用以下线程来读取服务器发送来的信息 */ class ClientThread extends Thread{ public void run() { try{ 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")){ //说明有人登录 lm.addElement(msg[2]); }else if(msg[0].equals("cmdRed")){ //说明有人退出 lm.removeElement(msg[2]); } } }catch(IOException 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() { public void actionPerformed(ActionEvent arg0) { final JDialog set = new JDialog(ClientForm.this,true); set.setBounds(ClientForm.this.getX(),ClientForm.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() { public void actionPerformed(ActionEvent arg0) { ClientForm.HOST = host.getText(); ClientForm.PORT = Integer.parseInt(port.getText()); System.err.println(ClientForm.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(ClientForm.this,true); set.setBounds(ClientForm.this.getX(),ClientForm.this.getY(), 300, 100); JLabel jl = new JLabel("版权所有@dingzhen 2016-03-09"); set.add(jl); set.setVisible(true); } }); bar.add(m); m.add(mi); m.add(help); this.setJMenuBar(bar); }}