欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java聊天室之實現(xiàn)客戶端一對一聊天功能

 更新時間:2022年10月28日 08:25:15   作者:小虛竹and掘金  
這篇文章主要為大家詳細(xì)介紹了Java簡易聊天室之實現(xiàn)客戶端一對一聊天功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,需要的可以了解一下

一、題目描述

題目實現(xiàn):不同的客戶端之間需要進(jìn)行通信,一個客戶端與指定的另一客戶端進(jìn)行通信,實現(xiàn)一對一聊天功能。

實現(xiàn)一個客戶端與指定的另一客戶端進(jìn)行通信,運(yùn)行程序,服務(wù)器啟動后,啟動3個客戶端程序,分別以小小,虛虛,竹竹,登錄 ,然后在左側(cè)的用戶列表中選擇接收信息用戶,輸入聊天信息,發(fā)送到目標(biāo)用戶。

二、解題思路

創(chuàng)建一個服務(wù)類:ClientOneToOneServerFrame,繼承JFrame類

定義ServerThread線程類,用于為客戶端添加用戶列表。有一部分代碼用于轉(zhuǎn)發(fā)客戶端發(fā)送的消息。

創(chuàng)建一個客戶端類:ClientOneToOneClientFrame,繼承JFrame類

定義ClientThread線程類,用于對接收到服務(wù)器的信息,進(jìn)行處理。如果是登錄用戶,就添加到用戶列表中。

如果是消息,就追加到文本域中。

技術(shù)重點(diǎn):

? 在服務(wù)器端通過線程對客戶端發(fā)送的信息進(jìn)行監(jiān)聽,并對登錄用戶和消息分別進(jìn)行處理。如果是登錄用戶,就將所有用戶添加到客戶端的用戶列表中;如果是消息,就轉(zhuǎn)發(fā)給指定的用戶;客戶端則通過線程對接收到的信息進(jìn)行處理,如果是登錄用戶就添加到用戶列表中,如果是消息就追加到文本域中。 ? (1)在服務(wù)器端創(chuàng)建線程類ServerThread,用于對登錄用戶和消息分別進(jìn)行處理。如果是登錄用戶,就將所有用戶添加到客戶端的用戶列表中;如果是消息就轉(zhuǎn)發(fā)給指定的用戶。

? (2)在客戶端創(chuàng)建線程類ClientThread,用于對接收到的信息進(jìn)行處理,如果是登錄用戶就添加到用戶列表中,如果是消息就追加到文本域中。

啟動多個客戶端:

1、把項目打成jar包:利用maven 的clean install

會在target目錄下生成jar包

2、進(jìn)入target目錄,使用java -cp的命令運(yùn)行指定的類

java -cp 命令中 cp 指的就是classpath。使用該命令可以運(yùn)行jar中的某個指定的類(要包含全路徑的包名)

進(jìn)入cmd命令模式

運(yùn)行服務(wù)端

java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToOneServerFrame

運(yùn)行多個客戶端

java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToOneClientFrame

三、代碼詳解

ClientOneToOneServerFrame

package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * Description: 
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改記錄:
 * 修改后版本	        修改人		修改日期			修改內(nèi)容
 * 2022/6/5.1	    xiaoxuzhu		2022/6/5		    Create
 * </pre>
 * @date 2022/6/5
 */
public class ClientOneToOneServerFrame  extends JFrame{
    private JTextArea ta_info;
    private ServerSocket server; // 聲明ServerSocket對象
    private Socket socket; // 聲明Socket對象socket
    private Hashtable<String, Socket> map = new Hashtable<String, Socket>();// 用于存儲連接到服務(wù)器的用戶和客戶端套接字對象

    public void createSocket() {
        try {
            server = new ServerSocket(9527);
            while (true) {
                ta_info.append("等待新客戶連接......\n");
                socket = server.accept();// 創(chuàng)建套接字對象
                ta_info.append("客戶端連接成功。" + socket + "\n");
                new ServerThread(socket).start();// 創(chuàng)建并啟動線程對象
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class ServerThread extends Thread {
        Socket socket;

        public ServerThread(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));// 創(chuàng)建輸入流對象
                while (true) {
                    String info = in.readLine();// 讀取信息
                    String key = "";
                    if (info.startsWith("用戶:")) {// 添加登錄用戶到客戶端列表
                        key = info.substring(3, info.length());// 獲得用戶名并作為鍵使用
                        map.put(key, socket);// 添加鍵值對
                        Set<String> set = map.keySet();// 獲得集合中所有鍵的Set視圖
                        Iterator<String> keyIt = set.iterator();// 獲得所有鍵的迭代器
                        while (keyIt.hasNext()) {
                            String receiveKey = keyIt.next();// 獲得表示接收信息的鍵
                            Socket s = map.get(receiveKey);// 獲得與該鍵對應(yīng)的套接字對象
                            PrintWriter out = new PrintWriter(s
                                    .getOutputStream(), true);// 創(chuàng)建輸出流對象
                            Iterator<String> keyIt1 = set.iterator();// 獲得所有鍵的迭代器
                            while (keyIt1.hasNext()) {
                                String receiveKey1 = keyIt1.next();// 獲得鍵,用于向客戶端添加用戶列表
                                out.println(receiveKey1);// 發(fā)送信息
                                out.flush();// 刷新輸出緩沖區(qū)
                            }
                        }

                    } else {// 轉(zhuǎn)發(fā)接收的消息
                        key = info.substring(info.indexOf(":發(fā)送給:") + 5, info
                                .indexOf(":的信息是:"));// 獲得接收方的key值,即接收方的用戶名
                        String sendUser = info.substring(0, info
                                .indexOf(":發(fā)送給:"));// 獲得發(fā)送方的key值,即發(fā)送方的用戶名
                        Set<String> set = map.keySet();// 獲得集合中所有鍵的Set視圖
                        Iterator<String> keyIt = set.iterator();// 獲得所有鍵的迭代器
                        while (keyIt.hasNext()) {
                            String receiveKey = keyIt.next();// 獲得表示接收信息的鍵
                            if (key.equals(receiveKey)
                                    && !sendUser.equals(receiveKey)) {// 如果是發(fā)送方,但不是用戶本身
                                Socket s = map.get(receiveKey);// 獲得與該鍵對應(yīng)的套接字對象
                                PrintWriter out = new PrintWriter(s
                                        .getOutputStream(), true);// 創(chuàng)建輸出流對象

                                out.println("MSG:"+info);// 發(fā)送信息
                                out.flush();// 刷新輸出緩沖區(qū)
                            }
                        }
                    }
                }
            } catch (IOException e) {
                ta_info.append(socket + "已經(jīng)退出。\n");
            }
        }
    }

    /**
     * Launch the application
     *
     * @param args
     */
    public static void main(String args[]) {
        ClientOneToOneServerFrame frame = new ClientOneToOneServerFrame();
        frame.setVisible(true);
        frame.createSocket();
    }

    /**
     * Create the frame
     */
    public ClientOneToOneServerFrame() {
        super();
        setTitle("客戶端一對一通信——服務(wù)器端程序");
        setBounds(100, 100, 385, 266);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JScrollPane scrollPane = new JScrollPane();
        getContentPane().add(scrollPane, BorderLayout.CENTER);

        ta_info = new JTextArea();
        scrollPane.setViewportView(ta_info);
    }
}

ClientOneToOneClientFrame

package com.xiaoxuzhu;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.*;

/**
 * Description: 
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改記錄:
 * 修改后版本	        修改人		修改日期			修改內(nèi)容
 * 2022/6/5.1	    xiaoxuzhu		2022/6/5		    Create
 * </pre>
 * @date 2022/6/5
 */
public class ClientOneToOneClientFrame extends JFrame{
    private JTextField tf_newUser;
    private JList user_list;
    private JTextArea ta_info;
    private JTextField tf_send;
    PrintWriter out;// 聲明輸出流對象
    private boolean loginFlag = false;// 為true時表示已經(jīng)登錄,為false時表示未登錄
    private Socket socket;
    /**
     * Launch the application
     *
     * @param args
     */
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ClientOneToOneClientFrame frame = new ClientOneToOneClientFrame();
                    frame.setVisible(true);
                    frame.createClientSocket();// 調(diào)用方法創(chuàng)建套接字對象
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void createClientSocket() {
        try {
             socket = new Socket("127.0.0.1", 9527);// 創(chuàng)建套接字對象
            out = new PrintWriter(socket.getOutputStream(), true);// 創(chuàng)建輸出流對象
            SwingWorker<Void,Void> worker=new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    try {
                        BufferedReader in = new BufferedReader(new InputStreamReader(
                                socket.getInputStream()));// 創(chuàng)建輸入流對象
                        DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
                                .getModel();// 獲得列表框的模型
                        while (true) {
                            String info = in.readLine().trim();// 讀取信息

                            if (!info.startsWith("MSG:")) {
                                boolean itemFlag = false;// 標(biāo)記是否為列表框添加列表項,為true不添加,為false添加
                                for (int i = 0; i < model.getSize(); i++) {
                                    if (info.equals((String) model.getElementAt(i))) {
                                        itemFlag = true;
                                    }
                                }
                                if (!itemFlag) {
                                    model.addElement(info);// 添加列表項
                                } else {
                                    itemFlag = false;
                                }
                            } else {
                                ta_info.append(info + "\n");// 在文本域中顯示信息
                                if (info.equals("88")) {
                                    break;// 結(jié)束線程
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            };
            worker.execute();
            
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void send() {
        if (!loginFlag) {
            JOptionPane.showMessageDialog(null, "請先登錄。");
            return;
        }
        String sendUserName = tf_newUser.getText().trim();
        String info = tf_send.getText();// 獲得輸入的信息
        if (info.equals("")) {
            return;// 如果沒輸入信息則返回,即不發(fā)送
        }
        String receiveUserName = (String) user_list.getSelectedValue();// 獲得接收信息的用戶
        String msg = sendUserName + ":發(fā)送給:" + receiveUserName + ":的信息是: "
                + info;// 定義發(fā)送的信息
        if (info.equals("88")) {
            System.exit(0);// 如果沒輸入信息是88,則退出
        }
        out.println(msg);// 發(fā)送信息
        out.flush();// 刷新輸出緩沖區(qū)
        tf_send.setText(null);// 清空文本框
    }

    /**
     * Create the frame
     */
    public ClientOneToOneClientFrame() {
        super();
        setTitle("客戶端一對一通信——客戶端程序");
        setBounds(100, 100, 385, 288);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel();
        getContentPane().add(panel, BorderLayout.SOUTH);

        final JLabel label = new JLabel();
        label.setText("輸入聊天內(nèi)容:");
        panel.add(label);

        tf_send = new JTextField();
        tf_send.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 調(diào)用方法發(fā)送信息
            }
        });
        tf_send.setPreferredSize(new Dimension(180, 25));
        panel.add(tf_send);

        final JButton button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 調(diào)用方法發(fā)送信息
            }
        });
        button.setText("發(fā)  送");
        panel.add(button);

        final JSplitPane splitPane = new JSplitPane();
        splitPane.setDividerLocation(100);
        getContentPane().add(splitPane, BorderLayout.CENTER);

        final JScrollPane scrollPane = new JScrollPane();
        splitPane.setRightComponent(scrollPane);

        ta_info = new JTextArea();
        scrollPane.setViewportView(ta_info);

        final JScrollPane scrollPane_1 = new JScrollPane();
        splitPane.setLeftComponent(scrollPane_1);

        user_list = new JList();
        user_list.setModel(new DefaultComboBoxModel(new String[] { "" }));
        scrollPane_1.setViewportView(user_list);

        final JPanel panel_1 = new JPanel();
        getContentPane().add(panel_1, BorderLayout.NORTH);

        final JLabel label_1 = new JLabel();
        label_1.setText("輸入用戶名稱:");
        panel_1.add(label_1);

        tf_newUser = new JTextField();
        tf_newUser.setPreferredSize(new Dimension(180, 25));
        panel_1.add(tf_newUser);

        final JButton button_1 = new JButton();
        button_1.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (loginFlag) {
                    JOptionPane.showMessageDialog(null, "在同一窗口只能登錄一次。");
                    return;
                }
                String userName = tf_newUser.getText().trim();// 獲得登錄用戶名
                out.println("用戶:" + userName);// 發(fā)送登錄用戶的名稱
                out.flush();// 刷新輸出緩沖區(qū)
                tf_newUser.setEnabled(false);
                loginFlag = true;
            }
        });
        button_1.setText("登  錄");
        panel_1.add(button_1);
    }
}

服務(wù)器啟動

客戶端1和客戶端2登錄

客戶端小小向客戶端虛虛發(fā)送消息

客戶端虛虛向客戶端小小發(fā)送消息

注:小小發(fā)給虛虛時,小小自己的界面不顯示自己發(fā)出的內(nèi)容。本示例主要是為了演示客戶端向指定客戶端發(fā)送消息。

多學(xué)一個知識點(diǎn)

swing的開發(fā)過程,要了解3種線程的概念:

1、初始化線程 :此類線程將執(zhí)行初始化應(yīng)用代碼。

2、事件調(diào)度線程 :所有的事件處理代碼在這里執(zhí)行。大多數(shù)與Swing框架 交互的代碼也必須執(zhí)行這個線程。

事件調(diào)度線程是單線程的:因為 Swing里面的各種組件類,比如JTextField,JButton 都不是線程安全的,這就意味著,如果有多個線程,那么同一個JTextField的setText方法,可能會被多個線程同時調(diào)用,這會導(dǎo)致同步問題以及錯誤數(shù)據(jù)的發(fā)生

3、工作線程 :也稱作background threads(后臺線程),此類線程將執(zhí)行所有消耗時間的任務(wù)。

比如的事件監(jiān)聽——在actionPerformed 里放一個長耗時任務(wù),如:數(shù)據(jù)庫訪問連接 建立網(wǎng)絡(luò)連接 文件復(fù)制等等 就會自動進(jìn)入事件調(diào)度線程。 而事件調(diào)度線程又是單線程模式,其結(jié)果就會是在執(zhí)行這些長耗時任務(wù)的時候,界面就無響應(yīng)了。

為了解決這個問題,Swing提供了一個SwingWorker類來解決。 SwingWorker是一個抽象類,為了使用,必須實現(xiàn)方法 doInBackground,在doInBackground中,就可以編寫我們的任務(wù),然后執(zhí)行SwingWorker的execute方法,放在專門的工作線程中去運(yùn)行。

上面題目里,ClientOneToOneClientFrame類中的createClientSocket()里就用到了SwingWorker

以上就是Java聊天室之實現(xiàn)客戶端一對一聊天功能的詳細(xì)內(nèi)容,更多關(guān)于Java聊天室的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java Thread之Sleep()使用方法及總結(jié)

    Java Thread之Sleep()使用方法及總結(jié)

    這篇文章主要介紹了Java Thread之Sleep()使用方法及總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 淺聊一下Spring?Security的使用方法

    淺聊一下Spring?Security的使用方法

    Spring?Security?是一個基于?Spring?框架的安全框架,提供了一套安全性認(rèn)證和授權(quán)的解決方案,用于保護(hù)?Web?應(yīng)用程序和服務(wù),接下來小編就和大家聊聊Spring?Security,感興趣的小伙伴跟著小編一起來看看吧
    2023-08-08
  • 使用AOP+反射實現(xiàn)自定義Mybatis多表關(guān)聯(lián)查詢

    使用AOP+反射實現(xiàn)自定義Mybatis多表關(guān)聯(lián)查詢

    這篇文章主要介紹了使用AOP+反射實現(xiàn)自定義Mybatis多表關(guān)聯(lián),目前的需求是增強(qiáng)現(xiàn)有的查詢,使用簡單的注解即可實現(xiàn)多表關(guān)聯(lián),本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • Java中拷貝list數(shù)組幾種常見的方法

    Java中拷貝list數(shù)組幾種常見的方法

    這篇文章主要給大家介紹了關(guān)于Java中拷貝list數(shù)組幾種常見的方法,在Java中,List是一個接口,它有多個實現(xiàn)類,如ArrayList、LinkedList等,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • JVM系列之:JIT中的Virtual Call接口操作

    JVM系列之:JIT中的Virtual Call接口操作

    這篇文章主要介紹了JVM系列之:JIT中的Virtual Call接口操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 淺析java中print和println的區(qū)別

    淺析java中print和println的區(qū)別

    以下是對java中print和println的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • java 面試題閏年判斷詳解及實例

    java 面試題閏年判斷詳解及實例

    這篇文章主要介紹了java面試題 閏年判斷的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • springboot國際化多語言配置方式

    springboot國際化多語言配置方式

    這篇文章主要介紹了springboot國際化多語言配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • SpringBoot+Mybatis實現(xiàn)登錄注冊的示例代碼

    SpringBoot+Mybatis實現(xiàn)登錄注冊的示例代碼

    這篇文章主要介紹了SpringBoot+Mybatis實現(xiàn)登錄注冊的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • String s = new String(''a '') 到底產(chǎn)生幾個對象

    String s = new String(''a '') 到底產(chǎn)生幾個對象

    這篇文章主要介紹了String s = new String(" a ") 到底產(chǎn)生幾個對象,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05

最新評論