您的位置:首页 > 教育 > 锐评 > 濮阳新闻网_百度seo报价_seo自动推广软件_bt最佳磁力搜索引擎

濮阳新闻网_百度seo报价_seo自动推广软件_bt最佳磁力搜索引擎

2025/2/24 23:15:17 来源:https://blog.csdn.net/x1343676/article/details/143220409  浏览:    关键词:濮阳新闻网_百度seo报价_seo自动推广软件_bt最佳磁力搜索引擎
濮阳新闻网_百度seo报价_seo自动推广软件_bt最佳磁力搜索引擎

chapter04(网络文件传输)

BufferReader类

BufferedReader 是 Java 中用来包装一个 Reader 对象的类,它提供了一个缓冲区,可以提高读取文本数据的效率。BufferedReader 通常用于逐行读取文本文件,因为它提供了 readLine() 方法,该方法一次读取一行文本。

以下是 BufferedReader 的一些常见用法:

创建 BufferedReader

要使用 BufferedReader,你首先需要创建一个实例。这通常是通过将现有的 Reader 对象(如 FileReader)传递给 BufferedReader 的构造函数来完成的。

FileReader fileReader = new FileReader("path/to/file.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
读取文本

使用 readLine() 方法逐行读取文本:

String line;
while ((line = bufferedReader.readLine()) != null) {System.out.println(line);
}
关闭 BufferedReader

读取完成后,应该关闭 BufferedReader(以及它包装的 Reader),以释放系统资源。

bufferedReader.close();
其他读取方法

除了 readLine()BufferedReader 还提供了其他方法来读取文本:

  • read():读取单个字符。
  • read(char[] cbuf):将字符读入数组。
  • read(char[] cbuf, int off, int len):从缓冲区读取字符到数组的某个部分。
示例代码

下面是一个使用 BufferedReader 读取文件内容的完整示例:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class BufferedReaderExample {public static void main(String[] args) {String filePath = "path/to/file.txt";try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}
}

在这个示例中,我们使用了 try-with-resources 语句来自动关闭 BufferedReader

注意事项
  • BufferedReader 是用于文本数据的,而不是二进制数据。
  • 读取操作可能会抛出 IOException,因此需要适当的异常处理。
  • 在读取大文件时,使用缓冲区可以显著提高性能,因为它减少了实际的磁盘访问次数。

如果你在处理二进制文件,应该使用 BufferedInputStream 或其他相关的输入流类。

FileOutputStream类

当你使用 FileOutputStream 来创建一个用于写入文件的输出流时,你可以直接将字节数据写入到一个文件中。FileOutputStreamOutputStream 的子类,专门用于将数据写入文件。

以下是如何使用 FileOutputStream 来写入数据到文件的示例:

创建 FileOutputStream

首先,你需要创建一个 FileOutputStream 实例,指定你想要写入数据的文件。

import java.io.FileOutputStream;
import java.io.File;File saveFile = new File("path/to/your/file.txt");
FileOutputStream fileOut = new FileOutputStream(saveFile);
写入数据

使用 write() 方法将字节数据写入文件。

byte[] data = ...; // 这里是你要写入文件的数据
fileOut.write(data);
关闭 FileOutputStream

完成写入操作后,应该关闭 FileOutputStream 以释放系统资源。

fileOut.close();
示例代码

下面是一个完整的示例,演示如何使用 FileOutputStream 将字节数据写入文件:

import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;public class FileWriteExample {public static void main(String[] args) {File saveFile = new File("path/to/your/file.txt");byte[] data = ...; // 这里是你要写入文件的数据try (FileOutputStream fileOut = new FileOutputStream(saveFile)) {fileOut.write(data);} catch (IOException e) {e.printStackTrace();}}
}

在这个示例中,我们使用了 try-with-resources 语句来自动关闭 FileOutputStream

注意事项
  • 确保在写入数据前文件路径是有效的,并且你有足够的权限写入文件。
  • 写入操作可能会抛出 IOException,因此需要适当的异常处理。
  • 如果文件不存在,FileOutputStream 将会创建它。
  • 如果文件已经存在,使用 FileOutputStream 写入将会覆盖原有内容。如果你想追加到现有文件,应该使用 FileOutputStream 的另一个构造函数:new FileOutputStream(file, true)

这样,你就可以使用 FileOutputStream 将字节数据写入到文件中了。

向socket写入字符串

在 Java 中,PrintWriter 是一个方便的类,用于向流写入字符数据。它支持方法如 print()println()printf(),这些方法可以方便地将各种数据类型转换为字符串并写入流。

OutputStreamWriter 是一个将字节流转换成字符流的桥梁,它使用指定的字符集将字节数据解码为字符数据。OutputStreamWriter 本身不缓存输出,因此如果你需要提高效率,通常会将它包装在一个 BufferedWriter 中。

在你的代码示例中:

new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);

以下是各个部分的解释:

  1. OutputStreamWriter

    • 它接受一个字节输出流(在这个例子中是 socketOut,即 Socket 的输出流)。
    • 它使用指定的字符集(这里是 StandardCharsets.UTF_8)将字节转换为字符。
  2. PrintWriter

    • 它接受一个 Writer 对象(这里是 OutputStreamWriter 的实例)。
    • 第二个参数 true 表示使用自动刷新模式。这意味着每当缓冲区满了或者新的行分隔符被写入时,PrintWriter 会自动刷新其内部缓冲区。这对于网络应用程序很有用,因为它可以确保数据及时发送到网络上。
示例代码

下面是一个完整的示例,演示如何使用 PrintWriter 通过 Socket 发送字符串数据:

import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class SocketExample {public static void main(String[] args) {try (Socket socket = new Socket("hostname", port)) {// 获取 Socket 的输出流OutputStreamWriter outputStreamWriter = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);// 创建 PrintWriter,自动刷新模式PrintWriter printWriter = new PrintWriter(outputStreamWriter, true);// 发送字符串数据printWriter.println("Hello, World!");// 关闭 PrintWriter,它会自动刷新并关闭 OutputStreamWriterprintWriter.close();} catch (Exception e) {e.printStackTrace();}}
}
注意事项
  • 自动刷新PrintWriter 的自动刷新模式非常有用,因为它确保数据及时发送。
  • 字符集:使用 StandardCharsets.UTF_8 可以确保文本数据在不同平台和语言环境中的一致性。
  • 异常处理:网络操作可能会抛出异常,因此需要适当的异常处理。
  • 资源管理:使用 try-with-resources 语句可以确保 Socket 在使用后被正确关闭。

这样,你就可以使用 PrintWriter 通过 Socket 发送字符串数据了。

读取socket字节数据返回字符

private BufferedReader getReader(Socket socket) throws IOException {//获得输入流缓冲区的地址InputStream socketIn = socket.getInputStream();//读取字节数据返回字符串return new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));
}

关闭通信套接字

public void getFile(File saveFile) throws IOException {if (dataSocket != null) {FileOutputStream fileOut = new FileOutputStream(saveFile); // 新建本地空文件byte[] buf = new byte[1024]; // 用来缓存接收的字节数据// (2)向服务器发送请求的文件名,字符串读写功能pw.println("require " + saveFile.getName());pw.flush(); // 确保数据发送到服务器// (3)接收服务器的数据文件,字节读写功能int size;// 这里服务器端必须退出输出流,要不然会一直读取while ((size = bir.read(buf)) != -1) { // 读一块到缓存,读取结束返回-1fileOut.write(buf, 0, size); // 写一块到文件System.out.println("读取到的数据大小" + size);}System.out.println("getfile函数结束了");fileOut.flush(); // 关闭前将缓存的数据全部推出fileOut.close(); // 关闭文件输出流}
}

如果你发现 while 循环一直无法退出,可能有几个原因:

  1. 服务器没有正确关闭连接:服务器端在发送完数据后应该关闭其输出流(通常是 Socket 的输出流),这样客户端在读取完数据后会得到一个 -1,表示连接已经关闭。

  2. 客户端读取到非预期的数据:如果客户端读取到非预期的数据,如空数据或持续的心跳包,它可能会一直读取而不退出。

  3. 阻塞模式Socket 默认是阻塞模式,如果服务器端没有数据发送,客户端的 read() 方法将会一直阻塞等待。

  4. 异常处理:如果在读取过程中发生异常,并且没有正确处理,可能会导致循环无法退出。

  5. 服务器端代码逻辑:服务器端代码可能存在逻辑问题,没有正确处理文件发送后的连接关闭。

  6. 客户端代码逻辑:客户端代码可能没有正确处理从服务器接收到的数据,例如,如果服务器发送的数据超过了缓冲区的大小,可能会导致问题。

为了解决这个问题,你可以尝试以下步骤:

  • 确保服务器端发送完数据后关闭输出流

    // 服务器端发送完数据后
    socket.shutdownOutput();
    
  • 在客户端添加超时设置
    你可以为 Socket 设置读取超时,这样如果服务器在指定时间内没有发送数据,read() 方法将会超时并返回 -1。

    dataSocket.setSoTimeout(5000); // 设置读取超时为5000毫秒
    
  • 检查服务器端代码:确保服务器端在发送完文件后正确关闭了连接。

  • 检查客户端代码:确保客户端正确处理了从服务器接收到的数据。

  • 添加异常处理:确保你添加了适当的异常处理,以便在发生错误时能够正确处理。

  • 调试:使用调试工具或打印日志来查看循环中发生了什么,这可能会帮助你找到问题所在。

  • 检查网络问题:确保网络连接没有问题,没有丢包或连接不稳定的情况。

设计思路

文本通信占用2021端口,将socket的输入输出流封装成PrinterWriterBufferedReader方便使用

// 得到网络输出字节流地址,并封装成网络输出字符流
// 设置最后一个参数为true,表示自动flush数据
OutputStream socketOut = socket.getOutputStream();
// 将字符转成字节数据输出到流中
pw = new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);// 得到网络输入字节流地址,并封装成网络输入字符流
InputStream socketIn = socket.getInputStream();
// 将socket的字节(输出)转变成字符
br = new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));

文件数据通信占用2020端口,向socket写入依旧是字符转成字节,但是获取socket的数据(字节),直接使用字节类型数据写入到文件流对象(或者包装一下,但都是字节数据)

private final Socket dataSocket;
private final PrintWriter pw; // 定义字符输出流
private final BufferedInputStream bir; // 定义字符输入流public FileDataClient(String ip, String port) throws IOException {dataSocket = new Socket(ip, Integer.parseInt(port));// 得到网络输出字节流地址,并封装成网络输出字符流// 设置最后一个参数为true,表示自动flush数据OutputStream socketOut = dataSocket.getOutputStream();pw = new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);// 得到网络输入字节流地址InputStream socketIn = dataSocket.getInputStream();bir = new BufferedInputStream(socketIn);
}

线程设计

  • 服务器端
    • msgThread: 用于接收客户端请求构建通信套接字并监听/发送信息
    • fileThread: 用于接收客户端的请求构建用于文件数据通信通信套接字并监听/发送信息(数据)
  • 客户端
    • 主线程: UI更新
    • 子线程: receiveMsgThread -> 用于接收服务器信息的单独线程,持续监听接收信息,实时显示

最终代码

FileClientFx
package client;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;import java.io.File;
import java.io.IOException;public class FileClientFx extends Application {private final Button btnCon = new Button("连接");private final Button btnExit = new Button("退出");private final Button btnSend = new Button("发送");private final Button btnDownload = new Button("下载");private final TextField IpAdd_input = new TextField();private final TextField Port_input = new TextField();private final TextArea OutputArea = new TextArea();private final TextField InputField = new TextField();private FileDialogClient fileDialogClient;private Thread receiveMsgThread = null;private String ip, port;public static void main(String[] args) {launch(args);}public void start(Stage primaryStage) {primaryStage.setTitle("文件传输");btnSend.setDisable(true);BorderPane mainPane = new BorderPane();VBox mainVBox = new VBox();HBox hBox = new HBox();hBox.setSpacing(10);//各控件之间的间隔//HBox面板中的内容距离四周的留空区域hBox.setPadding(new Insets(20, 20, 10, 20));hBox.getChildren().addAll(new Label("IP地址: "), IpAdd_input, new Label("端口: "), Port_input, btnCon);hBox.setAlignment(Pos.TOP_CENTER);//内容显示区域VBox vBox = new VBox();vBox.setSpacing(10);//各控件之间的间隔//VBox面板中的内容距离四周的留空区域vBox.setPadding(new Insets(10, 20, 10, 20));vBox.getChildren().addAll(new Label("信息显示区:"), OutputArea, new Label("信息输入区"), InputField);//设置显示信息区的文本区域可以纵向自动扩充范围VBox.setVgrow(OutputArea, Priority.ALWAYS);// 设置文本只读和自动换行OutputArea.setEditable(false);OutputArea.setStyle("-fx-wrap-text: true; /* 实际上是默认的 */ -fx-font-size: 14px;");InputField.setOnKeyPressed(event -> {if (event.getCode() == KeyCode.ENTER) {btnSend.fire();}});//底部按钮区域HBox hBox2 = new HBox();hBox2.setSpacing(10);hBox2.setPadding(new Insets(10, 20, 10, 20));// 重构thread,使用runnable接口,不要使用lambda表达式class ReceiveHandler  implements Runnable{@Overridepublic void run(){String msg = null;// 不知道服务器有多少回传信息,就持续不断接收// 由于在另外一个线程,不会阻塞主线程的正常运行while ((msg = fileDialogClient.receive()) != null) {String msgTemp = msg; // msgTemp 实质是final类型Platform.runLater(() -> {OutputArea.appendText(msgTemp + "\n");});}// 跳出了循环,说明服务器已关闭,读取为null,提示对话关闭Platform.runLater(() -> {OutputArea.appendText("对话已关闭!\n");});}}// 设置按钮的交互效果btnCon.setOnAction(event -> {ip = IpAdd_input.getText().trim();port = Port_input.getText().trim();// 设置不能再次点击btnCon.setDisable(true);try {fileDialogClient = new FileDialogClient(ip, port);// 用于接收服务器信息的单独线程receiveMsgThread = new Thread(new ReceiveHandler(), "receiveThread");receiveMsgThread.start(); // 启动线程btnSend.setDisable(false);} catch (Exception e) {OutputArea.appendText("服务器连接失败!" + e.getMessage() + "\n");}});btnDownload.setOnAction(event -> {if (InputField.getText().equals("")) //没有输入文件名则返回return;String fName = InputField.getText().trim();InputField.clear();FileChooser fileChooser = new FileChooser();fileChooser.setInitialFileName(fName);File saveFile = fileChooser.showSaveDialog(null);if (saveFile == null) {return;//用户放弃操作则返回}try {//数据端口是2020FileDataClient fdclient = new FileDataClient(ip, "2020");fdclient.getFile(saveFile);Alert alert = new Alert(Alert.AlertType.INFORMATION);alert.setContentText(saveFile.getName() + " 下载完毕!");alert.showAndWait();//通知服务器已经完成了下载动作,不发送的话,服务器不能提供有效反馈信息fileDialogClient.send("客户端开启下载");} catch (IOException e) {e.printStackTrace();}});btnExit.setOnAction(event -> {if (fileDialogClient != null) {//// 新增代码try {//向服务器发送关闭连接的约定信息fileDialogClient.send("bye");// 等待子线程和服务器 收到/读取信息完毕再关闭输入输出流,这样不会报错Thread.sleep(500);fileDialogClient.close();btnSend.setDisable(true);// 等待线程回收资源receiveMsgThread.join();} catch (Exception e) {System.out.println(e.getMessage());}}System.exit(0);});Port_input.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {@Overridepublic void handle(KeyEvent event) {if (event.getCode() == KeyCode.ENTER) {btnCon.fire();}}});//信息显示区鼠标拖动高亮文字直接复制到信息输入框,方便选择文件名//taDispaly 为信息选择区的 TextArea,tfSend 为信息输入区的 TextField//为 taDisplay 的选择范围属性添加监听器,当该属性值变化(选择文字时)会触发监听器中的代码OutputArea.selectionProperty().addListener((observable, oldValue, newValue) -> {//只有当鼠标拖动选中了文字才复制内容if(!OutputArea.getSelectedText().equals(""))InputField.setText(OutputArea.getSelectedText());});btnSend.setOnAction(event -> {String sendMsg = InputField.getText();fileDialogClient.send(sendMsg);//向服务器发送一串字符InputField.clear();OutputArea.appendText("客户端发送:" + sendMsg + "\n");});hBox2.setAlignment(Pos.CENTER_RIGHT);hBox2.getChildren().addAll(btnSend, btnDownload, btnExit);mainVBox.getChildren().addAll(hBox, vBox, hBox2);VBox.setVgrow(vBox, Priority.ALWAYS);mainPane.setCenter(mainVBox);Scene scene = new Scene(mainPane, 700, 400);IpAdd_input.setText("127.0.0.1");Port_input.setText("8888");primaryStage.setScene(scene);primaryStage.show();}
}
FileDialogClient
package client;import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class FileDialogClient {private final Socket socket; // 定义套接字private final PrintWriter pw; // 定义字符输出流private final BufferedReader br; // 定义字符输入流public FileDialogClient(String ip, String port) throws IOException {// 主动向服务器发起连接,实现TCP的三次握手过程// 如果不成功,则抛出错误信息,其错误信息交由调用者处理socket = new Socket(ip, Integer.parseInt(port));// 得到网络输出字节流地址,并封装成网络输出字符流// 设置最后一个参数为true,表示自动flush数据OutputStream socketOut = socket.getOutputStream();pw = new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);// 得到网络输入字节流地址,并封装成网络输入字符流InputStream socketIn = socket.getInputStream();br = new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));}public void send(String msg) {// 输出字符流,由Socket调用系统底层函数,经网卡发送字节流pw.println(msg);}public String receive() {String msg = null;try {// 从网络输入字符流中读信息,每次只能接收一行信息// 如果不够一行(无行结束符),则该语句阻塞等待msg = br.readLine();} catch (IOException e) {e.printStackTrace();}return msg;}// 实现close方法以关闭socket连接及相关的输入输出流public void close() {try {if (pw != null) {pw.close(); // 关闭PrintWriter会先flush再关闭底层流}if (br != null) {br.close(); // 关闭BufferedReader}if (socket != null) {socket.close(); // 关闭Socket连接}} catch (IOException e) {e.printStackTrace();}}
}
FileDataClient
package client;import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class FileDataClient {private final Socket dataSocket;private final PrintWriter pw; // 定义字符输出流private final BufferedInputStream bir; // 定义字符输入流public FileDataClient(String ip, String port) throws IOException {dataSocket = new Socket(ip, Integer.parseInt(port));// 得到网络输出字节流地址,并封装成网络输出字符流// 设置最后一个参数为true,表示自动flush数据OutputStream socketOut = dataSocket.getOutputStream();pw = new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);// 得到网络输入字节流地址InputStream socketIn = dataSocket.getInputStream();bir = new BufferedInputStream(socketIn);}public void getFile(File saveFile) throws IOException {if (dataSocket != null) {FileOutputStream fileOut = new FileOutputStream(saveFile); // 新建本地空文件byte[] buf = new byte[1024]; // 用来缓存接收的字节数据// (2)向服务器发送请求的文件名,字符串读写功能pw.println("require " + saveFile.getName());pw.flush(); // 确保数据发送到服务器// (3)接收服务器的数据文件,字节读写功能int size;// 这里服务器端必须退出输出流,要不然会一直读取// 直接使用dataSocket.getInputStream()也可以while ((size = bir.read(buf)) != -1) { // 读一块到缓存,读取结束返回-1fileOut.write(buf, 0, size); // 写一块到文件System.out.println("读取到的数据大小" + size);}System.out.println("getfile函数结束了");fileOut.flush(); // 关闭前将缓存的数据全部推出fileOut.close(); // 关闭文件输出流}}
}
FileDialogServer
package server;import java.io.*;
import java.math.RoundingMode;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.Scanner;public class FileDialogServer {public static ServerSocket msgserverSocket = null;public static ServerSocket fileserverSocket = null;public void fileListPushToClient(PrintWriter pw) {String path = "d:/ftpserver"; // 给出服务器下载目录路径File filePath = new File(path);if (!filePath.exists()) { // 路径不存在则返回System.out.println("ftp下载目录不存在");return;}if (!filePath.isDirectory()) { // 如果不是一个目录就返回System.out.println("不是一个目录");return;}// 开始显示目录下的文件,不包括子目录String[] fileNames = filePath.list();File tempFile;// 格式化文件大小输出,不保留小数,不用四舍五入,有小数位就进1DecimalFormat formater = new DecimalFormat();formater.setMaximumFractionDigits(0);formater.setRoundingMode(RoundingMode.CEILING);for (String fileName : fileNames) {tempFile = new File(filePath, fileName);if (tempFile.isFile()) {pw.println(fileName + "  " + formater.format(tempFile.length() / (1024.0)) + "KB");}}}private PrintWriter getWriter(Socket socket) throws IOException {//获得输出流缓冲区的地址OutputStream socketOut = socket.getOutputStream();//将字符转为字节写入到socketreturn new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);}private BufferedReader getReader(Socket socket) throws IOException {//获得输入流缓冲区的地址InputStream socketIn = socket.getInputStream();//读取字节数据返回字符串return new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));}public void msgService() throws IOException {msgserverSocket = new ServerSocket(2021);System.out.println("Server is running on port 2021");Thread msgThread = new Thread(() -> {while (true) {Socket socket = null;try {socket = msgserverSocket.accept();} catch (IOException e) {throw new RuntimeException(e);}System.out.println("New client connected");try {PrintWriter pw = getWriter(socket);fileListPushToClient(pw);BufferedReader br = getReader(socket);String msg;while ((msg = br.readLine()) != null) {if ("bye".equals(msg)) {break;}// 处理其他消息}} catch (Exception e) {System.out.println("Error while handling client: " + e.getMessage());e.printStackTrace();} finally {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}, "msgThread");msgThread.start();}public void fileService() throws IOException {fileserverSocket = new ServerSocket(2020);System.out.println("fileServer is running on port 2020");Thread fileThread = new Thread(() -> {while (true) {Socket socket = null;try {socket = fileserverSocket.accept();System.out.println("New file client connected");} catch (IOException e) {throw new RuntimeException(e);}try {PrintWriter pw = getWriter(socket);fileListPushToClient(pw);BufferedReader br = getReader(socket);String msg;while ((msg = br.readLine()) != null) {if (msg.startsWith("require ")) {System.out.println(msg);// 服务器请求文件String fileName = msg.substring(8);File requiredFile = new File("d:/ftpserver/" + fileName);// 读取文件Scanner sc = new Scanner(requiredFile, "UTF-8");while (sc.hasNextLine()) { // 使用hasNextLine()确保换行符不会重复添加pw.println(sc.nextLine()); // 输出文件的内容,字节类型}}System.out.println("文件没内容了,哥们");socket.close();// 处理其他消息}} catch (Exception e) {System.out.println("Error while handling client: " + e.getMessage());e.printStackTrace();} finally {try {socket.close();System.out.println("socket关闭");} catch (IOException e) {throw new RuntimeException(e);}}}});fileThread.start();}public static void main(String[] args) {try {FileDialogServer server = new FileDialogServer();server.msgService();server.fileService();} catch (Exception e) {e.printStackTrace();}}
}
点击退出报错Socket closed原因

因为直接点击退出可能会发送bye之后立刻执行到关闭socket,但是子线程还在阻塞等待读写socket,所以运行到子线程时报错–线程不可控性

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com