参考:https://blog.csdn.net/qq_43842093/article/details/129964892
https://blog.csdn.net/weixin_42408447/article/details/126437276
数据类型占用字节数:
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(); } }
 
                    
                 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号