参考:https://blog.csdn.net/qq_43842093/article/details/129964892
https://blog.csdn.net/weixin_42408447/article/details/126437276
数据类型占用字节数:
    // Java一共有8种基本数据类型:
    // 1、int占4字节,取值范围为“-2147483648~2147483647”;
    // 2、short占2字节,取值范围为“-32768~32767”;
    // 3、long占8字节;
    // 4、byte占1字节,取值范围为“-128~127”;
    // 5、float是单浮点类型,占4字节;
    // 6、double是双浮点类型,占8字节;
    // 7、char占2字节;
    // 8、boolean占1字节。

服务端:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author jay
 * @create 2023-04-12 14:59
 * 多线程下socket,服务端
 */
public class ServerSocketTest2 {
    public static void ServerStart() {
        try {
            // 初始化服务端socket并且绑定9999端口
            ServerSocket serverSocket = new ServerSocket(9999);
            // 创建一个线程池,开100个线程等待客户端连接。
            ExecutorService executorService = Executors.newFixedThreadPool(100);
            while (true) {
                // 监听socket创建的连接并接受到它,此为阻塞方法,直到连接创建。
                // 不能放到Runnable中,得到连接后才启用新线程,不然会立刻把线程池占满,一直在循环产生新线程。
                Socket socketClient = serverSocket.accept();
                Runnable runnable = () -> {
                    // 通过包类型+包长度+消息内容定义一个socket通信对象。
                    // 数据类型为byte类型,包长度为int类型,消息内容为byte类型。
                    try {
                        // 获取socket客户端输入流
                        InputStream inputStream = socketClient.getInputStream();
                        DataInputStream dataInputStream = new DataInputStream(inputStream);
                        // server端输出流,输出数据给客户端。
                        OutputStream outputStream = socketClient.getOutputStream();
                        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                        // 连接状态,客户端执行socket.shutdownOutput();后连接会被关闭。
                        while (socketClient.isConnected()) {
                            // 读取数据类型标识
                            byte b = dataInputStream.readByte();
                            // 读取数据总长度
                            int lenAccept = dataInputStream.readInt();
                            // 读取数据内容,此处要移除5个长度,是和客户端发送的内容约定好的。
                            byte[] dataAccept = new byte[lenAccept - 5];
                            dataInputStream.readFully(dataAccept);
                            // 把读取到的数据转为String
                            String strAccept = new String(dataAccept);
                            System.out.println("Server获取的数据类型为:" + b);
                            System.out.println("Server获取的数据长度为:" + lenAccept);
                            System.out.println("Server获取的数据内容为:" + strAccept);

                            // 写入,输出给客户端。
                            String strOut = "Server已接收到数据!";
                            int typeOut = 1;
                            byte[] dataOut = strOut.getBytes();
                            int lenOut = dataOut.length + 5;
                            dataOutputStream.writeByte(typeOut);// writeByte 长度1字节
                            dataOutputStream.writeInt(lenOut);// writeInt 长度4字节
                            dataOutputStream.write(dataOut);// write 长度为data[]的length长度
                            dataOutputStream.flush();// 提交输出数据
                            break;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                };
                executorService.submit(runnable);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端:

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

/**
 * @author jay
 * @create 2023-04-12 15:05
 * https://blog.csdn.net/weixin_42408447/article/details/126437276
 */
public class ClientSocket2 {
    public static void ClientStart() {
        try {
            Socket socket = new Socket("127.0.0.1", 9999);
            // 客户端输出流,输出数据给服务端。
            OutputStream outputStream = socket.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

            // 客户端输入流,获取服务端返回的数据。
            InputStream inputStream = socket.getInputStream();
            DataInputStream dataInputStream = new DataInputStream(inputStream);

            String str = "Client发送的数据!";
            int type = 1;
            byte[] data = str.getBytes();
            int len = data.length + 5;
            // len = len + type + data 的长度。
            // 客户端按顺序write,服务端同样按顺序读取。
            dataOutputStream.writeByte(type);// writeByte 长度1字节
            dataOutputStream.writeInt(len);// writeInt 长度4字节
            dataOutputStream.write(data);// write 长度为data[]的length长度
            //刷新输出流,把write提交进去,不然服务端没接收到内容。
            dataOutputStream.flush();

            // 接收Server端返回的数据
            // 读取数据类型标识
            byte b = dataInputStream.readByte();
            // 读取数据总长度
            int lenAccept = dataInputStream.readInt();
            // 读取数据内容,此处要移除5个长度,是和客户端发送的内容约定好的。
            byte[] dataAccept = new byte[lenAccept - 5];
            dataInputStream.readFully(dataAccept);
            // 把读取到的数据转为String
            String strAccept = new String(dataAccept);
            System.out.println("Client接收到返回数据:" + strAccept);
            // 关闭和释放资源
            socket.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

调用

Thread th1 = new Thread(new Runnable() {
            @Override
            public void run() {
                ServerSocketTest2.ServerStart();
            }
        });
        th1.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                ClientSocket2.ClientStart();
            }
        }).start();

调用socket.close()或者socket.shutdownOutput()方法,通知服务端数据输出已经完成。
调用这两个方法,都会结束客户端socket,但是有本质的区别。
socket.close() 将socket关闭连接,那边如果有服务端给客户端反馈信息,此时客户端是收不到的。
而socket.shutdownOutput()是将输出流关闭,此时,如果服务端有信息返回,则客户端是可以正常接收的。

posted on 2023-08-09 18:01  邢帅杰  阅读(498)  评论(0编辑  收藏  举报