【Socket網絡編程進階與實戰】------- Socket TCP快速入門

前言

Socket TCP快速入門,demo練習


TCP

在這裏插入圖片描述

TCP機制

在這裏插入圖片描述

TCP鏈接,傳輸流程

在這裏插入圖片描述

TCP能做什麼

在這裏插入圖片描述

TCP核心API

在這裏插入圖片描述
在這裏插入圖片描述

  • 客戶端創建流程
    在這裏插入圖片描述
  • 服務器端流程
    在這裏插入圖片描述

擴展-Socket與進程之間的關係

在這裏插入圖片描述

  • 基礎類型數據傳輸
    在這裏插入圖片描述

案例:


package com.zcw.demo4;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;

/**
 * @ClassName : Client
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 18:03
 */
public class Client {
    private static final int PORT = 20000;
    private static final int LOCAL_PORT = 20001;

    public static void main(String[] args) throws IOException {
        Socket socket = createSocket();

        initSocket(socket);

        // 鏈接到本地20000端口,超時時間3秒,超過則拋出超時異常
        socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), PORT), 3000);

        System.out.println("已發起服務器連接,並進入後續流程~");
        System.out.println("客戶端信息:" + socket.getLocalAddress() + " P:" + socket.getLocalPort());
        System.out.println("服務器信息:" + socket.getInetAddress() + " P:" + socket.getPort());

        try {
            // 發送接收數據
            todo(socket);
        } catch (Exception e) {
            System.out.println("異常關閉");
        }

        // 釋放資源
        socket.close();
        System.out.println("客戶端已退出~");

    }

    private static Socket createSocket() throws IOException {
        /*
        // 無代理模式,等效於空構造函數
        Socket socket = new Socket(Proxy.NO_PROXY);

        // 新建一份具有HTTP代理的套接字,傳輸數據將通過www.baidu.com:8080端口轉發
        Proxy proxy = new Proxy(Proxy.Type.HTTP,
                new InetSocketAddress(Inet4Address.getByName("www.baidu.com"), 8800));
        socket = new Socket(proxy);

        // 新建一個套接字,並且直接鏈接到本地20000的服務器上
        socket = new Socket("localhost", PORT);

        // 新建一個套接字,並且直接鏈接到本地20000的服務器上
        socket = new Socket(Inet4Address.getLocalHost(), PORT);

        // 新建一個套接字,並且直接鏈接到本地20000的服務器上,並且綁定到本地20001端口上
        socket = new Socket("localhost", PORT, Inet4Address.getLocalHost(), LOCAL_PORT);
        socket = new Socket(Inet4Address.getLocalHost(), PORT, Inet4Address.getLocalHost(), LOCAL_PORT);
        */

        Socket socket = new Socket();
        // 綁定到本地20001端口
        socket.bind(new InetSocketAddress(Inet4Address.getLocalHost(), LOCAL_PORT));

        return socket;
    }

    private static void initSocket(Socket socket) throws SocketException {
        // 設置讀取超時時間爲2秒
        socket.setSoTimeout(2000);

        // 是否複用未完全關閉的Socket地址,對於指定bind操作後的套接字有效
        socket.setReuseAddress(true);

        // 是否開啓Nagle算法
        socket.setTcpNoDelay(true);

        // 是否需要在長時無數據響應時發送確認數據(類似心跳包),時間大約爲2小時
        socket.setKeepAlive(true);

        // 對於close關閉操作行爲進行怎樣的處理;默認爲false,0
        // false、0:默認情況,關閉時立即返回,底層系統接管輸出流,將緩衝區內的數據發送完成
        // true、0:關閉時立即返回,緩衝區數據拋棄,直接發送RST結束命令到對方,並無需經過2MSL等待
        // true、200:關閉時最長阻塞200毫秒,隨後按第二情況處理
        socket.setSoLinger(true, 20);

        // 是否讓緊急數據內斂,默認false;緊急數據通過 socket.sendUrgentData(1);發送
        socket.setOOBInline(true);

        // 設置接收發送緩衝器大小
        socket.setReceiveBufferSize(64 * 1024 * 1024);
        socket.setSendBufferSize(64 * 1024 * 1024);

        // 設置性能參數:短鏈接,延遲,帶寬的相對重要性
        socket.setPerformancePreferences(1, 1, 0);
    }

    private static void todo(Socket client) throws IOException {
        // 得到Socket輸出流
        OutputStream outputStream = client.getOutputStream();


        // 得到Socket輸入流
        InputStream inputStream = client.getInputStream();
        byte[] buffer = new byte[256];
        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);

        // byte
        byteBuffer.put((byte) 126);

        // char
        char c = 'a';
        byteBuffer.putChar(c);

        // int
        int i = 2323123;
        byteBuffer.putInt(i);

        // bool
        boolean b = true;
        byteBuffer.put(b ? (byte) 1 : (byte) 0);

        // Long
        long l = 298789739;
        byteBuffer.putLong(l);


        // float
        float f = 12.345f;
        byteBuffer.putFloat(f);


        // double
        double d = 13.31241248782973;
        byteBuffer.putDouble(d);

        // String
        String str = "Hello你好!";
        byteBuffer.put(str.getBytes());

        // 發送到服務器
        outputStream.write(buffer, 0, byteBuffer.position() + 1);

        // 接收服務器返回
        int read = inputStream.read(buffer);
        System.out.println("收到數量:" + read);

        // 資源釋放
        outputStream.close();
        inputStream.close();
    }
}



package com.zcw.demo4;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;

/**
 * @ClassName : Server
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 18:06
 */
public class Server {
    private static final int PORT = 20000;

    public static void main(String[] args) throws IOException {
        ServerSocket server = createServerSocket();

        initServerSocket(server);

        // 綁定到本地端口上
        server.bind(new InetSocketAddress(Inet4Address.getLocalHost(), PORT), 50);


        System.out.println("服務器準備就緒~");
        System.out.println("服務器信息:" + server.getInetAddress() + " P:" + server.getLocalPort());


        // 等待客戶端連接
        for (; ; ) {
            // 得到客戶端
            Socket client = server.accept();
            // 客戶端構建異步線程
            ClientHandler clientHandler = new ClientHandler(client);
            // 啓動線程
            clientHandler.start();
        }

    }

    private static ServerSocket createServerSocket() throws IOException {
        // 創建基礎的ServerSocket
        ServerSocket serverSocket = new ServerSocket();

        // 綁定到本地端口20000上,並且設置當前可允許等待鏈接的隊列爲50個
        //serverSocket = new ServerSocket(PORT);

        // 等效於上面的方案,隊列設置爲50個
        //serverSocket = new ServerSocket(PORT, 50);

        // 與上面等同
        // serverSocket = new ServerSocket(PORT, 50, Inet4Address.getLocalHost());

        return serverSocket;
    }

    private static void initServerSocket(ServerSocket serverSocket) throws IOException {
        // 是否複用未完全關閉的地址端口
        serverSocket.setReuseAddress(true);

        // 等效Socket#setReceiveBufferSize
        serverSocket.setReceiveBufferSize(64 * 1024 * 1024);

        // 設置serverSocket#accept超時時間
        // serverSocket.setSoTimeout(2000);

        // 設置性能參數:短鏈接,延遲,帶寬的相對重要性
        serverSocket.setPerformancePreferences(1, 1, 1);
    }

    /**
     * 客戶端消息處理
     */
    private static class ClientHandler extends Thread {
        private Socket socket;

        ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            super.run();
            System.out.println("新客戶端連接:" + socket.getInetAddress() +
                    " P:" + socket.getPort());

            try {
                // 得到套接字流
                OutputStream outputStream = socket.getOutputStream();
                InputStream inputStream = socket.getInputStream();

                byte[] buffer = new byte[256];
                int readCount = inputStream.read(buffer);
                ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, readCount);

                // byte
                byte be = byteBuffer.get();

                // char
                char c = byteBuffer.getChar();

                // int
                int i = byteBuffer.getInt();

                // bool
                boolean b = byteBuffer.get() == 1;

                // Long
                long l = byteBuffer.getLong();

                // float
                float f = byteBuffer.getFloat();

                // double
                double d = byteBuffer.getDouble();

                // String
                int pos = byteBuffer.position();
                String str = new String(buffer, pos, readCount - pos - 1);

                System.out.println("收到數量:" + readCount + " 數據:"
                        + be + "\n"
                        + c + "\n"
                        + i + "\n"
                        + b + "\n"
                        + l + "\n"
                        + f + "\n"
                        + d + "\n"
                        + str + "\n");

                outputStream.write(buffer, 0, readCount);
                outputStream.close();
                inputStream.close();

            } catch (Exception e) {
                System.out.println("連接異常斷開");
            } finally {
                // 連接關閉
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            System.out.println("客戶端已退出:" + socket.getInetAddress() +
                    " P:" + socket.getPort());

        }
    }
}


  • 測試:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

package com.zcw.demo4;

/**
 * @ClassName : Tools
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 18:07
 */
public class Tools {
    public static int byteArrayToInt(byte[] b) {
        return b[3] & 0xFF |
                (b[2] & 0xFF) << 8 |
                (b[1] & 0xFF) << 16 |
                (b[0] & 0xFF) << 24;
    }

    public static byte[] intToByteArray(int a) {
        return new byte[]{
                (byte) ((a >> 24) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) (a & 0xFF)
        };
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章