java 基于TCP/IP协议的局域网聊天小程序

有6个模块

1.用户登录

2.两两私聊

3.群发消息

4.退出登录

5.关闭服务器

6.文件传输

一、用户登录
客户端:
1、发送登录信息:LOGIN|Username
处理USERLISTS命令:所有在线用户的用户名
2、处理新上线用户信息:ADD|username

服务器端:
1、得到所有在线用户信息名称,发回给客户端:USERLISTS|user1_user2_user3
2、将当前登录的Socket信息放入Arraylist中
3、将当前登录用户的信息(用户名),发送给已经在线的其他用户:ADD|userName

二、两两私聊
客户端:
1、选择用户
2、组织一个交互协议,发送到服务器:MSG|SenderName|RecName|MSGInfo
3、接收服务器转发回的消息
服务器端:
1、通过RecName用户名查找,找到目标SocketChat
2、向目标对象发送消息:MSG|SenderName|MSGInfo

三、群聊
MSG|Sendername|ALL|MSGInfo

四、用户退出连接
客户端:
1、向服务器发送下线消息:OFFLINE|username
2、关闭ClientChat,清空在线用户列表

3、处理下线用户信息:DEL|username
删除用户列表中的username

服务器端:
1、处理OFFLINE
2、向所有的其他在线用户发送用户下线消息:DEL|username
3、清除ArrayList中的当前用户信息(socketChat)

五、服务器关闭
  客户端:
1、处理CLOSE命令:界面显示服务器关闭

2、关闭ClientChat
3、清空在线用户列表


服务器端:
1、向所有在线用户发送关闭服务器的信息:CLOSE

2、遍历Arraylist将其中的每一个SocketChat关闭
3、ArrayList要清空
4、关闭SokcetListener
5、关闭ServerSocket

 六、文件传输

客户端:
准备工作:1,2,3
//1从本地选中一个文件,获取其文件相关信息(文件名,文件长度)

//2创建文件传输的服务器,与服务器接通

//3组织文件传输交互协议进行传输

//FILETRANS|sendername|recname|文件名|文件长度|IP|Port

处理服务器转发的内容,处理该内容确认是接收还是拒收,如果接收,建立连接通道接收文件(即开启fileRec线程)
如果拒收,组织拒收交互协议(FILECANCEL|拒收者|被拒收者)发送给服务器

服务器端:

接收发来的消息串,提取发送者+接收者+发送内容+传送文件的IP和Port 进行转发

服务器收到交互协议:FILECANCEL|拒收者|被拒收者 重新组织交互协议FILECANCELReturn|拒收者 要通知被拒收者,被拒收的消息

群发的流程图比较简单就没有画

六、文件传输

 


以下代码只需修改以下IP地址和端口号即可运行,后期准备对发送消息的内容进行加密用Base64加密方法加密

客户端代码:
package rjxy.lkl.Client;

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

public class ClientChat extends Thread {

    Socket socket;
    BufferedReader br = null;
    PrintWriter pw = null;
    String UserName;

    public ClientChat(Socket socket, String userName) {
        this.socket = socket;
        UserName = userName;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream(),
                    "UTF-8"));
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream(), "UTF-8")));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        //约定一个登录的交互协议Login|username
        sendMSG("Login|"+UserName);
    }
    public void sendMSG(String str){
        pw.println(str);
        pw.flush();
    }
    //断开socket连接
    public void closeChat(){
        try {
            if(socket!=null) socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //处理服务器发过来的在线用户List ,交互协议为:USERLISTS|user1_user2_user3
    public void run() {
        try {
            String str = "";
            while((str = br.readLine())!=null){
                System.out.println("---"+str+"---");
                String comms[] = str.split("[|]");
                if(comms[0].equals("USERLISTS")){
                    String users[] = comms[1].split("_");
                    ClientMG.getClientMG().addItems(users);
                } else if(comms[0].equals("ADD")){
                    ClientMG.getClientMG().addItem(comms[1]);
                } else if(comms[0].equals("MsgReturn")){
                    //"MsgReturn|"+sender+"|"+msg
                    String sender = comms[1];
                    String msg = comms[2];
                    ClientMG.getClientMG().setLog("【"+sender+"】:");
                    ClientMG.getClientMG().setLog(msg);
                } else if(comms[0].equals("DEL")){
                    //交互协议为:"DEL|"+UserName
                    String sUser = comms[1];
                    ClientMG.getClientMG().removeItem(sUser);
                    ClientMG.getClientMG().setLog(sUser+"已下线");
                } else if(comms[0].equals("CLOSE")){
                    ClientMG.getClientMG().setLog("服务器已关闭");
                    //关闭ClientChat
                    ClientMG.getClientMG().getClientChat().closeChat();
                    //清空在线用户列表
                    ClientMG.getClientMG().clearItems();
                } else if(comms[0].equals("FILETRANS")){
                    //"FILETRANS|"+sender+"|"+sFname+"|"+finfo.length()+"|"+IP+"|"+Port
                    String sender = comms[1];
                    String fileName = comms[2];
                    int filelen = Integer.parseInt(comms[3]);
                    String sIP = comms[4];
                    int port = Integer.parseInt(comms[5]);
                    //调用ClientMG中的接收文件的方法
                    ClientMG.getClientMG().recFile(sender, fileName, filelen, sIP, port);
                    
                } else if(comms[0].equals("FILECANCEL")){
                    ClientMG.getClientMG().cancelFileTrans();
                } else if (comms[0].equals("FILECANCELReturn")){
                    //FILECANCELReturn|拒收者A
                    ClientMG.getClientMG().setLog(comms[1]+"取消了传输。。。");
                }
                
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (br != null)
                    br.close();
                if (pw != null)
                    pw.close();
                if (socket != null)
                    socket.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
package rjxy.lkl.Client;

import java.awt.BorderLayout;

public class ClientForm extends JFrame {

    private JPanel contentPane;
    public JPanel panel;
    public JLabel lblIp;
    public JTextField txtIP;
    public JLabel label_1;
    public JTextField txtPort;
    public JButton btnLogin;
    public JButton btnExit;
    public JPanel panel_1;
    public JButton btnSend;

    Socket socket;    
    BufferedReader br=null;
    PrintWriter pw=null;
    public JScrollPane scrollPane;
    public JTextArea txtLog;
    public JScrollPane scrollPane_1;
    public JTextArea txtSend;
    public JLabel label;
    public JTextField txtUser;
    public JScrollPane scrollPane_2;
    public JList lOnlines;
    
    DefaultListModel<String> items=new DefaultListModel<String>();
    public JButton sendToAll;
    public JButton FileTranbutton;
    public JProgressBar FileprogressBar;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ClientForm frame = new ClientForm();
                    frame.setVisible(true);
                    ClientMG.getClientMG().setClientForm(frame);
                    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public ClientForm() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 513, 583);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
        
        panel = new JPanel();
        panel.setLayout(null);
        panel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "u767Bu5F55u4FE1u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panel.setBounds(11, 10, 476, 64);
        contentPane.add(panel);
        
        lblIp = new JLabel("IP:");
        lblIp.setHorizontalAlignment(SwingConstants.RIGHT);
        lblIp.setBounds(10, 19, 35, 31);
        panel.add(lblIp);
        
        txtIP = new JTextField();
        txtIP.setText("10.12.50.10");
        txtIP.setColumns(10);
        txtIP.setBounds(55, 22, 97, 24);
        panel.add(txtIP);
        
        label_1 = new JLabel("u7AEFu53E3:");
        label_1.setHorizontalAlignment(SwingConstants.RIGHT);
        label_1.setBounds(154, 19, 35, 31);
        panel.add(label_1);
        
        txtPort = new JTextField();
        txtPort.setText("8899");
        txtPort.setColumns(10);
        txtPort.setBounds(190, 21, 35, 26);
        panel.add(txtPort);
        
        btnLogin = new JButton("u767Bu5F55");
        btnLogin.addActionListener(new BtnLoginActionListener());
        btnLogin.setBounds(337, 22, 65, 25);
        panel.add(btnLogin);
        
        btnExit = new JButton("u9000u51FA");
        btnExit.addActionListener(new BtnExitActionListener());
        btnExit.setBounds(401, 22, 65, 25);
        panel.add(btnExit);
        
        label = new JLabel("u7528u6237u540D:");
        label.setHorizontalAlignment(SwingConstants.RIGHT);
        label.setBounds(228, 19, 50, 31);
        panel.add(label);
        
        txtUser = new JTextField();
        txtUser.setText("visiter");
        txtUser.setColumns(10);
        txtUser.setBounds(281, 22, 50, 26);
        panel.add(txtUser);
        
        panel_1 = new JPanel();
        panel_1.setLayout(null);
        panel_1.setBorder(new TitledBorder(new LineBorder(new Color(184, 207, 229)), "u64CDu4F5C", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panel_1.setBounds(10, 414, 477, 121);
        contentPane.add(panel_1);
        
        btnSend = new JButton("u53D1u9001u6D88u606F");
        btnSend.addActionListener(new BtnSendActionListener());
        btnSend.setBounds(357, 82, 110, 23);
        panel_1.add(btnSend);
        
        scrollPane_1 = new JScrollPane();
        scrollPane_1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane_1.setBounds(10, 24, 457, 48);
        panel_1.add(scrollPane_1);
        
        txtSend = new JTextArea();
        scrollPane_1.setViewportView(txtSend);
        
        sendToAll = new JButton("u7FA4u53D1u6D88u606F");
        sendToAll.addActionListener(new ButtonActionListener());
        sendToAll.setBounds(254, 82, 93, 23);
        panel_1.add(sendToAll);
        
        FileTranbutton = new JButton("u4F20u8F93u6587u4EF6");
        FileTranbutton.addActionListener(new ButtonActionListener_1());
        FileTranbutton.setBounds(10, 82, 81, 23);
        panel_1.add(FileTranbutton);
        
        FileprogressBar = new JProgressBar();
        FileprogressBar.setBounds(98, 92, 146, 8);
        panel_1.add(FileprogressBar);
        
        scrollPane = new JScrollPane();
        scrollPane.setBorder(new TitledBorder(null, "u804Au5929u8BB0u5F55", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        scrollPane.setBounds(11, 84, 309, 332);
        contentPane.add(scrollPane);
        
        txtLog = new JTextArea();
        scrollPane.setViewportView(txtLog);
        
        scrollPane_2 = new JScrollPane();
        scrollPane_2.setBorder(new TitledBorder(null, "u5728u7EBFu7528u6237", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        scrollPane_2.setBounds(323, 83, 164, 332);
        contentPane.add(scrollPane_2);
        
        lOnlines = new JList(items);
        scrollPane_2.setViewportView(lOnlines);
    }
    //登录
    private class BtnLoginActionListener implements ActionListener {
        public void actionPerformed(ActionEvent arg0) {
            String ip = txtIP.getText().trim();
            int port = Integer.parseInt(txtPort.getText().trim());
            String socketname = txtUser.getText().trim();
            ClientMG.getClientMG().connect(ip, port, socketname);
        }
    }
    //发送信息
    private class BtnSendActionListener implements ActionListener {
        public void actionPerformed(ActionEvent arg0) {
            //选中要聊天的用户
            String sendUsername = null;
            if(lOnlines.getSelectedIndex()>=0){
                //得到用户选择的名称
                String targetUsername = lOnlines.getSelectedValue().toString();
                System.out.println(targetUsername);
                //发送者的名称
                sendUsername = txtUser.getText().trim();
                //消息体
                String sMSG = txtSend.getText();
                //交互协议 "MSG|"+sendUsername+"|"+targetUsername+"|"+sMSG
                //包装后的消息发送出去
                String strSend = "MSG|"+sendUsername+"|"+targetUsername+"|"+sMSG;
                System.out.println(strSend);
                ClientMG.getClientMG().getClientChat().sendMSG(strSend);
                ClientMG.getClientMG().setLog("I send To "+targetUsername+":");
                ClientMG.getClientMG().setLog(sMSG);
                //清空发送消息框
                txtSend.setText("");
            }
            
        }
    }
    //推出操作
    private class BtnExitActionListener implements ActionListener {
        public void actionPerformed(ActionEvent arg0) {
            //组织推出交互协议"OFFLINE|"+username
            String sendMSG = "OFFLINE|"+txtUser.getText().trim();
            ClientMG.getClientMG().getClientChat().sendMSG(sendMSG);
            //断开与服务器的socket连接
            ClientMG.getClientMG().getClientChat().closeChat();
            ClientMG.getClientMG().clearItems();  //清空列表
            
        }
    }
    private class ButtonActionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            //发送者的名称
            String sendUsername = txtUser.getText().trim();
            //消息体
            String sMSG = txtSend.getText();
            //交互协议 "MSG|"+sendUsername+"|"+targetUsername+"|"+sMSG
            //包装后的消息发送出去
            String strSend = "MSG|"+sendUsername+"|ALL|"+sMSG;
            System.out.println(strSend);
            //协议为:"MSG|"+sendUsername+"|ALL|"+msg
            ClientMG.getClientMG().getClientChat().sendMSG(strSend);
            txtSend.setText("");
        }
    }
    //传输文件
    private class ButtonActionListener_1 implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            //1从本地选中一个文件,获取其文件相关信息(文件名,文件长度)
            //2创建文件传输的服务器,与服务器接通
            //3组织文件传输交互协议进行传输 
            //FILETRANS|sendername|recname|文件名|文件长度|IP|Port
            
            File finfo = null;
            //用于文件选择的对象jFileChooser
            JFileChooser jFileChooser = new JFileChooser();
            int result = jFileChooser.showOpenDialog(null);
            if(result==JFileChooser.APPROVE_OPTION){
                finfo = new File(jFileChooser.getSelectedFile().getAbsolutePath());
                String sFname = finfo.getName();
                //在用户列表中选择目标用户
                if(lOnlines.getSelectedIndex()!=-1){
                    String sTarget = lOnlines.getSelectedValue().toString();//得到目标用户
                    String sender = txtUser.getText().trim();
                    //得到新开服务器的IP+Port
                    String IPandPort = ClientMG.getClientMG().CreateFileTranServer(finfo);
                    //组织交互协议串,然后发送    FILETRANS+发送者+目标用户+文件名+文件的长度+IP和端口号
                    String strSend = "FILETRANS|"+sender+"|"+sTarget+"|"+sFname+"|"+finfo.length()+"|"+IPandPort;
                    ClientMG.getClientMG().getClientChat().sendMSG(strSend);
                }
            }
            
        }
    }
}
package rjxy.lkl.Client;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JOptionPane;

public class ClientMG {
    

    //实现管理类的单例化
    private static final ClientMG clientMG = new ClientMG();
    public ClientMG() {
    }
    public static ClientMG getClientMG(){
        return clientMG;
    }
    //操作图形化界面
    ClientForm cWin;
    ClientChat cChat;
    public void setClientForm(ClientForm cf){
        cWin = cf;
    }
//    设置界面中的消息记录
    public void setLog(String str){
        cWin.txtLog.append(str+"
");
    }
    public ClientChat getClientChat(){
        return cChat;
    }
    //新上线的用户添加到JList中
    public void addItem(String username){
        cWin.items.addElement(username);
    }
    public void addItems(String [] sItems){
        for (String username : sItems) {
            addItem(username);
        }
    }
    //一旦断开连接,清空JList中的用户
    //清空单个
    public void removeItem(String str){
        cWin.items.removeElement(str);
    }
    //清空所有
    public void clearItems(){
        cWin.items.clear();
    }
    public void connect(String IP,int port,String Username){
        try {
            Socket socket = new Socket(IP,port);
            ClientMG.getClientMG().setLog("已连接到服务器 ");
            cChat = new ClientChat(socket,Username);
            cChat.start();
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    FileListener filelistener;
    //创建文件传输的服务器  
    public String CreateFileTranServer(File file){
        try {
            ServerSocket server = new ServerSocket(8881);
            String IP = InetAddress.getLocalHost().getHostAddress();
            filelistener = new FileListener(server,file);
            filelistener.start();
            return IP+"|"+8881;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
        
    }
    //接收文件
    public void recFile(String sender,String fName,int len,String IP,int port){
        //文件名|文件长度|IP|Port
        //4判断是否要接收?  JOptionPane->confirm
        //5同意接收,连接服务器进行文件传输
        //6拒绝接收,向服务器发回拒接接收的消息:FILECANCEL|sendername|recname
        
        JOptionPane msg = new JOptionPane();
        int result = msg.showConfirmDialog(null, sender+"发送文件【"+fName+"】,
是否接收?", "文件传输确认", JOptionPane.YES_NO_OPTION);
        if(result == JOptionPane.YES_NO_OPTION){
            //确认接收
            try {
                Socket socket = new Socket(IP,port);
                new fileRec(socket, fName, len).start();
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        } else{
            //如果拒收   FILECANCEL|FromUser|toUser,sender给我发消息,某某某拒绝了,就通知sender,某某某拒绝了你的文件传输
            String strSend = "FILECANCEL|"+this.getClientChat().UserName+"|"+sender;
            this.getClientChat().sendMSG(strSend);
            this.setLog("您已拒接了"+sender+"的文件传输");
        }
        
    }
    //对方取消文件传递
    public void cancelFileTrans(){
        filelistener.cancelFileTrans();
//        this.setLog("对方取消了文件传输!!!");
    }
    
}
package rjxy.lkl.Client;

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

public class FileListener extends Thread {
    ServerSocket fserver;
    File filetrans;
    public FileListener(ServerSocket fserver, File filetrans) {
        this.fserver = fserver;
        this.filetrans = filetrans;
    }
    //取消传输
    public void cancelFileTrans(){
        if(fserver!=null){
            try {
                fserver.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    
    public void run() {
        Socket sfile = null;
        DataInputStream dis = null;
        DataOutputStream dos = null;
        try {
            sfile = fserver.accept();
            dis = new DataInputStream(new FileInputStream(filetrans));
            dos = new DataOutputStream(sfile.getOutputStream());
            
            //有关进度条属性的设置
            ClientMG.getClientMG().cWin.FileprogressBar.setValue(0);
            ClientMG.getClientMG().cWin.FileprogressBar.setVisible(true);
            ClientMG.getClientMG().cWin.FileprogressBar.setMaximum((int)filetrans.length());
            
            
            byte[] buff = new byte[1024];
            int iread = 0;
            int len =0;
            while((iread=dis.read(buff, 0, 1024))!=-1){
                dos.write(buff, 0, iread);  //写文件是,是根据读出的大小进行写入的
                len += iread;
                dos.flush();
                
//                写入流的同时,设置进度条的进度
                ClientMG.getClientMG().cWin.FileprogressBar.setValue(len);
            }
            ClientMG.getClientMG().setLog("文件传输完毕!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                dos.close();
                dis.close();
                if(sfile!=null){sfile.close();}
                if(fserver!=null){fserver.close();}
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package rjxy.lkl.Client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.*;

public class fileRec extends Thread{
    Socket socket;
    String sRecFilePath="D:\";
    String fileName;
    int fileLen;
    public fileRec(Socket socket, String fileName, int fileLen) {
        this.socket = socket;
        this.fileName = fileName;
        this.fileLen = fileLen;
    }
    
    public void run() {
        DataInputStream dis = null;
        DataOutputStream dos = null;
        
        //设置进度条属性
        ClientMG.getClientMG().cWin.FileprogressBar.setValue(0);
        ClientMG.getClientMG().cWin.FileprogressBar.setVisible(true);
        ClientMG.getClientMG().cWin.FileprogressBar.setMaximum(fileLen);
        try {
            dis = new DataInputStream(socket.getInputStream());
            dos = new DataOutputStream(new FileOutputStream(sRecFilePath+fileName));
            
            byte[] buff = new byte[1024];
            int iread = 0;
            int len = 0;
            while((iread=dis.read(buff, 0, 1024))!=-1){
                dos.write(buff, 0, iread);
                len +=iread;
                ClientMG.getClientMG().cWin.FileprogressBar.setValue(len);
                dos.flush();
            }
            ClientMG.getClientMG().setLog("文件接收完毕!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                dis.close();
                dos.close();
                if(socket!=null){ socket.close();}
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    
}

服务器端代码:

package rjxy.lkl.Server;

import java.awt.BorderLayout;

public class ServerForm extends JFrame {

    private JPanel contentPane;
    public JPanel panel;
    public JLabel label;
    public JTextField txtPort;
    public JButton btnStart;
    public JButton btnStop;
    public JScrollPane scrollPane;
    public JTextArea txtLog;
    
    
    ServerSocket server;
    ServerListener listener;
    volatile boolean serverFlag;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ServerForm frame = new ServerForm();
                    frame.setVisible(true);
                    SocketMG.getsocketMG().setServerForm(frame); //窗体对象传入SocketMG中
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public ServerForm() {
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 422, 520);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
        
        panel = new JPanel();
        panel.setBorder(new TitledBorder(null, "u914Du7F6Eu4FE1u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panel.setBounds(0, 0, 406, 66);
        contentPane.add(panel);
        panel.setLayout(null);
        
        label = new JLabel("u7AEFu53E3uFF1A");
        label.setBounds(10, 29, 54, 15);
        panel.add(label);
        
        txtPort = new JTextField();
        txtPort.setText("8899");
        txtPort.setBounds(46, 21, 66, 30);
        panel.add(txtPort);
        txtPort.setColumns(10);
        
        btnStart = new JButton("u5F00u59CBu670Du52A1");
        btnStart.addActionListener(new BtnStartActionListener());
        btnStart.setBounds(129, 21, 98, 31);
        panel.add(btnStart);
        
        btnStop = new JButton("u505Cu6B62u670Du52A1");
        btnStop.addActionListener(new BtnStopActionListener());
        btnStop.setBounds(253, 21, 98, 31);
        panel.add(btnStop);
        
        scrollPane = new JScrollPane();
        scrollPane.setBorder(new TitledBorder(null, "u6D88u606Fu8BB0u5F55", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        scrollPane.setBounds(0, 76, 406, 406);
        contentPane.add(scrollPane);
        
        txtLog = new JTextArea();
        scrollPane.setViewportView(txtLog);
    }
    
    //启动Socket服务 
    private class BtnStartActionListener implements ActionListener {
        public void actionPerformed(ActionEvent arg0) {
            int port = Integer.parseInt(txtPort.getText().trim());
            try {
                server = new ServerSocket(port);
                listener = new ServerListener(server);
                listener.start();
                SocketMG.getsocketMG().setLog("服务已开启");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    //停止服务
    private class BtnStopActionListener implements ActionListener {
        public void actionPerformed(ActionEvent arg0) {
            SocketMG.getsocketMG().setLog("服务器已关闭");
            //通知所有在线用户服务器关闭消息    交互协议为:"CLOSE|"
            SocketMG.getsocketMG().sendCloseMSGToAll();
            //把OnlineUsers集合中的每一个SocketChat关闭
            SocketMG.getsocketMG().closeALLSocket();
            //ArrayList清空
            SocketMG.getsocketMG().clearList();
            //关闭ServerSocket
            listener.stopListener();
            
            try {
                if (server != null) {
                    serverFlag = false;
                    server.close();
                }
            } catch (Exception e2) {
                // TODO: handle exception
            }
        }
    }
    
}
package rjxy.lkl.Server;
import java.io.IOException;
import java.net.*;


public class ServerListener extends Thread {
    
    ServerSocket server;
    volatile boolean serverFlag;
    public ServerListener(ServerSocket server) {
        this.server = server;
        serverFlag = true;
    }
    //停止监听
    public void stopListener(){
        serverFlag = false;
    }
    public void run() {
        while(serverFlag){
            Socket s = null;
            try {
                s = server.accept();
                new SocketChat(s).start();
                SocketMG.getsocketMG().setLog(s+"已登录");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
package rjxy.lkl.Server;
import java.net.*;
import java.io.*;
public class SocketChat extends Thread {
    
    Socket socket;
    BufferedReader br=null;
    PrintWriter pw = null;
    String UserName;
    public SocketChat(Socket socket) {
        this.socket = socket;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream(),
                    "UTF-8"));
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream(), "UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void sendMSG(String str){
        pw.println(str);
        pw.flush();
    }
    //关闭SocketChat
    public void closeChat(){
        try {
            if (socket != null)
                socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void run() {
        try {
            String str = "";
            while((str = br.readLine())!=null){
                String comm[] = str.split("[|]");
                if(comm[0].equals("Login")){
                    //读取客户端发过来的用户名
                    String cUsername = comm[1];
                    //赋给服务器端的UserName
                    UserName = cUsername;
                    //①得到所有在线用户发给客户端
                    SocketMG.getsocketMG().sendOnlineUsers(this);
                    //②将当期的socket信息存放在OnLineUsers数组中
                    SocketMG.getsocketMG().addList(this);
                    //③把当前用户信息发送给在线用户
                    SocketMG.getsocketMG().sendNewUsertoAll(this);
                }else if(comm[0].equals("MSG")){
                    //交互协议 "MSG|"+sendUsername+"|"+targetUsername+"|"+sMSG
                    //取出协议串中的内容
                    String sender = comm[1];
                    
                    String receiver = comm[2];
                    String msg = comm[3];
                    System.out.println("发送者:"+sender+"---接收者:"+receiver+"---消息体:"+msg);
                    if(receiver.equals("ALL")){
                        //"MSG|"+sendUsername+"|ALL|"+msg
                        String strmsg = "MsgReturn|"+sender+"|"+msg;
                        SocketMG.getsocketMG().sendMSGToALL(strmsg, this);
                        SocketMG.getsocketMG().setLog(sender+"发消息给所有人"+"内容为:"+msg);
                    }else{
                        //查询在线集合,如果接收对象则返回这个SocketChat对象
                        SocketChat sc = SocketMG.getsocketMG().getSocketChatByName(receiver);
                        System.out.println("选中的用户的信息:"+sc);
                        if(!(sc==null)){
                            String strmsg = "MsgReturn"+"|"+sender+"|"+msg; //重新组织交换协议
                            System.out.println(strmsg);
                            SocketMG.getsocketMG().sendMSGToSocket(strmsg, sc);
                            SocketMG.getsocketMG().setLog(sender+"发送给"+sc+"的消息是:"+msg);
                        }
                    }
                }else if(comm[0].equals("OFFLINE")){
                    //用户下线的交互协议:"OFFLINE|"+username
                    //向其他用户发送该用户下线的消息
                    SocketMG.getsocketMG().sendOffLineMSGToAll(this);
                    //移除List中已经下线用户的信息
                    SocketMG.getsocketMG().removeList(this);
                    SocketMG.getsocketMG().setLog(comm[1]+"下线了");
                } else if(comm[0].equals("FILETRANS")){
//                    "FILETRANS|"+sender+"|"+sTarget+"|"+sFname+"|"+finfo.length()+"|"+IPandPort
                    String sender = comm[1];
                    SocketChat sTarget = SocketMG.getsocketMG().getSocketChatByName(comm[2]);
                    //sFname+"|"+finfo.length()+"|"+IPandPort
                    String strSend = comm[3]+"|"+comm[4]+"|"+comm[5]+"|"+comm[6];
                    //调用文件发送函数
                    SocketMG.getsocketMG().sendFileTrans(sender, sTarget, strSend);
                    SocketMG.getsocketMG().setLog(sender+"发送了"+strSend+"给"+sTarget);
                } else if(comm[0].equals("FILECANCEL")){
                    //FILECANCEL|拒收者(A)|被拒收者(B)
                    //得到被拒收者
                    String A = comm[1];
                    SocketChat sc = SocketMG.getsocketMG().getSocketChatByName(comm[2]);
                    //重新组织交互协议  //FILECANCELReturn|拒收者A
                    String strSend = "FILECANCELReturn|"+A;
                    SocketMG.getsocketMG().setLog(A+"拒收了"+comm[2]+"传输的文件");
                    sc.sendMSG(strSend);
                    
                    
                    
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (br != null)
                    br.close();
                if (pw != null)
                    pw.close();
                if (socket != null)
                    socket.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
package rjxy.lkl.Server;

import java.util.ArrayList;

public class SocketMG {
    
    //实现管理类的单例化
    private static final SocketMG socketMG=new SocketMG();
    private SocketMG(){}
    public static SocketMG getsocketMG(){
        return socketMG;
    }
    SocketChat sChat;
    //操作图形界面
    ServerForm sWin;
    public void setServerForm(ServerForm s){
        sWin=s;
    }
    //设置界面中的消息记录
    public void setLog(String str){
        sWin.txtLog.append(str+"
");
    }
    
    //存储socket信息的集合
    private ArrayList<SocketChat> OnLineUsers = new ArrayList<SocketChat>();
    //把新用户添加到集合中
    public synchronized void addList(SocketChat sChat){
        OnLineUsers.add(sChat);
    }
    //得到所有用户在线信息名称,发回给客户端
    public void sendOnlineUsers(SocketChat sc){
        //发送所有用户信息的协议:USERLISTS|user1_user2_user3
        if(OnLineUsers.size()>0){
            String str = "";
            for (int i = 0; i < OnLineUsers.size(); i++) {
                SocketChat sChat = OnLineUsers.get(i);
                str += sChat.UserName+"_";
            }
            sc.sendMSG("USERLISTS|"+str);
        }
    }
    //新上线的用户发送给所有在线用户      ADD|用户名
    public void sendNewUsertoAll(SocketChat sc){
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat socketChat = OnLineUsers.get(i);
            //新上线用户这个消息不发给自己,发给其他用户,让其他用户知道该你上线了
            if(!socketChat.equals(sc)){
                socketChat.sendMSG("ADD|"+sc.UserName);
            }
        }
    }
    //通过用户名查找SocketChat对象
    public SocketChat getSocketChatByName(String name){
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat sChat = OnLineUsers.get(i);
            //此处曾出现过错误,形式为:sChat.equals(name)
            if(sChat.UserName.equals(name)){
                return sChat;
            }
        }
        return null;
    }
    
    //向目标对象发送消息
    public void sendMSGToSocket(String str,SocketChat sc){
        System.out.println("2222222222222"+str);
        sc.sendMSG(str);     
    }
    //发送消息出自己以外的所有人
    public void sendMSGToALL(String str,SocketChat sc){
        for (int i = 0; i < OnLineUsers.size(); i++) {
            //写程序的时候遇到的问题:SocketChat sChat = OnLineUsers.get(i);  
            //造成了与类成员变量重名,消息只发给自己
            SocketChat socketChat = OnLineUsers.get(i);
//            if(!socketChat.equals(sc)){
//                socketChat.sendMSG(str);
//            }
            socketChat.sendMSG(str);
        }
    }
    //向其他用户发送下线用户下线的通知
    public void sendOffLineMSGToAll(SocketChat sc){
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat socketChat = OnLineUsers.get(i);
            if(!socketChat.equals("sc")){
                String str = "DEL|"+sc.UserName;
                socketChat.sendMSG(str);
            }
        }
    }
    //把当前下线的用户从OnLineUsers中清除
    public synchronized void removeList(SocketChat sChat){
        //清除ArrayList中的当前用户信息(socketChat)
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat schat=OnLineUsers.get(i);
            if(schat.equals(sChat)){
                OnLineUsers.remove(sChat);
                break;
            }
        }
    }
    //关闭服务器通知给所有在线用户
    public void sendCloseMSGToAll(){
        //组织交互协议为:"CLOSE|"
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat socketchat = OnLineUsers.get(i);
            socketchat.sendMSG("CLOSE|");
        }
    }
    //关闭OnlineUsers中的每一个SocketChat
    public void closeALLSocket(){
        for (int i = 0; i < OnLineUsers.size(); i++) {
            SocketChat socketchat = OnLineUsers.get(i);
            socketchat.closeChat();
        }
    }
    //清空在线集合中的内容
    public void clearList(){
        OnLineUsers.clear();
    }
    //文件传输    发送者,接收者,内容
    public void sendFileTrans(String sender,SocketChat sTarget,String sMSG){
        sTarget.sendMSG("FILETRANS|"+sender+"|"+sMSG);
    }
}
原文地址:https://www.cnblogs.com/lkldeblog/p/9093895.html