13.Java实现P2P聊天软件(客户端代码)

上一篇实现了服务端,本篇主要展示 客户端代码的设计
客户端的代码比较复杂一点,由于P2P中,客户端要二者兼顾。
注意:目前本实例中只实现了消息的传输,但大致框架已定,后面的文件传输很简单了。

废话不多,首先上效果:(由于时间比较紧,只是初步实现了,欢迎大家二次创作,优化加强!!)

在这里插入图片描述

项目地址:https://gitee.com/yan-jiadou/study/tree/master/Java%E5%8A%A8%E6%89%8B%E5%81%9A%E4%B8%80%E5%81%9A/src/main/java/InternetCode/Socket/JJTalk

详细代码如下:

JJTalkClient.java
它是客户端主程序

package InternetCode.Socket.JJTalk;

import InternetCode.Socket.JJTalk.ClientUtil.ClientAbleUtil;
import InternetCode.Socket.JJTalk.ClientUtil.ClientThread;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

import static InternetCode.Socket.JJTalk.ClientUtil.ClientAbleUtil.makeActiveClientInfo;

public class JJTalkClient {
    
    
    // 创建流对象
    private ObjectOutputStream out = null;
    // 创建流对象
    private ObjectInputStream in = null;
    //声明服务器Socket
    private ServerSocket serverSocket;

    /**
     * 新建服务器对象并等待连接
     */
    public void getConnect(){
    
    
        try {
    
     // 捕捉异常
            Socket socket;
            System.out.println("开始连接服务器");
            socket = new Socket("127.0.0.1", 2006); // 实例化Socket对象
            //客户端信息注册
            ClientAbleUtil ableUtil=new ClientAbleUtil();
            ableUtil.sendObject(makeActiveClientInfo(),socket);
            new ClientThread(socket,ableUtil,"N","成功连接到服务器").start();
        } catch (Exception e) {
    
    
            e.printStackTrace(); // 输出异常信息
        }
    }

    /**
     * 新建服务器对象并等待连接
     */
    public void getServer() {
    
    
        try {
    
    
            serverSocket = new ServerSocket(1998);
            while (true) {
    
    
                Socket socket;
                // 监听是否有客户端连接
                System.out.println("等待连接!!");
                socket = serverSocket.accept();
                System.out.println("连接成功!");
                ClientAbleUtil ableUtil=new ClientAbleUtil();
                // 创建并启动连接线程对象
                ClientThread clientThread=new ClientThread(socket,ableUtil,"Y",socket.getInetAddress().getHostName()+"向您发起会话");
                clientThread.start();
            }
        } catch (Exception e) {
    
    
            e.printStackTrace(); // 输出异常信息
        }
    }

    public static void main(String[] args) {
    
    
       JJTalkClient client=new JJTalkClient();
       //连接服务器线程
       new Thread(new Runnable() {
    
    
           @Override
           public void run() {
    
    
               client.getConnect();
           }
       }).start();
       //监听连接线程
       new Thread(new Runnable() {
    
    
           @Override
           public void run() {
    
    
               client.getServer();
           }
       }).start();
    }

}

ClientThread.java
它主要负责图形化界面的展示和事件处理

package InternetCode.Socket.JJTalk.ClientUtil;

import InternetCode.Socket.JJTalk.pojo.ClientInfo;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;

public class ClientThread extends Thread{
    
    
    //连接服务器的套接字
    Socket socket;
    ClientAbleUtil ableUtil;
    //连接客户端的套接字
    Socket clientSocket;
    ClientAbleUtil ableUtil1;
    //是否客户端标志
    String clientFlat;
    String text;
    // 创建JTextArea对象
    public JTextArea outInfo = new JTextArea();

    public ClientThread(Socket socket,ClientAbleUtil ableUtil,String clientFlat,String text) throws IOException {
    
    
        this.socket = socket;
        this.ableUtil=ableUtil;
        this.clientFlat=clientFlat;
        this.text=text;
    }

    public void run() {
    
    
        try {
    
    
            new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    //运行图像化界面
                    Frame frame=new Frame(text);
                    frame.setVisible(true);
                }
            }).start();
            //监听发送方发送的消息
            if(clientFlat.equals("Y")){
    
    
                new Thread(new Runnable(){
    
    
                    @Override
                    public void run() {
    
    
                        while (true){
    
    
                            String line=ableUtil.getInfo(socket);
                            if(line!=null){
    
    
                                outInfo.append("\n");
                                outInfo.append(socket.getInetAddress().getHostName()+"发送消息:"+line);
                            }
                        }
                    }
                }).start();
            }

        } catch (Exception e) {
    
    
            System.out.println(socket + "已经退出。\n");
        }
    }

    class Frame extends JFrame{
    
    
        //连接客户端文本框
        private JTextField connectJText;
        //发送信息文本狂
        private JTextField sendInfoJText;

        public Frame(String text) {
    
    
            super();
            setTitle("客户端程序");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBounds(500, 100, 800, 700);
            final JScrollPane scrollPane = new JScrollPane();
            getContentPane().setLayout(new GridLayout(1,2));
            getContentPane().add(scrollPane);
            scrollPane.setViewportView(outInfo);
            getContentPane().add(getMainPanel());
            outInfo.append(text);
        }

        /**得到按钮对象
         * @return 按钮对象
         */
        protected JButton getButton(String text) {
    
    
            JButton jButton=new JButton();
            jButton = new JButton();
            jButton.addActionListener(new ActionListener() {
    
    
                public void actionPerformed(final ActionEvent e) {
    
    
                    if(text.equals("连接")){
    
    
                        ClientInfo clientInfo=new ClientInfo();
                        clientInfo.setClientId(connectJText.getText());
                        clientInfo.setQuery("Y");
                        System.out.println("开始向服务器发送查询信息");
                        ableUtil.sendObject(clientInfo,socket);
                        //等待接收服务器发送来的客户信息
                        try{
    
    
                            clientInfo=ableUtil.getClientInfoFromServer(socket);
                        }catch (Exception e3){
    
    
                            e3.printStackTrace();
                        }
                        if(clientInfo.isActive().equals("Y")){
    
    
                            //连接通信对方
                            try {
    
    
                                outInfo.append("开始连接客户:"+clientInfo.getClientId());
                                // 实例化Socket对象
                                clientSocket = new Socket(clientInfo.getIp(),Integer.parseInt(clientInfo.getPort()));
                                ableUtil1=new ClientAbleUtil();
                                outInfo.append("\n");
                                outInfo.append("连接成功!!可以开始通信了");
                                //监听请求方发送的消息
                                new Thread(new Runnable() {
    
    
                                    @Override
                                    public void run() {
    
    
                                        while (true){
    
    
                                            String line=ableUtil1.getInfo(clientSocket);
                                            if(line!=null){
    
    
                                                outInfo.append("\n");
                                                outInfo.append(clientSocket.getInetAddress().getHostName()+"发送消息:"+line);
                                            }
                                        }
                                    }
                                }).start();
                            } catch (Exception ex) {
    
    
                                ex.printStackTrace(); // 输出异常信息
                            }
                        }else if(clientInfo.isActive().equals("N")){
    
    
                            //对方不在线,输出提示信息
                            outInfo.append("对方不在线,请稍后在试!!");
                        }else{
    
    
                            outInfo.append("不存在此用户!!!请检查");
                        }
                    }
                    //发送消息给对方
                    if(text.equals("发送")){
    
    
                        if(clientFlat.equals("N")){
    
    
                            ableUtil1.sendInfo(sendInfoJText.getText(),clientSocket);
                        }else{
    
    
                            ableUtil.sendInfo(sendInfoJText.getText(),socket);
                        }
                    }

                    if(text.equals("选择文件")){
    
    

                    }

                    if(text.equals("发送文件")){
    
    

                    }

                }
            });
            jButton.setText(text);

            return jButton;
        }
        /**
         * 得到画板对象
         * @return 返回画板
         */
        protected JPanel getMainPanel() {
    
    
            JPanel panel;
            panel = new JPanel();
            panel.setLayout(new GridLayout(4,1));
            panel.add(getConnectPanel());
            panel.add(getSendDataPanel());
            panel.add(getSendDataPathPanel());
            panel.add(getSendInfoPanel());
            return panel;
        }

        /**
         * 得到连接客户端画板对象
         * @return 返回画板
         */
        protected JPanel getConnectPanel() {
    
    
            JPanel panel;
            connectJText=getJTextFiled(100,25);
            panel = new JPanel();
            panel.add(getLabel("对方客户端名称:"));
            panel.add(connectJText);
            panel.add(getButton("连接"));
            return panel;
        }

        /**
         * 得到发送信息的画板
         * @return
         */
        protected JPanel getSendInfoPanel() {
    
    
            JPanel panel;
            sendInfoJText=getJTextFiled(200,100);
            panel = new JPanel();
            panel.add(getLabel("请输入要发送的信息:"));
            panel.add(sendInfoJText);
            panel.add(getButton("发送"));
            return panel;
        }
        /**
         * 得到发送数据文件的画板
         * @return 发送数据的画板
         */
        protected JPanel getSendDataPanel() {
    
    
            JPanel panel;
            panel = new JPanel();
            panel.add(getLabel("选择要发送的文件:"));
            panel.add(getButton("选择文件"));
            return panel;
        }
        /**
         * 得到发送数据文件的画板
         * @return 发送数据的画板
         */
        protected JPanel getSendDataPathPanel() {
    
    
            JPanel panel;
            panel = new JPanel();
            panel.add(getLabel("文件路径:"));
            panel.add(getButton("发送文件"));
            return panel;
        }

        /**文本标签
         * @return
         */
        protected JLabel getLabel(String text) {
    
    
            JLabel jLabel=new JLabel();
            jLabel.setText(text);
            return jLabel;
        }

        /**获得输入框
         * @param width
         * @param height
         * @return 输入框对象
         */
        protected JTextField getJTextFiled(int width,int height) {
    
    
            JTextField jTextField;
            jTextField = new JTextField();
            jTextField.setPreferredSize(new Dimension(width, height));
            return jTextField;
        }

    }

}

ClientAbleUtil.java
这个类主要将Socket通信能力集合起来方便使用

package InternetCode.Socket.JJTalk.ClientUtil;

import InternetCode.Socket.JJTalk.pojo.ClientInfo;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientAbleUtil {
    
    

    private ObjectOutputStream objectOut;
    private ObjectInputStream objectIn;
    private PrintWriter infoOut;
    private BufferedReader infoIn;
    private DataOutputStream DataOut;
    private DataInputStream DataIn;


    /**
     * 生成活跃信息
     * @return
     * @throws UnknownHostException
     */
    public static ClientInfo makeActiveClientInfo() throws UnknownHostException {
    
    
        InetAddress inetAdder = InetAddress.getLocalHost();
        ClientInfo clientInfo=new ClientInfo();
        clientInfo.setClientId(String.valueOf(System.currentTimeMillis()));
        clientInfo.setActive("Y");
        clientInfo.setIp(inetAdder.getHostAddress());
        clientInfo.setPort("1998");
        clientInfo.setQuery("N");
        return clientInfo;
    }

    /**
     * 发送信息
     * @param info
     * @param socket
     */
    public void sendInfo(String info, Socket socket){
    
    
        try{
    
    
            if(infoOut==null){
    
    
                infoOut=new PrintWriter(socket.getOutputStream(),true);
            }
            infoOut.println(info);
            System.out.println("发送消息完成: "+info+"发送到:"+socket.getInetAddress().getHostAddress()+":"+socket.getPort());
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

    /**
     * 发送对象
     * @param obj 要发送的对象
     * @param socket 连接套接字
     */
   public void sendObject(Object obj, Socket socket){
    
    
        try {
    
    
            if(objectOut==null){
    
    
                objectOut=new ObjectOutputStream(socket.getOutputStream());
            }
            objectOut.writeObject(obj);
            System.out.println("发送对象完成");
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

    /**
     * 发送数据文件
     * @param file 要发送的文件对象
     * @param socket 连接套接字
     */
    public void sendData(File file, Socket socket){
    
    
        long lengths;
        try {
    
    
            if(socket!=null){
    
    
                if(DataOut==null){
    
    
                    DataOut=new DataOutputStream(socket.getOutputStream());
                }
                DataInputStream inStream = null;// 定义数据输入流对象
                FileInputStream inFile;
                if (file != null) {
    
    
                    lengths = file.length();
                    inFile=new FileInputStream(file);
                    inStream = new DataInputStream(inFile);
                } else {
    
    
                    System.out.println("没有选择文件。");
                    return;
                }
                DataOut.writeLong(lengths);
                DataOut.writeUTF(file.getName());
                byte[] bt = new byte[(int) lengths];
                int len = -1;
                while ((len = inStream.read(bt)) != -1) {
    
    
                    DataOut.write(bt);// 将字节数组写入输出流
                }
                inStream.close();
                inFile.close();
            }
        } catch (IOException e1) {
    
    
            e1.printStackTrace();
        }
    }

    /**
     * 监听接收服务端返回的对象信息
     * @param socket
     * @return
     */
    public ClientInfo getClientInfoFromServer(Socket socket) throws IOException {
    
    
        try {
    
    
            if(socket!=null){
    
    
                if(objectIn==null){
    
    
                    objectIn=new ObjectInputStream(socket.getInputStream());
                }
                while (true){
    
    
                    ClientInfo clientInfo=(ClientInfo) objectIn.readObject();
                    if(clientInfo!=null){
    
    
                        System.out.println("接收对象完成");
                        return clientInfo;
                    }
                }
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            objectIn.close();
        }
        return null;
    }

    /**
     * 监听其他节点传过来的信息
     * @param socket
     * @return
     */
    public  String getInfo(Socket socket){
    
    
        String info=null;
        try {
    
    
            if(socket!=null){
    
    
                if(infoIn==null){
    
    
                    infoIn=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                }
                while (true){
    
    
                    info=infoIn.readLine();
                    if(info!=null){
    
    
                        System.out.println("接收消息完成:"+info);
                        return info;
                    }
                }
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 等待客户端发送数据并接收
     */
    public boolean getData(Socket socket) {
    
    
        try {
    
    
            if(socket!=null){
    
    
                if(DataIn==null){
    
    
                    DataIn=new DataInputStream(socket.getInputStream());
                }
                while (true){
    
    
                    // 读取数据文件大小
                    long lengths = DataIn.readLong();
                    if(lengths>0){
    
    
                        String fileName=DataIn.readUTF();
                        // 创建字节数组
                        byte[] bt = new byte[(int) lengths];
                        for (int i = 0; i < bt.length; i++) {
    
    
                            bt[i] = DataIn.readByte();// 读取字节信息并存储到字节数组
                        }
                        File img=new File(String.valueOf(Math.random())+fileName);
                        OutputStream out=new DataOutputStream(new FileOutputStream(img));
                        out.write(bt);
                        System.out.println("文件接收成功!!");
                        return true;
                    }
                }
            }

        } catch(Exception e){
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (DataIn != null) {
    
    
                    DataIn.close();// 关闭流
                }
                if (socket != null) {
    
    
                    socket.close(); // 关闭套接字
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        return false;
    }
}

猜你喜欢

转载自blog.csdn.net/c1776167012/article/details/121196573
P2P