天天看點

Java網絡程式設計,TCP與UDP模式分别實作網絡聊天室目錄TCP/IPInetAddress類TCP程式設計UDP程式設計

目錄

Java網絡程式設計,TCP與UDP模式分别實作網絡聊天室目錄TCP/IPInetAddress類TCP程式設計UDP程式設計

TCP/IP

TCP-傳輸控制協定

  • 面向連接配接的、可靠的、基于位元組流的傳輸層通信協定
  • 資料大小無限制
  • 連接配接三次握手,斷開連接配接四次握手

UDP協定-使用者資料報協定

  • 是一種無連接配接的傳輸層協定
  • 提供面向事務的簡單不可靠資訊傳送服務,每個包的大小64KB

IP協定-網際網路協定位址

  • 配置設定給物聯網裝置的唯一辨別

端口号

  • 公認端口:0~1023
  • 注冊端口:1024~49151
  • 動态或私有端口:49152~65535

常用端口

  • MySQL:3306
  • Oracle:1521
  • Tomcat:8080
  • SMTP:25
  • Web伺服器:80
  • FTP伺服器:21

InetAddress類

概念:表示網際網路協定(IP)位址對象,封裝了與該IP位址相關的所有資訊,并提供擷取資訊的常用方法

// 擷取本地主機位址對象
InetAddress inetAddress = InetAddress.getLocalHost();
// 擷取IP位址字元串
System.out.println("本機IP: " + inetAddress.getHostAddress());
// 擷取主機名
System.out.println("主機名: " + inetAddress.getHostName());
// 根據IP擷取本機對象
InetAddress byName = InetAddress.getByName("10.0.139.215");
// 擷取本機對象
InetAddress localhost = InetAddress.getByName("localhost");
// 擷取本機對象
InetAddress byName1 = InetAddress.getByName("127.0.0.1");
// 測試3秒是否可達
InetAddress byName2 = InetAddress.getByName("www.baidu.com");
System.out.println("測試3秒是否可達: " + byName2.isReachable(3000));
// 擷取所有IP
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
for (InetAddress address : allByName) {
    System.out.println(address);
}
           

TCP程式設計

步驟

伺服器端(接收端)

  1. 建立Socket連接配接,并綁定端口号
  2. 監聽
  3. 建立流
  4. 讀取資料
  5. 關閉

用戶端(發送端)

  1. 建立Socket連接配接,并綁定IP位址和端口号
  2. 建立流
  3. 讀取資料
  4. 關閉
每一端,既可以發送資料,也可以接收資料

用戶端向伺服器端發送資料

伺服器端

package com.robot.net.tcp;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 伺服器端(TCP)。
 *
 * @author 張寶旭
 */
public class TcpService {
    public static void main(String[] args) throws IOException {
        // 1、建立Socket連接配接
        ServerSocket listener = new ServerSocket(12580);
        // 2、監聽
        System.out.println("伺服器啟動成功,等待連接配接...");
        Socket client = listener.accept();
        // 3、建立接收流
        InputStream inputStream = client.getInputStream();
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
        // 4、讀取資料
        byte[] buf = new byte[1024];
        int len = bufferedInputStream.read(buf);
        if (len != -1) {
            System.out.println(new String(buf, 0, len));
        } else {
            System.out.println("讀取失敗");
        }
        // 4、關閉
        bufferedInputStream.close();
        listener.close();
    }
}
           

用戶端

package com.robot.net.tcp;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 用戶端(TCP)。
 *
 * @author 張寶旭
 */
public class TcpClient {
    public static void main(String[] args) throws IOException {
        // 1、建立連接配接
        Socket socket = new Socket("127.0.0.1", 12580);
        // 2、建立流
        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
        // 3、發送資料
        String say = "Hello";
        bufferedOutputStream.write(say.getBytes());
        // 4、關閉
        bufferedOutputStream.close();
        socket.close();
    }
}
           

用戶端向伺服器端發送檔案

package com.robot.net.tcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * TCP 傳輸檔案 伺服器端。
 *
 * @author 張寶旭
 */
public class FileServer {
    public static void main(String[] args) throws IOException {
        ServerSocket listener = new ServerSocket(12580);
        Socket client = listener.accept();
        InputStream inputStream = client.getInputStream();
        FileOutputStream fileOutputStream = new FileOutputStream("d:myTemp\\server.jpg");

        int len = 0;
        byte[] buf = new byte[1024];
        while ((len = inputStream.read(buf)) != -1) {
            fileOutputStream.write(buf, 0, len);
        }

        fileOutputStream.close();
        inputStream.close();
        listener.close();
    }
}
           
package com.robot.net.tcp;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * TCP 傳輸檔案 用戶端。
 *
 * @author 張寶旭
 */
public class FileClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 12580);
        OutputStream outputStream = socket.getOutputStream();
        FileInputStream fileInputStream = new FileInputStream("d:\\myTemp\\client.jpg");

        int len;
        byte[] buf = new byte[1024];
        while ((len = fileInputStream.read(buf)) != -1) {
            outputStream.write(buf, 0, len);
        }

        fileInputStream.close();
        outputStream.close();
        socket.close();
    }
}
           

伺服器端與用戶端互發消息

package com.robot.net.tcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * TCP 伺服器端與用戶端互發消息 伺服器端。
 *
 * @author 張寶旭
 */
public class TcpService {
    public static void main(String[] args) throws IOException {
        // 1、建立Socket連接配接
        ServerSocket listener = new ServerSocket(12580);
        // 2、監聽
        System.out.println("伺服器啟動成功,等待連接配接...");
        Socket client = listener.accept();
        // 3、建立流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
        // 4、讀取資料
        String say = bufferedReader.readLine();
        System.out.println("Client: " + say);
        // 回複資訊
        String reply = "I am Server";
        bufferedWriter.write(reply);
        bufferedWriter.newLine();
        bufferedWriter.flush();
        System.out.println("Server: " + reply);
        // 4、關閉
        bufferedWriter.close();
        bufferedReader.close();
        listener.close();
    }
}
           
package com.robot.net.tcp;

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

/**
 * TCP 伺服器端與用戶端互發消息 用戶端。
 *
 * @author 張寶旭
 */
public class TcpClient {
    public static void main(String[] args) throws IOException {
        // 1、建立連接配接
        Socket socket = new Socket("127.0.0.1", 12580);
        // 2、建立流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        // 3、發送資料
        String say = "I am Client";
        bufferedWriter.write(say);
        bufferedWriter.newLine();
        bufferedWriter.flush();
        System.out.println("Client: " + say);
        // 接收資料
        String reply = bufferedReader.readLine();
        System.out.println("Server: " + reply);
        // 4、關閉
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
    }
}
           

網絡聊天室

實作效果

多個用戶端可以連接配接同一個伺服器端,并發送消息,全部消息在伺服器端顯示

使用者類,存儲使用者資訊

package com.robot.net.chat;

/**
 * 使用者類。
 * 
 * @author 張寶旭
 */
public class User {
    private String name;
    private int age;
    private String gender;

    public User() {
    }

    public User(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}
           

工具類

可根據IP位址,在存儲使用者的map中查找此IP的使用者,并傳回

package com.robot.net.chat;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 張寶旭
 */
public class Tool {
    /**
     * 根據IP位址,查找使用者
     * @param map 使用者集合
     * @param ip IP位址
     * @return 查找到的使用者
     */
    public static User getUserBuIp(ConcurrentHashMap<String, User> map, String ip) {
        for (Map.Entry<String, User> entry : map.entrySet()) {
            if (entry.getKey().equals(ip)) {
                return entry.getValue();
            }
        }
        return null;
    }
}
           

伺服器端

所有用戶端的聊天都會傳輸到伺服器端,每個用戶端使用者需要提前加入到群聊中,才可聊天。

package com.robot.net.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * TCP 網絡聊天室 伺服器端。
 * 所有用戶端的聊天都會傳輸到伺服器端。
 * 每個用戶端使用者需要提前加入到群聊中,才可聊天。
 *
 * @author 張寶旭
 */
public class Server {
    public static void main(String[] args) {

        ExecutorService pool = Executors.newCachedThreadPool();

        // 鍵:IP位址,值:使用者
        ConcurrentHashMap<String, User> map = new ConcurrentHashMap<>();

        // 臨時初始化一個使用者
        map.put("127.0.0.1", new User("zbx", 21, "男"));

        ServerSocket listener = null;
        try {
            // 建立Socket
            listener = new ServerSocket(12580);
            System.out.println("伺服器啟動成功");

            // 擷取多個連接配接,每個連接配接開啟一個線程去接收
            while (true) {
                Socket client = listener.accept();
                // 根據IP位址,查找使用者
                User user = Tool.getUserBuIp(map, client.getInetAddress().getHostAddress());
                if (user == null) {
                    System.out.println(client.getInetAddress().getHostAddress() + " 連接配接失敗,群裡沒有此使用者");
                } else {
                    System.out.println(user.getName() + " 加入聊天");
                    pool.submit(new Reply(user, client));
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert listener != null;
                listener.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
           

伺服器端處理資料的線程

伺服器端每次收到一個用戶端的請求連接配接,就會建立一個線程來執行任務

package com.robot.net.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 伺服器端負責接收處理資料的線程。
 *
 * @author 張寶旭
 */
public class Reply implements Runnable {
    Socket socket = null;
    BufferedReader bufferedReader = null;
    User user;


    public Reply() {
    }

    public Reply(User user, Socket socket) {
        this.socket = socket;
        this.user = user;
    }

    @Override
    public void run() {
        try {
            // 擷取流
            bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 讀取資料
            while (true) {

                // 讀取消息
                String receive = bufferedReader.readLine();
                if (receive == null) {
                    System.out.println(user.getName() + "異常退出");
                    break;
                }

                // 結束條件
                if (receive.equals("bye")) {
                    System.out.println(user.getName() + "退出聊天");
                    break;
                }

                // 列印資料
                System.out.println(user.getName() + "--->" + receive);

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
           

用戶端

向伺服器端發送消息

package com.robot.net.chat;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

/**
 * TCP 網絡聊天室 用戶端。
 *
 * @author 張寶旭
 */
public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        BufferedWriter bufferedWriter = null;
        try {
            socket = new Socket("127.0.0.1", 12580);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            Scanner scanner = new Scanner(System.in);
            // 可以連續發送消息
            while (true) {
                String say = scanner.next();
                bufferedWriter.write(say);
                bufferedWriter.newLine();
                bufferedWriter.flush();
                System.out.println("client::" + say);
                if (say.equals("bye")) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert bufferedWriter != null;
                bufferedWriter.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
           

UDP程式設計

步驟

伺服器端(接收端)

  1. 建立Socket,并綁定端口号
  2. 建立資料報包
  3. 接收資料
  4. 處理資料
  5. 關閉

用戶端(發送端)

  1. 建立Socket
  2. 建立資料報包,并綁定發送IP和端口号
  3. 發送資料
  4. 關閉
每一端,既可以發送資料,也可以接收資料

用戶端向伺服器端發送資料

伺服器端

package com.robot.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author 張寶旭
 */
public class receive {
    public static void main(String[] args) throws IOException {
        // 建立Socket,并綁定端口号
        DatagramSocket datagramSocket = new DatagramSocket(6666);
        // 建立緩沖區
        byte[] buf = new byte[1024];
        // 建立資料報包
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
        // 接收資料
        datagramSocket.receive(datagramPacket);
        // 擷取資料
        byte[] data = datagramPacket.getData();
        // 列印資料
        System.out.println(new String(data, 0, data.length));
        // 關閉
        datagramSocket.close();
    }
}
           

用戶端

package com.robot.net.udp;

import java.io.IOException;
import java.net.*;

/**
 * @author 張寶旭
 */
public class Send {
    public static void main(String[] args) throws IOException {
        // 建立Socket
        DatagramSocket datagramSocket = new DatagramSocket();
        // 建立要發送的資料,并轉換為位元組
        byte[] buf = "Hello".getBytes();
        // 建立資料報包,并綁定發送IP和端口号
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 6666);
        // 發送資料
        datagramSocket.send(datagramPacket);
        // 關閉
        datagramSocket.close();
    }
}
           

網絡聊天室

實作效果

一個伺服器端可以連接配接多個用戶端,每個用戶端都可以向伺服器端發送消息, 并顯示在伺服器端

伺服器端

package com.robot.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * UDP 網絡聊天室 伺服器端。
 * @author 張寶旭
 */
public class ChatReceive {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        try {
            datagramSocket = new DatagramSocket(8899);
            System.out.println("聊天室啟動");
            while (true) {
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                datagramSocket.receive(packet);
                byte[] data = packet.getData();
                System.out.println(packet.getAddress().getHostAddress() + "::" +new String(data, 0, data.length));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            assert datagramSocket != null;
            datagramSocket.close();
        }
    }
}
           

用戶端

package com.robot.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
 * @author 張寶旭
 */
public class ChatSend {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        try {
            datagramSocket = new DatagramSocket();
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.println("輸入消息,回車發送");
                String next = scanner.next();
                DatagramPacket packet = new DatagramPacket(next.getBytes(), next.getBytes().length,
                        InetAddress.getByName("10.0.139.255"), 8899);
                datagramSocket.send(packet);
                System.out.println("發送成功");
                if (next.equals("bye")) {
                    System.out.println("退出聊天");
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            assert datagramSocket != null;
            datagramSocket.close();
        }
    }
}
anner = new Scanner(System.in);
            while (true) {
                System.out.println("輸入消息,回車發送");
                String next = scanner.next();
                DatagramPacket packet = new DatagramPacket(next.getBytes(), next.getBytes().length,
                        InetAddress.getByName("10.0.139.255"), 8899);
                datagramSocket.send(packet);
                System.out.println("發送成功");
                if (next.equals("bye")) {
                    System.out.println("退出聊天");
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            assert datagramSocket != null;
            datagramSocket.close();
        }
    }
}