java - java客户端-服务器通信中的问题
问题描述
我已经在 java 中实现了客户端-服务器通信。以下是传输一组文件的代码:
服务器代码:
public class TransferServer {
static List<String> filesListInDir = new ArrayList<String>();
static String zipName = "tmp.tar.gz";
public static void main(String[] args) throws IOException, InterruptedException {
// TODO Auto-generated method stub
ServerSocket s1 = new ServerSocket(7104);
System.out.println("Transfer server started");
while (true) {
Socket sckt = s1.accept();
System.out.println("Request received. Please wait..");
zipData();
transferData(sckt);
System.out.println("Data transferred");
}
}
private static void transferData(Socket ts) throws IOException {
FileInputStream fi=new FileInputStream(zipName);
byte b[] = new byte[8000];
fi.read(b, 0, b.length);
OutputStream os = ts.getOutputStream();
os.write(b, 0, b.length);
fi.close();
}
客户端代码:
public class Fetchmyfile {
static String addr_list="/home/pi/addresslist.txt";
static String zipName = "tmp.tar.gz";
public static void main(String[] args) throws InterruptedException, IOException {
// TODO Auto-generated method stub
trigger();
}
private static void trigger() throws InterruptedException, IOException {
// TODO Auto-generated method stub
String[] hostList = readAddressList(addr_list);
//remove tmp.zip
for (int i = 0; i < hostList.length; i++) {
Runtime r = Runtime.getRuntime();
Process p = null;
try {
p = r.exec("rm /home/pi/combined_data/"+hostList[i]+"/"+zipName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p.waitFor();
}
//remove complete
for (int i = 0; i < hostList.length; i++) {
String addr = hostList[i];
TransferClient clientInstance = new TransferClient();
clientInstance.fileCopy(addr, "/home/pi/combined_data/"+addr.trim()+"/tmp.tar.gz");
}
System.out.println("All data has been transferred");
}
private static String[] readAddressList(String addr_list) throws IOException {
FileReader fileReader = new FileReader(addr_list);
BufferedReader bufferedReader = new BufferedReader(fileReader);
List<String> lines = new ArrayList<String>();
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
lines.add(line);
}
bufferedReader.close();
System.out.println("Loaded the host list");
return lines.toArray(new String[lines.size()]);
}
}
public class TransferClient {
public boolean fileCopy(String sensor_node_ip, String filename) throws InterruptedException{
//public static void main(String args[]) throws IOException
{
try {
//String filename = "‎�‎�localfile.zip";
byte b[] = new byte[8000];
Socket s = null;
try {
s = new Socket(sensor_node_ip, 7104);
System.out.println("connection done");
} catch (IOException e) {
System.out.println("Couldn't connect to the server");
return false;
}
InputStream iss = s.getInputStream();
FileOutputStream fr = new FileOutputStream(filename);
iss.read(b, 0, b.length);
fr.write(b, 0, b.length);
fr.close();
s.close();
//unZip(filename);
System.out.println("Tar file recieved from " + sensor_node_ip);
return true;
}
catch (IOException e){
return false;
}
}
}
我面临的问题是,对于一个相对较大的文件,客户端创建一个具有预期名称的声明缓冲区大小的文件。但是该文件不可读并且是存档文件,无法提取。然而,服务器实际上拥有无论如何都是正确的文件。这可能是什么原因。任何建议/指针都非常感谢。
解决方案
如我所见,问题是您正在写入 8000 字节,而不管输出的实际大小。您甚至没有尝试检查文件的大小,因此如果文件小于 8000 字节,您可能会写入垃圾,或者如果文件超过 8000 字节,则可能会截断它。
相反,您应该读取文件直到没有更多字节要读取,并确保您只写入实际读取的字节数(因为读取的字节数可能小于缓冲区长度)。
这确实是基本的 I/O。
因此,下面的示例将概念剥离为基本概念,仅关注客户端和服务器之间的文件传输。为了比较,我在每一端都添加了一个 MD5 检查,所以比较文件结果很容易。
编程的一个重要方面是,永远不要假设任何事情。始终查看您获得的内容并在运行时做出决定(例外情况是,如果它已预先记录并达成一致,但即便如此,我也会仔细检查,因为我不信任任何人)
服务器
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
public class Server {
public static void main(String[] args) {
try (ServerSocket server = new ServerSocket(7104)) {
Socket socket = server.accept();
read(socket);
} catch (IOException ex) {
ex.printStackTrace();
}
}
protected static void read(Socket socket) {
File target = new File("Target.file");
try (InputStream is = socket.getInputStream(); OutputStream os = new FileOutputStream(target)) {
byte bytes[] = new byte[1024];
int bytesRead = -1;
while ((bytesRead = is.read(bytes)) != -1) {
os.write(bytes, 0, bytesRead);
}
System.out.println("Server MD5 = " + Util.getMD5Checksum(target));
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
}
客户
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
public class Client {
public static void main(String[] args) {
try {
File source = new File(<BYO own file>);
System.out.println("Client MD5 = " + Util.getMD5Checksum(source));
try (Socket socket = new Socket("127.0.0.1", 7104); OutputStream os = socket.getOutputStream(); FileInputStream fis = new FileInputStream(source)) {
byte bytes[] = new byte[1024];
int bytesRead = -1;
while ((bytesRead = fis.read(bytes)) != -1) {
os.write(bytes, 0, bytesRead);
}
} catch (IOException exp) {
}
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
}
MD5
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Util {
protected static byte[] createChecksum(File filename) throws IOException, NoSuchAlgorithmException {
try (InputStream fis = new FileInputStream(filename)) {
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
complete.update(buffer, 0, numRead);
}
} while (numRead != -1);
return complete.digest();
}
}
// see this How-to for a faster way to convert
// a byte array to a HEX string
public static String getMD5Checksum(File filename) throws IOException, NoSuchAlgorithmException {
byte[] b = createChecksum(filename);
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
}
我强烈建议您花时间阅读Basic I/O,这些是您将一直重复使用的概念。
推荐阅读
- html - 如何制作一个按钮列表以在移动设备上显示两列?
- java - 如何在 Spring Boot Web 应用程序的 Bean 初始化代码中获取随机 http 端口?
- java - 用于授权 API 请求的 YouTube 帐户必须与用户的 Google 帐户合并
- blazor-webassembly - 将参数传递给根组件 Blazor 程序集
- c# - 如何在 C# 中的操作中添加另一个操作?
- gdb - msys2 中的 gdb 无法正常工作(点击“运行”后的“ModuleNotFoundError”和“无法插入断点”)
- materialize - 如何在materializecss optgroup中的标签中添加复选框?
- javascript - FontAwesome 图标 onClick() 事件未按预期工作
- javascript - Mock.mockImplementation 不是函数
- liferay - 如何在 Liferay 主菜单中打开外部应用程序链接 (D3)