[英]java Filetransfer with SocketChannel
I have problem with filetransfer using SocketChannels: client ends to transfer the file, but the server still wait more byte from client. 我在使用SocketChannels进行文件传输时遇到问题:客户端结束了文件的传输,但是服务器仍然等待来自客户端的更多字节。 This causes a timeout, and the file will be saved less than a small part. 这会导致超时,并且文件保存的时间将少于一小部分。 The server remains stucked here: "fileChannel.transferFrom(socketChannel, 0, fileLength);". 服务器仍然卡在这里:“ fileChannel.transferFrom(socketChannel,0,fileLength);”。 Everything that happens before is working properly. 之前发生的所有事情都可以正常工作。
server: 服务器:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import javax.imageio.ImageIO;
public class RequestHandler implements Runnable {
private SocketChannel socketChannel;
BufferedReader stringIn;
public RequestHandler(SocketChannel socketChannel) {
this.socketChannel = socketChannel;
// this.serverSocketChannel = socketChannel;
System.out.println("RequestHandler initialized");
}
public static int getLastPush(String dir) {
return new File("./" + dir).listFiles().length + 1;
}
public void run() {
LoadConfig config = null;
try {
config = new LoadConfig();
} catch (IOException e) {
e.printStackTrace();
}
String type = null;
try {
socketChannel.socket().setSoTimeout(10000);
MainServer.log("Client connected from: " + socketChannel);
// Prendere immagine
DataInputStream dis = new DataInputStream(socketChannel.socket().getInputStream());
// Leggo string
stringIn = new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));
// Invio al client
DataOutputStream dos = new DataOutputStream(socketChannel.socket().getOutputStream());
// leggo in ricezione
MainServer.log("Attendo auth");
String auth = stringIn.readLine();
// check auth
MainServer.log("Auth ricevuto: " + auth);
String pass = config.getPass();
if (pass.equals(auth)) {
dos.writeBytes("OK\n");
System.out.println("Client Authenticated");
type = stringIn.readLine();
System.out.println("fileType: " + type);
dos.writeBytes(type + "\n");
Integer i = getLastPush(config.getFolder());
String fileName = i.toString();
System.out.println("fileName: " + fileName);
switch (type) {
case "img":
// transfer image
int len = dis.readInt();
System.out.println("Transfer started.");
byte[] data = new byte[len];
dis.readFully(data);
System.out.println("Transfer ended.");
File toWrite = new File(config.getFolder() + "/" + fileName + ".png");
ImageIO.write(ImageIO.read(new ByteArrayInputStream(data)), "png", toWrite);
dos.writeBytes("http://" + config.getDomain() + "/" + toWrite.getName());
break;
case "file":
// transfer file
System.out.println("Transfer started.");
readFileFromSocket(config.getFolder() + "/" + fileName + ".zip");
System.out.println("Transfer ended.");
System.out.println("Sending link...");
dos.writeBytes("http://" + config.getDomain() + "/" + fileName + ".zip");
break;
default:
}
i++;
System.out.println("Chiudo");
dos.close();
dis.close();
stringIn.close();
} else {
dos.writeBytes("Invalid Id or Password");
System.out.println("Invalid Id or Password");
dos.close();
dis.close();
stringIn.close();
}
socketChannel.close();
} catch (Exception exc) {
exc.printStackTrace();
}
System.out.println("----------");
}
public void readFileFromSocket(String fileName) {
RandomAccessFile aFile = null;
try {
aFile = new RandomAccessFile(fileName, "rw");
FileChannel fileChannel = aFile.getChannel();
long fileLength = Long.parseLong(stringIn.readLine());
System.out.println("File length: " + fileLength);
fileChannel.transferFrom(socketChannel, 0, fileLength);
fileChannel.close();
Thread.sleep(1000);
fileChannel.close();
System.out.println("End of file reached, closing channel");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
client: 客户:
import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import javax.imageio.ImageIO;
public class Uploader {
private BufferedImage img;
private byte[] bytes;
private SocketChannel socketChannel;
private String link;
private String fileName;
DataOutputStream dos;
// Per gli screen parziali
public Uploader(Rectangle r, String ip, int port) throws IOException, AWTException {
SocketChannel socketChannel = createChannel(ip, port);
this.socketChannel = socketChannel;
Rectangle screenRect = new Rectangle(0, 0, 0, 0);
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
screenRect = screenRect.union(gd.getDefaultConfiguration().getBounds());
}
this.img = new Robot().createScreenCapture(screenRect).getSubimage(r.x, r.y, r.width, r.height);
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
ImageIO.write(img, "png", outputArray);
outputArray.flush();
this.bytes = outputArray.toByteArray();
outputArray.close();
}
// Per gli screen completi
public Uploader(BufferedImage bi, String ip, int port) throws IOException {
SocketChannel socketChannel = createChannel(ip, port);
this.socketChannel = socketChannel;
this.img = bi;
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
ImageIO.write(img, "png", outputArray);
outputArray.flush();
this.bytes = outputArray.toByteArray();
outputArray.close();
}
// Per i file
public Uploader(String fileName, String ip, int port) throws UnknownHostException, IOException {
SocketChannel socketChannel = createChannel(ip, port);
this.socketChannel = socketChannel;
// this.socket = new Socket(ip, port);
this.fileName = fileName;
}
public void send(String pass, String type) throws IOException {
dos = new DataOutputStream(socketChannel.socket().getOutputStream());
BufferedReader stringIn = new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));
try {
socketChannel.socket().setSoTimeout(10000);
// send auth
System.out.println("Sending auth");
dos.writeBytes(pass + "\n");
System.out.println("Auth sent: " + pass);
this.link = stringIn.readLine();
// this.link = os.println();
System.out.println("Auth reply: " + link);
if (this.link.equals("OK")) {
System.out.println("Sending type: " + type);
dos.writeBytes(type + "\n");
// Controllo e aspetto che il server abbia ricevuto il type
// corretto
if (stringIn.readLine().equals(type)) {
System.out.println("Il server riceve un: " + type);
switch (type) {
// image transfer
case "img":
System.out.println("Uploading image...");
dos.writeInt(bytes.length);
dos.write(bytes, 0, bytes.length);
dos.flush();
break;
// file transfer
case "file":
sendFile(fileName);
break;
// default case, hmm
default:
break;
}
// return link
System.out.println("Waiting link...");
this.link = stringIn.readLine();
System.out.println("Returned link: " + link);
bytes = null;
} else {
System.out.println("The server had a bad interpretation of the fileType");
}
} else {
System.out.println("Closed");
}
dos.close();
stringIn.close();
socketChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public SocketChannel createChannel(String ip, int port) {
SocketChannel socketChannel = null;
try {
socketChannel = SocketChannel.open();
SocketAddress socketAddress = new InetSocketAddress(ip, port);
socketChannel.connect(socketAddress);
System.out.println("Connected, now sending the file...");
} catch (IOException e) {
e.printStackTrace();
}
return socketChannel;
}
public void sendFile(String fileName) {
RandomAccessFile aFile = null;
try {
File file = new File(fileName);
aFile = new RandomAccessFile(file, "r");
FileChannel inChannel = aFile.getChannel();
long bytesSent = 0, fileLength = file.length();
System.out.println("File length: " + fileLength);
dos.writeBytes(fileLength + "\n");
// send the file
while (bytesSent < fileLength) {
bytesSent += inChannel.transferTo(bytesSent, fileLength - bytesSent, socketChannel);
}
inChannel.close();
Thread.sleep(1000);
System.out.println("End of file reached..");
aFile.close();
System.out.println("File closed.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getLink() {
return link;
}
}
You're losing data in the BufferedReader
. 您正在BufferedReader
丢失数据。 If you look at the file that has been received you'll see that part of it is missing at the beginning. 如果您查看已收到的文件,则会在开始时看到该文件的一部分丢失。
You can't mix buffered and unbuffered input on the same channel. 您不能在同一通道上混合使用缓冲和非缓冲输入。 I suggest you use a DataInputStream
and use read/writeUTF()
to transfer the filename, and read/writeLong()
to transfer the length. 我建议您使用DataInputStream
并使用read/writeUTF()
传输文件名,并使用read/writeLong()
传输长度。
I can't imagine why you're using different code to transfer images and other files. 我无法想象为什么您使用不同的代码来传输图像和其他文件。 It's all bytes. 全部都是字节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.