Java 基礎【03】TCP


    不積跬步,無以至千里;不積小流,無以成江海。——《荀子勸學》

   JAVA 中設計網絡編程模式的主要有TCP和UDP兩種。

   TCP 是屬於即時通信,點對點連接進行通信。

   UDP 是通過數據包來進行通信,UDP當中就會牽扯到數據的解析和傳送。

   在安全性能方面,TCP 要略勝一籌,通信過程中不容易出現數據丟失的現象,有一方中斷,兩方的通信就會結束。

   UDP 數據包傳送的過程當中,一方中斷,數據包有很大的可能丟失,還有可能傳來的數據包的順序是錯亂的。

   在效率方面,UDP 要比 TCP 快的不只是一點點的問題,若終端有解析數據方法的函數,數據包就會源源不斷的傳送過來,然后反饋回去。

public class Server {
    static BufferedReader br; //服務器端的輸入流
    static PrintStream ps; //服務器端的輸出流
    static JTextArea text; //服務器相關的界面組件

    public Server() {
        JFrame frame = new JFrame("服務器端");
        text = new JTextArea();
        JScrollPane scroll = new JScrollPane(text);
        frame.add(scroll);
        frame.setVisible(true);
        frame.setSize(300, 400);
        text.setEditable(false);
    }

    public static void main(String[] args) throws Exception {
        new Server();    //生成服務器界面
        //通過服務器端構造函數  ServerSocket(port) 實例化一個服務器端口
        ServerSocket server = new ServerSocket(2000);
        text.append("監聽2000端口" + "\n");
        Socket client = server.accept();
        br = new BufferedReader(new InputStreamReader(client.getInputStream()));
        ps = new PrintStream(client.getOutputStream());
        String msg;
        //如果輸入流不為空,將接受到的信息打印到相應的文本框中並反饋回收到的信息
        while ((msg = br.readLine()) != null) {
            text.append("服務器端收到:" + msg + "\n");
            ps.println(msg);
            if (msg.equals("quit")) {
                text.append("客戶端“2000”已退出!" + "\n");
                text.append("服務器程序將退出!");
                break;
            }
        }
        ps.close();
        br.close();
        client.close();
    }
}

 

 Client類:

public class Client implements ActionListener {
    //這里有兩個圖形界面,一個是連接的frame,另一個和服務器通信的界面frame1
    private JFrame frame;
    private JLabel adress;
    private JLabel port;
    JTextField adresstext;
    JTextField porttext;
    JButton connect;

    private JFrame frame1;
    private JLabel shuru;
    private JPanel panel1;
    private JPanel panel2;
    private JLabel jieshou;
    JButton send;
    static JTextArea shurukuang;
    static TextArea jieshoukuang;

    static BufferedReader br1; //從服務端接受的數據流
    static PrintStream ps; //從客戶端輸出的數據流
    static BufferedReader br2;  //從通信界面中的輸入框接受的數據流
    static Socket client;
    //將輸入框字符串轉換為字符串流所需的字符串的輸入流
    static ByteArrayInputStream stringInputStream;

    public Client() {
        frame = new JFrame();
        adress = new JLabel("IP 地址");
        port = new JLabel("端口號");
        adresstext = new JTextField("127.0.0.1", 10);
        porttext = new JTextField("2000", 10);
        connect = new JButton("連接");
        //連接界面的布局
        frame.setLayout(new FlowLayout());
        frame.add(adress);
        frame.add(adresstext);
        frame.add(port);
        frame.add(porttext);
        frame.add(connect);
        frame.setVisible(true);
        frame.setSize(200, 150);
        connect.addActionListener(this);
        //通信界面的實例化
        frame1 = new JFrame();
        shuru = new JLabel("請輸入");
        shurukuang = new JTextArea("請輸入····", 5, 40);

        panel1 = new JPanel();
        panel1.add(shuru);
        panel1.add(shurukuang);
        panel1.setLayout(new FlowLayout());

        send = new JButton("發送");
        panel2 = new JPanel();
        jieshou = new JLabel("已接受");

        jieshoukuang = new TextArea(8, 60);
        jieshoukuang.setEditable(false);

        panel2.add(jieshou);
        panel2.add(jieshoukuang);
        panel2.setLayout(new FlowLayout());
        frame1.setLayout(new FlowLayout());
        //通信界面都的布局
        frame1.add(BorderLayout.NORTH, panel1);
        frame1.add(send);
        frame1.add(BorderLayout.SOUTH, panel2);
        //連接時通信界面是處於看不到的
        frame1.setVisible(false);
        frame1.setSize(500, 350);
        send.addActionListener(this);
    }

    //兩個界面當中都有相應的按鈕時間,為相應的時間添加動作
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == connect) {
            try {
                //當觸發連接按鈕時,實例化一個客戶端
                client = new Socket("127.0.0.1", 2000);
                //隱藏連接界面,顯示通信界面
                frame.setVisible(false);
                frame1.setVisible(true);
                jieshoukuang.append("已經連接上服務器!" + "\n");
            } catch (IOException e1) {
                System.out.println("鏈接失敗!");
                e1.printStackTrace();
            }
        }
        //通信界面中的發送按鈕相應的時間處理
        if (e.getSource() == send) {
            //將輸入框中的字符串轉換為字符串流
            stringInputStream = new ByteArrayInputStream((shurukuang.getText()).getBytes());
            br2 = new BufferedReader(new InputStreamReader(stringInputStream));
            String msg;
            try {
                while ((msg = br2.readLine()) != null) {
                    ps.println(msg);   //將輸入框中的內容發送給服務器端
                    jieshoukuang.append("向服務器發送:" + msg + "\n");
                    jieshoukuang.append("客戶端接受相應:" + br1.readLine() + "\n");
                    if (msg.equals("quit")) {
                        jieshoukuang.append("客戶端將退出!");
                        br1.close();
                        ps.close();
                        client.close();
                        frame1.setVisible(false);
                        break;
                    }
                }
            } catch (IOException e2) {
                System.out.println("讀輸入框數據出錯!");
            }
            shurukuang.setText("");
        }
    }

    public static void main(String[] args) throws IOException {
        new Client();  //實例化連接界面
        client = new Socket("127.0.0.1", 2000);
        br1 = new BufferedReader(new InputStreamReader(client.getInputStream()));     //從服務端接受的數據
        ps = new PrintStream(client.getOutputStream());        //從客戶端輸出的數據
    }
}

 寫完這兩個類以后還是有幾個問題:

1)main 函數為什么非要用 static 來修飾?

2)緩沖對象 BufferedReader 為什么不能直接用於判斷,非要將讀到的數據賦值給字符串來進行操作?

3)在連接界面當中的 Connect 按鈕事件 當中我有實例化一個 客戶端的對象,注釋掉主函數中 client=new Socket("127.0.0.1",2000)會發現拋出 NULLPOINTEXCEPTION 異常,我很不理解?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM