有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"), "\u767B\u5F55\u4FE1\u606F", 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("\u7AEF\u53E3:"); 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("\u767B\u5F55"); btnLogin.addActionListener(new BtnLoginActionListener()); btnLogin.setBounds(337, 22, 65, 25); panel.add(btnLogin); btnExit = new JButton("\u9000\u51FA"); btnExit.addActionListener(new BtnExitActionListener()); btnExit.setBounds(401, 22, 65, 25); panel.add(btnExit); label = new JLabel("\u7528\u6237\u540D:"); 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)), "\u64CD\u4F5C", TitledBorder.LEADING, TitledBorder.TOP, null, null)); panel_1.setBounds(10, 414, 477, 121); contentPane.add(panel_1); btnSend = new JButton("\u53D1\u9001\u6D88\u606F"); 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("\u7FA4\u53D1\u6D88\u606F"); sendToAll.addActionListener(new ButtonActionListener()); sendToAll.setBounds(254, 82, 93, 23); panel_1.add(sendToAll); FileTranbutton = new JButton("\u4F20\u8F93\u6587\u4EF6"); 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, "\u804A\u5929\u8BB0\u5F55", 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, "\u5728\u7EBF\u7528\u6237", 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+"\r\n"); } 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+"】,\r\n是否接收?", "文件傳輸確認", 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, "\u914D\u7F6E\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null)); panel.setBounds(0, 0, 406, 66); contentPane.add(panel); panel.setLayout(null); label = new JLabel("\u7AEF\u53E3\uFF1A"); 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("\u5F00\u59CB\u670D\u52A1"); btnStart.addActionListener(new BtnStartActionListener()); btnStart.setBounds(129, 21, 98, 31); panel.add(btnStart); btnStop = new JButton("\u505C\u6B62\u670D\u52A1"); btnStop.addActionListener(new BtnStopActionListener()); btnStop.setBounds(253, 21, 98, 31); panel.add(btnStop); scrollPane = new JScrollPane(); scrollPane.setBorder(new TitledBorder(null, "\u6D88\u606F\u8BB0\u5F55", 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+"\r\n"); } //存儲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); } }
