参考: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()是将输出流关闭,此时,如果服务端有信息返回,则客户端是可以正常接收的。

java通过Socket发送文件,服务端示例:

ServerSocket serverSocket = new ServerSocket(9999);

        while (true) {
            try {
                // 等待客户端连接。阻塞直到有客户端连接,然后返回一个Socket对象。
                var socket = serverSocket.accept();
                // 创建输入流,用于接收客户端发送的数据。
                var in = socket.getInputStream();
                // 创建输出流,用于向客户端发送数据。
                var out = socket.getOutputStream();

                // 读取客户端发送的数据,并将其存储在缓存区中。
                DataInputStream dis = new DataInputStream(in);
                // 创建数据输出流,用于向客户端发送数据。
                DataOutputStream dos = new DataOutputStream(out);
                // 缓存区,用于暂存从客户端接收的数据。
                byte[] buffer = new byte[1024];

                String endOfFile = "END_OF_FILE";
                byte[] endOfFileBuffer = endOfFile.getBytes(StandardCharsets.UTF_8);
                int endOfFileByteLen = endOfFileBuffer.length;

                // 读取到客户端发送的数据长度。
                int bytesRead;
                //发送文件路径。E:\Demos\JavaProject\xcgwebapp\LawsonSOT_2.3.6.zip
                File desFile = new File("LawsonSOT_2.3.6.zip");
                long fileLength = desFile.length();
                String fileName = desFile.getName();
                String cmd = "nameAndLength," + fileName + "," + fileLength + "\r\n";
                byte[] bytesCmd = cmd.getBytes(StandardCharsets.UTF_8);
                // 发送文件名和长度信息,确保接收方知道接下来要读取的文件大小等信息。
//                byte[] bytes = Arrays.copyOf(bytesCmd, 1024);
//                out.write(bytes, 0, 1024);
                dos.write(bytesCmd);
                dos.flush();

                try (FileInputStream fis = new FileInputStream(desFile)) {
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        dos.write(buffer, 0, bytesRead);
                    }
                    dos.write(endOfFileBuffer);
                    dos.flush();
                    System.out.println("文件发送完成。");
                } catch (Exception e) {
                    logger.error("文件发送异常:" + e.getMessage(), e);
                }
            } catch (Exception e) {
                logger.error("异常:" + e.getMessage(), e);
            }
        }

java通过Socket发送文件,客户端接收文件示例:

FileOutputStream fos = null;
        try {
            Socket socket = new Socket();
            String ip = "172.30.250.170";
            socket.connect(new InetSocketAddress(ip, 9999), 2000);
            if (socket.isConnected()) {
                InputStream inputStream = socket.getInputStream();
                DataInputStream dis = new DataInputStream(inputStream);
                OutputStream outputStream = socket.getOutputStream();
                DataOutputStream dos = new DataOutputStream(outputStream);
//                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
//                  String nameAndLength = br.readLine();

                int bytesRead;
                byte[] buffer = new byte[1024];
                String endOfFile = "END_OF_FILE";
                byte[] endOfFileBuffer = endOfFile.getBytes(StandardCharsets.UTF_8);
                int endOfFileByteLen = endOfFileBuffer.length;

                //是否到文件末尾
                boolean isEndOfFile = false;
                File desFile = null;
                while (!isEndOfFile && ((bytesRead = dis.read(buffer)) != -1)) {
                    String res = new String(buffer, StandardCharsets.UTF_8);
                    if (res.startsWith("nameAndLength")) {
                        String[] commandOrg = res.split("\r\n");
                        //逗号分隔
                        String[] command1 = commandOrg[0].trim().split("\\,");
                        //文件名
                        String fileName1 = command1[1].trim();
                        //文件长度
                        long fileLength = Long.valueOf(command1[2].trim());
                        desFile = new File(fileName1);
                        if (desFile.exists()) {
                            desFile.delete();
                            desFile.createNewFile();
                        }
                    } else if (res.contains("END_OF_FILE")) {
                        int k = 0;
                        for (int i = 0; i <= buffer.length - endOfFileBuffer.length; i++) {
                            if (Arrays.equals(Arrays.copyOfRange(buffer, i, i + endOfFileBuffer.length), endOfFileBuffer)) {
                                k = i;
                                break;
                            }
                        }
                        if (k != 0) {
                            fos = new FileOutputStream(desFile, true);
                            fos.write(buffer, 0, k);
                            fos.flush();
                            fos.close();
                        }
                        isEndOfFile = true;
                        break;
                    } else {
                        fos = new FileOutputStream(desFile, true);
                        fos.write(buffer, 0, bytesRead);
                        fos.flush();
                        fos.close();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

 

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