我正在制作一个程序,它接收一个文件,然后通过socket发送给客户端。客户端接收它并将其保存到文件中。这就是应该做的。
但不知何故,客户端收到的字节数组只包含0个字节,因此我的输出文件为空。这是代码:
服务器:
try {
serverSocket=new ServerSocket(7575);
serverSocket.setSoTimeout(1000000);
System.out.println("serverSocket created.");
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Error in creating new serverSocket on port 7575");
}
for(int i=0;i<array.length;i++)
System.out.println(array[i]);
Socket socket=null;
try {
System.out.println("Waiting for client...");
socket=serverSocket.accept();
System.out.println("Client accepted.");
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
PrintWriter outWriter=null;
DataOutputStream outputStream=null;
OutputStream os=null;
BufferedOutputStream bos=null;
try {
os=socket.getOutputStream();
outputStream=new DataOutputStream(os);
outWriter=new PrintWriter(socket.getOutputStream());
bos=new BufferedOutputStream(socket.getOutputStream());
System.out.println("Server streams created.");
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("sending name "+name);
outWriter.println(name);
outWriter.flush();
outWriter.println(array.length);
outWriter.println("array.length"+array.length);
outWriter.flush();
try {
os.write(array);
os.flush();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("couldnt send array of bytes");
}
try {
os.close();
outputStream.close();
socket.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
客户端:
public class Client implements Runnable {
private Socket socket;
private String folderPath;
public Client(String p)
{
folderPath=p;
}
@Override
public void run()
{
try {
System.out.println("Client connecting to localhost on 7575 port...");
socket=new Socket("localhost", 7575);
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
BufferedReader reader=null;
BufferedInputStream bis=null;
InputStream input=null;
DataInputStream in=null;
try {
System.out.println("creating streams");
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
input=socket.getInputStream();
in=new DataInputStream(input);
bis=new BufferedInputStream(socket.getInputStream());
System.out.println("streams created!");
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
String name="";
int size=0;
String s="32";
try {
name=reader.readLine();
s=reader.readLine();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
if(s!=null)
size=Integer.parseInt(s);
System.out.println("name: "+name);
System.out.println("size: "+size);
byte [] arr=new byte[size];
try {
input.read(arr);
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("couldnt read the byte array");
}
for(int i=0;i<arr.length;i++)
System.out.println(arr[i]);
FileOutputStream fos=null;
try {
fos=new FileOutputStream(folderPath+"/"+name);
} catch (FileNotFoundException ex) {
System.out.println("Could write the file");
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
try {
fos.write(arr);
fos.flush();
} catch (IOException ex) {
System.out.println("Could write the file2");
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
try {
fos.close();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
try {
in.close();
input.close();
reader.close();
socket.close();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
答案 0 :(得分:2)
在同一个流上混合二进制和文本模式很棘手。建议你不要这样做。使用DataInputStream
(用于名称,计数和文件内容)是一种可能的解决方案。 (这就是我想要的)。另一种方法是将文件内容编码为文本(例如,使用Base64编码)。
当前&#34;混合流的问题:代码在客户端。当您从BufferedReader读取名称和大小时,您将使读取器从套接字读取并缓冲多达4096个字节。问题是这些字节中的一些是文件内容。因此,当您尝试在此处阅读基础InputStream
的内容时:
input.read(arr);
你可能会发现没有什么可读的。结果:文件为空或已损坏。
还有另一个问题。您的代码假定input.read(arr)
语句将读取流的其余部分,或者直到它填充字节数组。这个假设是不正确的。当您从套接字流中读取时,read
只能返回当前可用的字节(在客户端网络堆栈中)。
再次,结果可能是一个损坏的文件。 (在这种情况下被截断。)
读取的代码应如下所示:
int count = 0;
while (count < size) {
int bytesRead = is.read(bytes, count, bytes.length - count);
if (bytesRead == -1) {
throw EOFException("didn't get a complete file");
}
count += bytesRead;
}
最后:
将文件内容读入两端的字节数组会浪费内存,对于一个非常大的文件会有问题。
你真的应该使用&#34;尝试使用资源&#34;确保所有流都正确关闭。手工操作很麻烦,并且有资源泄漏的风险。
答案 1 :(得分:1)
您可以使用DataOutputStream使用writeUTF()函数直接在输出流上写一些字符串(消息)。然后,您可以使用readUTF()方法使用DataInputStream类的对象接收消息。
你可以使用以下方式发送数据: -
String message="something";
DataOutputStream out=new DataOutputStream(socket.getOutputStream());
out.writeUTF(message);
您可以使用以下方式接收数据或消息: -
DataInputStream in=new DataInputStream(socket.getInputStream());
String message=in.readUTF();
我基本上使用这些方法从输入流中读取数据并将数据多次写入输出流并且每次都有效,所以你也应该这样检查。
答案 2 :(得分:1)
我正在制作一个程序,它接收一个文件,然后通过socket发送给客户端。客户端接收它并将其保存到文件中。这就是应该做的。
如果您不需要检查正在传递的内容,那么在我看来,直接InputStream
和OutputStream
是可行的方法。代码简单快捷,因为它避免了检查内容进行编码等的高级流类型所带来的任何开销。这也减少了破坏信息的机会。
除了
之外,我同意Stephen C的回答将文件内容读入两端的字节数组会浪费内存,对于一个非常大的文件来说会有问题。
具有将一个文件简单地移动到另一个系统而不需要查看值的特定要求,如果您知道如何处理内容,这不是问题。基本流程是
client: InputStream in = getFileInputStream();
OutputStream out = socket.getOutputStream();
byte[] bytes = new byte[BUFFER_SIZE]; // could be anything
int bytesRead;
while((bytesRead = in.read(bytes)) != -1){
out.write(bytes,0,bytesRead);
}
in.close();
out.close();
server: InputStream in = socket.getInputStream();
OutputStream out = getFileOutputStream();
// the rest is the exact same thing as the client
这将处理任何任意大小的文件,仅受服务器磁盘大小的限制。
这是我掀起的一个例子。它被认为是hacky(例如使用FILE_COUNTER
和STOP_KEY
),但我只是试图显示让用户输入文件然后在两者之间发送文件的各个方面客户端和服务器。
public class FileSenderDemo {
private static final int PORT = 7999;
private static final String STOP_KEY = "server.stop";
private static final int[] FILE_COUNTER = {0};
public static void main(String[] args) {
FileSenderDemo sender = new FileSenderDemo();
Thread client = new Thread(sender.getClient());
Thread server = new Thread(sender.getServer());
server.start();
client.start();
try {
server.join();
client.join();
} catch (InterruptedException e) {
FILE_COUNTER[0] = 999 ;
System.setProperty(STOP_KEY,"stop");
throw new IllegalStateException(e);
}
}
public void send(File f, OutputStream out) throws IOException{
try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(f),1<<11)){
byte[] bytes = new byte[1<<11];
int bytesRead;
while((bytesRead = in.read(bytes)) != -1){
out.write(bytes,0,bytesRead);
}
}
}
public Runnable getClient() {
return () -> {
while(FILE_COUNTER[0] < 3 && System.getProperty(STOP_KEY) == null) {
Socket socket;
try {
socket = new Socket("localhost", PORT);
} catch (IOException e) {
throw new IllegalStateException("CLIENT: Can't create the client: " + e.getMessage(), e);
}
File f = getFile();
try (BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream())) {
send(f, out);
} catch (IOException e) {
System.out.println("CLIENT: Failed to send file " + f.getAbsolutePath()+" due to: " + e.getMessage());
e.printStackTrace(System.err);
} finally {
FILE_COUNTER[0]++;
}
}
System.setProperty(STOP_KEY,"stop");
};
}
public File getFile(){
Scanner scanner = new Scanner(System.in);
System.out.println("CLIENT: Enter a file Name: ");
return new File(scanner.next());
}
public Runnable getServer(){
return () -> {
OutputStream out = null;
try{
ServerSocket server = new ServerSocket(PORT);
server.setSoTimeout(20000);
while(System.getProperty(STOP_KEY) == null){
Socket socket = null;
try {
socket = server.accept();
}catch (SocketTimeoutException e){
System.out.println("SERVER: Waited 20 seconds for an accept. Now checking if we need to stop.");
continue;
}
String fileName = "receivedFile_"+System.currentTimeMillis()+".content";
File outFile = new File(fileName);
out = new BufferedOutputStream(new FileOutputStream(outFile));
InputStream in = socket.getInputStream();
int bytesRead;
byte[] bytes = new byte[1<<12];
while((bytesRead = in.read(bytes)) != -1){
out.write(bytes,0,bytesRead);
}
out.close();
socket.close();
System.out.println("SERVER: Just created a new file: " + outFile.getAbsolutePath());
}
System.out.println("SERVER: " + STOP_KEY + " was not null, so quit.");
}catch (IOException e){
throw new IllegalStateException("SERVER: failed to receive the file content",e);
}finally {
if(out != null){
try{out.close();}catch (IOException e){}
}
}
};
}
}