java 基于TCP/IP协议的局域网聊天小程序
Posted 乘着风破万浪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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"), "\\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, C++语言实现网络聊天程序的设计与实现(基于TCP/IP协议的SOCKET编程)超详细(代码+解析)