首頁 > 軟體

Java實戰之基於TCP實現簡單聊天程式

2022-03-19 13:02:04

一、如何實現TCP通訊

要實現TCP通訊需要建立一個伺服器端程式和一個使用者端程式,為了保證資料傳輸的安全性,首先需要實現伺服器端程式,然後在編寫使用者端程式。

在本機執行伺服器端程式,在遠端機執行使用者端程式

本機的IP地址:192.168.129.222

遠端機的IP地址:192.168.214.213

二、編寫C/S架構聊天程式

1.編寫伺服器端程式 - Server.java

在net.hw.network包裡建立Server類

package net.hw.network;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 功能:伺服器端
 * 作者:華衛
 * 日期:2022年03月18日
 */
public class Server extends JFrame {
    static final int PORT = 8136;
    static final String HOST_IP = "192.168.129.222";

    private JPanel panel1, panel2;
    private JTextArea txtContent, txtInput, txtInputIP;
    private JScrollPane panContent, panInput;
    private JButton btnClose, btnSend;

    private ServerSocket serverSocket;
    private Socket socket;
    private DataInputStream netIn;
    private DataOutputStream netOut;

    public static void main(String[] args) {
        new Server();
    }

    public Server() {
        super("伺服器");

        //建立元件
        panel1 = new JPanel();
        panel2 = new JPanel();
        txtContent = new JTextArea(15, 60);
        txtInput = new JTextArea(3, 60);
        panContent = new JScrollPane(txtContent, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        panInput = new JScrollPane(txtInput, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        btnClose = new JButton("關閉");
        btnSend = new JButton("傳送");

        //新增元件
        getContentPane().add(panContent, "Center");
        getContentPane().add(panel1, "South");
        panel1.setLayout(new GridLayout(0, 1));
        panel1.add(panInput);
        panel1.add(panel2);
        panel2.add(btnSend);
        panel2.add(btnClose);

        //設定元件屬性
        txtContent.setEditable(false);
        txtContent.setFont(new Font("宋體", Font.PLAIN, 13));
        txtInput.setFont(new Font("宋體", Font.PLAIN, 15));
        txtContent.setLineWrap(true);
        txtInput.setLineWrap(true);
        txtInput.requestFocus();
        setSize(450, 350);
        setLocation(50, 200);
        setResizable(false);
        setVisible(true);

        //等候客戶請求	
        try {
            txtContent.append("伺服器已啟動...n");
            serverSocket = new ServerSocket(PORT);
            txtContent.append("等待客戶請求...n");
            socket = serverSocket.accept();
            txtContent.append("連線一個客戶。n" + socket + "n");
            netIn = new DataInputStream(socket.getInputStream());
            netOut = new DataOutputStream(socket.getOutputStream());
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        /

        //註冊監聽器,編寫事件程式碼	
        txtContent.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayClientMsg();
            }
        });

        txtInput.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayClientMsg();
            }
        });

        panel2.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayClientMsg();
            }
        });

        txtInput.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                displayClientMsg();
            }
        });

        txtInput.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent e) {
                displayClientMsg();
            }
        });

        btnSend.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {

                    String serverMsg = txtInput.getText();
                    if (!serverMsg.trim().equals("")) {
                        txtContent.append("伺服器>" + serverMsg + "n");
                        netOut.writeUTF(serverMsg);
                    } else {
                        JOptionPane.showMessageDialog(null, "不能傳送空資訊!", "伺服器", JOptionPane.WARNING_MESSAGE);
                    }

                    txtInput.setText("");
                    txtInput.requestFocus();
                } catch (IOException ie) {
                    ie.printStackTrace();
                }
            }
        });

        btnClose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    netIn.close();
                    netOut.close();
                    socket.close();
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.exit(0);
            }
        });

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                try {
                    netIn.close();
                    netOut.close();
                    socket.close();
                    serverSocket.close();
                } catch (IOException ie) {
                    ie.printStackTrace();
                }
                System.exit(0);
            }

            public void windowActivated(WindowEvent e) {
                txtInput.requestFocus();
            }
        });
    }

    //顯示使用者端資訊
    void displayClientMsg() {
        try {
            if (netIn.available() > 0) {
                String clientMsg = netIn.readUTF();
                txtContent.append("使用者端>" + clientMsg + "n");
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

2.編寫使用者端程式 - Client.java

在net.hw.network包裡建立Client類

package net.hw.network;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 功能:使用者端
 * 作者:華衛
 * 日期:2022年03月18日
 */
public class Client extends JFrame {

    private JPanel panel1, panel2;
    private JTextArea txtContent, txtInput;
    private JScrollPane panContent, panInput;
    private JButton btnClose, btnSend;

    private Socket socket;
    private DataInputStream netIn;
    private DataOutputStream netOut;

    public static void main(String[] args) {
        new Client();
    }

    public Client() {
        super("使用者端");

        //建立元件
        panel1 = new JPanel();
        panel2 = new JPanel();
        txtContent = new JTextArea(15, 60);
        txtInput = new JTextArea(3, 60);
        panContent = new JScrollPane(txtContent, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        panInput = new JScrollPane(txtInput, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        btnClose = new JButton("關閉");
        btnSend = new JButton("傳送");

        //新增元件
        getContentPane().add(panContent, "Center");
        getContentPane().add(panel1, "South");
        panel1.setLayout(new GridLayout(0, 1));
        panel1.add(panInput);
        panel1.add(panel2);
        panel2.add(btnSend);
        panel2.add(btnClose);

        //設定元件屬性
        txtContent.setEditable(false);
        txtContent.setFont(new Font("宋體", Font.PLAIN, 13));
        txtInput.setFont(new Font("宋體", Font.PLAIN, 15));
        txtContent.setLineWrap(true);
        txtInput.setLineWrap(true);
        txtInput.requestFocus();
        setSize(450, 350);
        setLocation(550, 200);
        setResizable(false);
        setVisible(true);

        //連線伺服器
        try {
            txtContent.append("連線伺服器...n");
            socket = new Socket(Server.HOST_IP, Server.PORT);
            txtContent.append("連線伺服器成功。n" + socket + "n");
            netIn = new DataInputStream(socket.getInputStream());
            netOut = new DataOutputStream(socket.getOutputStream());
        } catch (IOException e1) {
            JOptionPane.showMessageDialog(null, "伺服器連線失敗!n請先啟動伺服器程式!", "使用者端", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }

        /

        //註冊監聽器,編寫事件程式碼
        txtContent.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayServerMsg();
            }
        });

        txtInput.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayServerMsg();
            }
        });

        panel2.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                displayServerMsg();
            }
        });

        txtInput.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                displayServerMsg();
            }
        });

        txtInput.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent e) {
                displayServerMsg();
            }
        });

        btnSend.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {

                    String clientMsg = txtInput.getText();
                    if (!clientMsg.trim().equals("")) {
                        netOut.writeUTF(clientMsg);
                        txtContent.append("使用者端>" + clientMsg + "n");
                    } else {
                        JOptionPane.showMessageDialog(null, "不能傳送空資訊!", "使用者端", JOptionPane.WARNING_MESSAGE);
                    }

                    txtInput.setText("");
                    txtInput.requestFocus();
                } catch (IOException ie) {
                    ie.printStackTrace();
                }
            }
        });

        btnClose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    netIn.close();
                    netOut.close();
                    socket.close();
                } catch (IOException ie) {
                    ie.printStackTrace();
                }
                System.exit(0);
            }
        });

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                try {
                    netIn.close();
                    netOut.close();
                    socket.close();
                } catch (IOException ie) {
                    ie.printStackTrace();
                }
                System.exit(0);
            }

            public void windowActivated(WindowEvent e) {
                txtInput.requestFocus();
            }
        });
    }

    //顯示伺服器端資訊
    void displayServerMsg() {
        try {
            if (netIn.available() > 0) {
                String serverMsg = netIn.readUTF();
                txtContent.append("伺服器>" + serverMsg + "n");
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

3.測試伺服器端與使用者端能否通訊

在本機[192.168.129.222]上啟動伺服器端

在遠端機[192.168.214.213]上啟動使用者端

顯示連線伺服器[192.168.129.222]成功,切換到伺服器端檢視,顯示連線了一個客戶[192.168.214.213]

此時,伺服器端和使用者端就可以相互通訊了

4.程式優化思路 - 伺服器端採用多執行緒

其實,很多伺服器端程式都是允許被多個應用程式存取的,例如入口網站可以被多個使用者同時存取,因此伺服器端都是多執行緒的。

以上就是Java實戰之基於TCP實現簡單聊天程式的詳細內容,更多關於Java TCP聊天程式的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com