Java實驗——基於GUI的網路通訊程式設計

RealWeakCoder發表於2020-10-21

一、實驗目的

1.掌握Java中GUI程式的編寫,包括事件監聽機制。

2.掌握Java的網路通訊程式設計,ServerSocket,Socket類的使用。

3.掌握Java中多執行緒的程式設計,Thread類,Runnable介面的使用。

4.掌握用物件導向的方法分析和解決複雜問題。

二、實驗原理

1.使用物件導向的設計方法設計程式

2.通過繼承JFrame類實現圖形化介面

3.通過事件監聽器實現按鈕點選監聽與觸發事件

4.利用ServerSocket和Socket類實現網路通訊

5.利用多執行緒技術實現同時讀入資料與傳送資料

三、使用硬體、軟體環境

硬體環境:PC計算機一臺,配置CPU為Intel(R)Core(TM)i7-8565U CPU @1.80Ghz記憶體為8.0GB,硬碟256G+1T(機械硬碟),安裝系統為Windows10作業系統。
軟體環境:IDEA,JDK12.0

四、實驗過程

在這裡插入圖片描述
①伺服器:

//Author:Sherlock Novitch in Hfut
// -*- codeing=utf-8 -*-
// @time:2020/10/19 15:14
// @File:ServerFrame.java
// @Software:IDEA
// @blog:https://blog.csdn.net/RealCoder

package experiment2;

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

public class ServerFrame extends JFrame {
    private JTextField text1,text2; //text1為埠號文字欄,text2為訊息輸入欄
    private JTextArea text;         //訊息顯示區
    private JButton button1,button2; //button1對應start,button2對應say
    private ServerSocket server;    //伺服器套接字
    private Socket sc;              //與客戶端建立聯絡的套接字
    private DataInputStream in;     //客戶端到伺服器的輸入流
    private DataOutputStream out;   //伺服器到客戶端的輸出流
    private ReadThread readThread;  //負責讀入資訊的執行緒
    private myactionlistenr ac;   //監聽兩個按鈕的監聽器
    private ServerFrame(){          //構造方法
        setLayout(new FlowLayout()); //窗體容器整體佈局設定為FlowLayout
        GUIinit();                     //呼叫元件初始化方法
        eventinit();               //呼叫事件監聽器初始化方法
        setVisible(true);         //設定可視
        setResizable(false);      //設定不可更改大小
        setDefaultCloseOperation(EXIT_ON_CLOSE); //在關閉窗體時,程式終止

    }
    private void GUIinit(){
        setTitle("伺服器");    //設定標題
        setBounds(100,250,500,300);  //位置與大小
        Box boxH1=Box.createHorizontalBox(); //建立水平盒式容器,後續依次從左到右新增"Port:",text1,button1;
        Box boxH2=Box.createHorizontalBox(); //建立水平盒式容器,後續依次從左到右新增"Say: ",text2,button2;
        Box boxV=Box.createVerticalBox();  //建立垂直盒式容器,後續依次從垂直方向從上向下新增"伺服器設定:",boxH1,boxH2
        //1°開始新增“伺服器設定:”標籤至boxV
        Box temp=Box.createHorizontalBox();
        temp.add(new JLabel("伺服器設定:"));
        temp.add(Box.createHorizontalStrut(400)); //新增水平支撐(類似Qt中的彈簧)
        boxV.add(temp);
        boxV.add(Box.createVerticalStrut(5));//新增垂直支撐(類似Qt中的彈簧)
        //2°開始填裝boxH1,之後加入到boxV中
        boxH1.add(new JLabel("Port:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text1=new JTextField();
        boxH1.add(text1);
        boxH1.add(Box.createHorizontalStrut(10));
        button1=new JButton("Start");
        boxH1.add(button1);
        boxV.add(boxH1);
        boxV.add(Box.createVerticalStrut(10));
        //3°開始新增文字顯示區至boxV
        text=new JTextArea(9,30);
        JScrollPane jScrollPane=new JScrollPane(text);  //將text放置到滾動窗格(一種容器)中
        text.setEditable(false);
        jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                                                       //當text內文字高度超過text高度時,text出現豎直滾動條
        boxV.add(jScrollPane);
        boxV.add(Box.createVerticalStrut(10));
        //4°開始填裝boxH2,之後將boxH2加入到boxV中
        boxH2.add(new JLabel("Say:"));
        boxH2.add(Box.createHorizontalStrut(5));
        text2=new JTextField();
        boxH2.add(text2);
        boxH2.add(Box.createHorizontalStrut(5));
        button2=new JButton("Say");
        boxH2.add(button2);
        boxV.add(boxH2);
        add(boxV);
    }
    private void eventinit(){
        ac=new myactionlistenr();   //初始化監聽器
        button1.addActionListener(ac);  //監聽器註冊
        button2.addActionListener(ac);  //監聽器註冊
    }
    private void startserver(){  //”開啟服務“方法,當點選Start按鈕時,監聽器檢測到,呼叫此方法
          try {
              server = new ServerSocket(Integer.parseInt(text1.getText())); //用text1文字框內容對應的數字初始化伺服器套接字
              text.append("Server starting…\n");                     //伺服器端列印"Server starting…"
              text.paintImmediately(text.getBounds()); //本條語句使得Server starting立即顯示出來
                                                      // 原因在於append方法只是將引數加至緩衝區
                                                     // 而本執行緒會被下一行accept方法阻塞
                                                     //呼叫paintImmediately方法直接將緩衝區內容顯示出來
              sc = server.accept();         // 等待客戶端連線,初始化與客服端相連線的套接字物件sc
              text.append("Client connected…\n"); //伺服器端列印”Client connected…“
              in = new DataInputStream(sc.getInputStream()); //將in初始化為sc的輸入流
              out = new DataOutputStream(sc.getOutputStream()); //將out初始化為sc的輸出流
              readThread = new ReadThread();               //建立讀取資料的執行緒
              readThread.start();                          //讀取資料的執行緒開始執行
          } catch (IllegalArgumentException e) {  //若埠引數不符合,丟擲IllegalArgumentException,用訊息對話方塊提示使用者
              JOptionPane.showMessageDialog(this,"埠值範圍必須為0~65535","警告",JOptionPane.WARNING_MESSAGE);
          }catch (IOException e){
              JOptionPane.showMessageDialog(this,"未知原因連線錯誤","警告",JOptionPane.WARNING_MESSAGE);
          }catch (Exception e){
              System.out.println(e.toString());
          }

    }
    private void sentmessage(){  //當say按鈕被點選,監聽器檢測到,呼叫該方法
        if(readThread==null){    //先判斷是否已連線,只需判斷readThread是否被建立,未建立則發出提示資訊,終止方法
            JOptionPane.showMessageDialog(this,"未連線無法傳送資訊","警告",JOptionPane.WARNING_MESSAGE);
            return;
        }
        try{
            out.writeUTF("Server: "+text2.getText()+"\n");  //向客戶端傳送資訊
            text.append("Server: "+text2.getText()+"\n");       //同時更新伺服器端文字區內容
            text2.setText("");                                 //清空text2
        }catch (IOException e){//異常處理
            JOptionPane.showMessageDialog(this,"未知原因無法傳送資訊","警告",JOptionPane.WARNING_MESSAGE);
            System.out.println(e.toString());
        }
    }
    class myactionlistenr implements ActionListener { //監視按鈕的監聽器
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == button1) startserver();   //如果點選的按鈕為start,呼叫startserver方法
            if (e.getSource() == button2) sentmessage();   //如果點選的按鈕為say,則呼叫sentmessage方法
        }
    }
    class ReadThread extends Thread{
        public void run(){
            while(true) {
                try {
                    text.append(in.readUTF());    //將輸入流讀取的資料新增至文字顯示區
                } catch (IOException e) {
                    System.out.println(e.toString());
                }
            }
        }
    }
    public static void main(String[] args) {
        ServerFrame sf=new ServerFrame();
    }
}

②客戶端:

//Author:Sherlock Novitch in Hfut
// -*- codeing=utf-8 -*-
// @time:2020/10/19 15:14
// @File:ClientFrame.java
// @Software:IDEA
// @blog:https://blog.csdn.net/RealCoder

package experiment2;

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

public class ClientFrame extends JFrame {
    private JTextField text1,text2,text3; //text1為ip地址輸入欄,text2為埠地址輸入欄,text3為訊息輸入欄
    private JTextArea text;           //文字顯示區
    private JButton button1,button2;  //button1為connect按鈕,button2為say按鈕
    private Socket client;           //客戶端套接字
    private DataInputStream in;     //從伺服器到客戶端的輸入流
    private DataOutputStream out;  //從客戶端到伺服器的輸出流
    private ReadThread readThread; //讀取伺服器訊息的執行緒
    private actionlistener ac;  //監聽按鈕button1和button2的監聽器
    private ClientFrame() { //構造方法
        setLayout(new FlowLayout()); //窗體整體佈局為FlowLayout
        GUIinit();                //呼叫元件初始化方法
        Eventinit();              //呼叫事件初始化方法
        setVisible(true);          //設定可見
        setResizable(false);     //設定不可更改大小
        setDefaultCloseOperation(EXIT_ON_CLOSE);  //設定當關閉視窗時,程式終止
    }
    private void GUIinit(){  //元件初始化方法
        setTitle("客戶端");  //設定標題
        setBounds(600,250,500,300);  //位置大小
        Box boxH1=Box.createHorizontalBox(); //建立水平盒式容器,後續裝入"Server IP:",text1,"Server Port",button1;
        Box boxH2=Box.createHorizontalBox(); //建立水平盒式容器,後續裝入"Say:",text3,button2;
        Box boxV=Box.createVerticalBox();  //建立垂直盒式容器,後續裝入“客戶端設定:",boxH1,text,boxH2;
        //1°boxV裝入“客戶端設定”標籤
        Box temp=Box.createHorizontalBox();
        temp.add(new JLabel("客戶端設定:"));
        temp.add(Box.createHorizontalStrut(400));
        boxV.add(temp);
        boxV.add(Box.createVerticalStrut(5));
        //2°將Server IP:",text1,"Server Port",button1從左到右加入到boxH1中,再講boxH1加入到boxV中
        boxH1.add(new JLabel("Server IP:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text1=new JTextField();
        boxH1.add(text1);
        boxH1.add(Box.createHorizontalStrut(10));
        boxH1.add(new JLabel("Server Port:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text2=new JTextField();
        boxH1.add(text2);
        boxH1.add(Box.createHorizontalStrut(5));
        button1=new JButton("Connect");
        boxH1.add(button1);
        boxV.add(boxH1);
        boxV.add(Box.createVerticalStrut(10));
        //3°將text文字顯示區加入到滾動窗格並設定超高度出現豎直滾動條,再將滾動視窗加入到boxV中
        text=new JTextArea(9,30);
        JScrollPane jScrollPane=new JScrollPane(text);
        text.setEditable(false);
        jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        boxV.add(jScrollPane);
        boxV.add(Box.createVerticalStrut(10));
        //4°依次將從左到右“客戶端設定:",boxH1,text,boxH2加入到boxH2中,再將boxH3加入到boxV中
        boxH2.add(new JLabel("Say:"));
        boxH2.add(Box.createHorizontalStrut(5));
        text3=new JTextField();
        boxH2.add(text3);
        boxH2.add(Box.createHorizontalStrut(5));
        button2=new JButton("Say");
        boxH2.add(button2);
        boxV.add(boxH2);
        add(boxV);
    }
    private void Eventinit(){
        ac=new actionlistener();//初始化監聽器
        button1.addActionListener(ac); //監聽器註冊
        button2.addActionListener(ac);  //監聽器註冊
    }
    private void startserver(){  //點選connect按鈕後呼叫的啟動客戶端服務的方法
        try{
            client=new Socket();   //初始化客戶端套接字
            InetAddress address=InetAddress.getByName(text1.getText()); //用text1文字欄中的ip地址建立InetAddress
            InetSocketAddress socketAddress=new InetSocketAddress(address,Integer.parseInt(text2.getText())); //所連線伺服器的地址
            client.connect(socketAddress); //連線到伺服器
            text.append("Connect to server…\n"); //文字顯示區新增“Connect to server…”
            in=new DataInputStream(client.getInputStream());  //初始化輸入流
            out=new DataOutputStream(client.getOutputStream()); //初始化輸出流
            readThread=new ReadThread();   //建立讀取資料的執行緒
            readThread.start();           //執行緒開始執行
        }catch (UnknownHostException e){ //IP地址有誤,發出提示
           JOptionPane.showMessageDialog(this,"輸入IP地址有誤","警告",JOptionPane.WARNING_MESSAGE);
        }catch (IllegalArgumentException e) { //埠值非法,發出提示
            JOptionPane.showMessageDialog(this,"埠值範圍必須為0~65535","警告",JOptionPane.WARNING_MESSAGE);
        }
        catch  (IOException e) {
            JOptionPane.showMessageDialog(this,"無法連線至埠","警告",JOptionPane.WARNING_MESSAGE);
        }catch (Exception e){
            System.out.println(e.toString());
        }
    }
    private void sentmessage(){  //點選say按鈕呼叫的方法
        if(readThread==null){   //先判斷是否已經連線至伺服器,若沒有,提示並終止方法
            JOptionPane.showMessageDialog(this,"未連線無法傳送資訊","警告",JOptionPane.WARNING_MESSAGE);
            return;
        }
        try{
            out.writeUTF("Client: "+text3.getText()+"\n"); //傳送資訊至伺服器
            text.append("Client: "+text3.getText()+"\n");  //客戶端文字顯示區新增剛發過的內容
            text3.setText(""); //清空輸入欄
        }catch (IOException e){
            JOptionPane.showMessageDialog(this,"未知原因無法傳送資訊","警告",JOptionPane.WARNING_MESSAGE);
        }
    }
    class actionlistener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            if(e.getSource()==button1) startserver(); //如果點選的按鈕是connect(button1),呼叫startserver方法
            if(e.getSource()==button2) sentmessage(); //如果點選的按鈕是say(button2),呼叫sentmessage方法
        }
    }
    class ReadThread extends Thread{  //讀取資料的執行緒
        public void run(){
            while(true){
                try{
                    text.append(in.readUTF());  //讀入伺服器傳入的資訊,並顯示到文字顯示區
                }catch (IOException e) {
                    System.out.println(e.toString());
                }
            }

        }
    }
    public static void main(String[] args) {
        ClientFrame cf=new ClientFrame();
    }
}

卑微求贊

相關文章