Java聊天服务器:文件传输实现与优化建议
这是一个简单的Java聊天服务器,实现文件传输功能。服务器使用ServerSocket对象监听端口17500,在接收到客户端连接后,使用新线程处理客户端请求,并通过SocketUtil类中的outByFile方法发送文件给客户端。
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) throws IOException {
// 创建ServerSocket对象,监听端口17500
ServerSocket serverSocket = new ServerSocket(17500);
System.out.println('服务器已启动,正在监听端口 ' + serverSocket.getLocalPort() + ' ...');
while (true) {
// 接收客户端连接,创建Socket对象
Socket socket = serverSocket.accept();
System.out.println('接收到来自 ' + socket.getInetAddress().getHostAddress() + ':' + socket.getPort() + ' 的连接。');
// 启动新线程处理客户端请求
new Thread(() -> {
try {
// 创建SocketUtil对象
SocketUtil socketUtil = new SocketUtil(socket);
// 发送文件并等待客户端断开连接
socketUtil.outByFile('data');
System.out.println('成功发送文件给 ' + socket.getInetAddress().getHostAddress() + ':' + socket.getPort() + ' 。');
} catch (IOException e) {
System.err.println('处理客户端请求时出现异常:' + e.getMessage());
}
}).start();
}
}
static class SocketUtil {
private InputStream is;
private OutputStream os;
public SocketUtil(Socket socket) throws IOException {
// 获取输入输出流
this.is = socket.getInputStream();
this.os = socket.getOutputStream();
}
public void outByFile(String filePath) throws IOException {
String path = ChatServer.class.getResource(filePath).getPath();
FileInputStream fis = null;
try {
// 读取文件内容,并写入输出流
fis = new FileInputStream(path);
byte[] buffer = new byte[8129];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
os.flush();
// 等待客户端断开连接
while (is.available() > 0) {
Thread.sleep(100);
}
} catch (FileNotFoundException e) {
System.err.println('文件 ' + filePath + ' 不存在。');
} catch (IOException e) {
System.err.println('发送文件 ' + filePath + ' 时出现异常:' + e.getMessage());
} catch (InterruptedException e) {
System.err.println('等待客户端断开连接时出现异常:' + e.getMessage());
}
}
}
}
优化建议
- 建议将服务器IP和端口作为参数传递给程序,而不是硬编码。
- 建议设置超时时间,如果超时则关闭连接,防止客户端无法断开连接导致服务器一直等待。
- 在处理异常时,建议将异常信息记录到日志文件中,而不是仅仅输出到控制台。
代码改进
import java.io.*;
import java.net.*;
public class ChatServer {
public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.err.println('请提供服务器IP和端口号作为参数!');
System.exit(1);
}
String ip = args[0];
int port = Integer.parseInt(args[1]);
// 创建ServerSocket对象,监听端口
ServerSocket serverSocket = new ServerSocket(port, 0, InetAddress.getByName(ip));
System.out.println('服务器已启动,正在监听端口 ' + serverSocket.getLocalPort() + ' ...');
while (true) {
// 接收客户端连接,创建Socket对象
Socket socket = serverSocket.accept();
System.out.println('接收到来自 ' + socket.getInetAddress().getHostAddress() + ':' + socket.getPort() + ' 的连接。');
// 启动新线程处理客户端请求
new Thread(() -> {
try {
// 创建SocketUtil对象
SocketUtil socketUtil = new SocketUtil(socket);
// 发送文件并等待客户端断开连接
socketUtil.outByFile('data', 10000);
System.out.println('成功发送文件给 ' + socket.getInetAddress().getHostAddress() + ':' + socket.getPort() + ' 。');
} catch (IOException e) {
System.err.println('处理客户端请求时出现异常:' + e.getMessage());
// 记录异常信息到日志文件
// ...
}
}).start();
}
}
static class SocketUtil {
private InputStream is;
private OutputStream os;
public SocketUtil(Socket socket) throws IOException {
// 获取输入输出流
this.is = socket.getInputStream();
this.os = socket.getOutputStream();
}
public void outByFile(String filePath, int timeout) throws IOException {
String path = ChatServer.class.getResource(filePath).getPath();
FileInputStream fis = null;
try {
// 读取文件内容,并写入输出流
fis = new FileInputStream(path);
byte[] buffer = new byte[8129];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
os.flush();
// 等待客户端断开连接,设置超时时间
long endTime = System.currentTimeMillis() + timeout;
while (is.available() > 0 && System.currentTimeMillis() < endTime) {
Thread.sleep(100);
}
// 超时则关闭连接
if (System.currentTimeMillis() >= endTime) {
socket.close();
System.err.println('客户端连接超时,已关闭连接。');
}
} catch (FileNotFoundException e) {
System.err.println('文件 ' + filePath + ' 不存在。');
} catch (IOException e) {
System.err.println('发送文件 ' + filePath + ' 时出现异常:' + e.getMessage());
} catch (InterruptedException e) {
System.err.println('等待客户端断开连接时出现异常:' + e.getMessage());
} finally {
if (fis != null) {
fis.close();
}
}
}
}
}
代码说明
- 使用命令行参数传递服务器IP和端口号。
- 在SocketUtil类的outByFile方法中设置超时时间,如果超时则关闭连接。
- 使用finally块关闭FileInputStream,避免资源泄漏。
通过以上改进,可以提升服务器的稳定性和安全性。
原文地址: https://www.cveoy.top/t/topic/lHdV 著作权归作者所有。请勿转载和采集!