如何修复线程 "main" java.io.EOFException 中的异常? (java 套接字)
How to fix Exception in thread "main" java.io.EOFException? (java socket)
我想使用 java 套接字创建一个简单的多文件传输程序。
服务器输出:
I am server
The server is listening...
Client are connected
Files Selected : 2
README.txt
vcruntime140.dll
Server Closed!
客户端输出:
i am client
Server are connected
filecount : 2
filenames : README.txt
Exception in thread "main" java.io.EOFException at
java.io.DataInputStream.readFully(Unknown Source) at
java.io.DataInputStream.readLong(Unknown Source) at
socket.client.main(client.java:32)
这是我的服务器代码!服务器是发件人。
public static void main(String[] args) throws Exception {
System.out.println("i am server");
System.out.println("");
server = new ServerSocket(12345);
System.out.println("Server is listening...");
client = server.accept();
System.out.println("Client are connected");
dos = new DataOutputStream(client.getOutputStream());
dir = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
byte[] b = new byte[4096];
for (File file : files)
{
long length = file.length();
dos.writeLong(length);
String filename = file.getName();
dos.writeUTF(filename);
System.out.println(file.getName());
fis = new FileInputStream(file);
while (fis.read(b) != -1)
{
fis.read(b, 0, b.length);
dos.write(b, 0, b.length);
}
}
System.out.println("");
fis.close();
client.close();
server.close();
System.out.println("Server Closed!");
}
这是我的客户端代码!客户是接收者。
public static void main(String[] args) throws Exception {
System.out.println("i am client");
System.out.println("");
soc = new Socket("localhost", 12345);
System.out.println("Server are connected");
dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i=0;i<filecount;i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filenames : "+filename);
files[i] = new File(dirPath + "/" + filename);
fos = new FileOutputStream(files[i]);
for(int j = 0; j < filelength; j++)
{
fos.write(b);
dis.read(b);
}
}
System.out.println("data received!");
fos.flush();
fos.close();
soc.close();
System.out.println("client closed!");
}
我期待客户端的输出:
文件数:2
文件名:README.txtvcruntime140.dll
在服务器端,您在读取输入文件流时每次循环迭代调用 fis.read()
两次。每次迭代只需调用一次,并且需要将 fis.read()
的 return 值传递给 dos.write()
,以便它知道要写入的正确字节数。
在客户端,在读取文件流时,您在调用 dis.read()
之前调用 fos.write()
以使用数据填充 b
。而且你循环了太多次,因为你没有用每次迭代实际读取的字节数更新你的 j
循环计数器。
尝试更像这样的东西:
服务器:
public static void main(String[] args) throws Exception
{
System.out.println("i am server");
System.out.println("");
ServerSocket server = new ServerSocket(12345);
System.out.println("Server is listening...");
Socket client = server.accept();
System.out.println("Client is connected");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String dir = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
Files[] files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
byte[] b = new byte[4096];
for (File file : files)
{
long filelength = file.length();
dos.writeLong(filelength);
String filename = file.getName();
dos.writeUTF(filename);
System.out.println(filename);
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = DataInputStream(fis);
int loops = (int) (filelength / (long) b.length);
int remainder = (int) (filelength % (long) b.length);
for (int j = 0; j < loops; j++)
{
dis.readFully(b);
dos.write(b);
}
if (remainder > 0)
{
dis.readFully(b, 0, remainder);
dos.write(b, 0, remainder);
}
}
System.out.println("");
dos.close();
server.close();
System.out.println("Server Closed!");
}
客户:
public static void main(String[] args) throws Exception
{
System.out.println("i am client");
System.out.println("");
Socket soc = new Socket("localhost", 12345);
System.out.println("Server is connected");
DataInputStream dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i = 0; i < filecount; i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filename : " + filename);
files[i] = new File(dirPath + "/" + filename);
FileOutputStream fos = new FileOutputStream(files[i]);
int loops = (int) (filelength / (long) b.length);
int remainder = (int) (filelength % (long) b.length);
for (int j = 0; j < loops; j++)
{
dis.readFully(b);
fos.write(b);
}
if (remainder > 0)
{
dis.readFully(b, 0, remainder);
fos.write(b, 0, remainder);
}
}
System.out.println("data received!");
dis.close();
System.out.println("client closed!");
}
举个例子说明如何使用 Google Gauva library, here is your code changed to use a couple of utility classes from Guava, ByteStreams
and Files
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ClientServerGuava {
private static final int PORT = 12345;
public static void main(String[] args) throws IOException {
Thread serverThread = new ServerThread();
serverThread.start();
runClient();
}
private static void runClient() throws IOException {
System.out.println("i am client");
System.out.println("");
Socket soc = new Socket("localhost", PORT);
System.out.println("Server are connected");
DataInputStream dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i=0;i<filecount;i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filenames : "+filename);
files[i] = new File(filename);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(files[i]));
InputStream limitedStream = ByteStreams.limit(dis, filelength);
ByteStreams.copy(limitedStream, bos);
bos.close();
}
System.out.println("data received!");
dis.close();
soc.close();
System.out.println("client closed!");
}
private static class ServerThread extends Thread {
private static final String DIR = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
@Override
public void run() {
try {
System.out.println("i am server");
System.out.println("");
ServerSocket server = new ServerSocket(PORT);
System.out.println("Server is listening...");
Socket client = server.accept();
System.out.println("Client are connected");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String dir = DIR;
File[] files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
for (File file : files) {
dos.writeLong(file.length());
dos.writeUTF(file.getName());
System.out.println(file.getName());
Files.copy(file, dos);
}
System.out.println("");
dos.close();
client.close();
server.close();
System.out.println("Server Closed!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
注意读取循环的消除。您确实应该学习如何编写读取循环的代码,但在实践中,依赖受支持的、经过分析的、成熟的、优化的库,您可能会得到更好的服务。我相信 Apache commons-io 具有类似的功能。
我想使用 java 套接字创建一个简单的多文件传输程序。
服务器输出:
I am server The server is listening... Client are connected Files Selected : 2 README.txt vcruntime140.dll Server Closed!
客户端输出:
i am client Server are connected filecount : 2 filenames : README.txt
Exception in thread "main" java.io.EOFException at java.io.DataInputStream.readFully(Unknown Source) at java.io.DataInputStream.readLong(Unknown Source) at socket.client.main(client.java:32)
这是我的服务器代码!服务器是发件人。
public static void main(String[] args) throws Exception {
System.out.println("i am server");
System.out.println("");
server = new ServerSocket(12345);
System.out.println("Server is listening...");
client = server.accept();
System.out.println("Client are connected");
dos = new DataOutputStream(client.getOutputStream());
dir = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
byte[] b = new byte[4096];
for (File file : files)
{
long length = file.length();
dos.writeLong(length);
String filename = file.getName();
dos.writeUTF(filename);
System.out.println(file.getName());
fis = new FileInputStream(file);
while (fis.read(b) != -1)
{
fis.read(b, 0, b.length);
dos.write(b, 0, b.length);
}
}
System.out.println("");
fis.close();
client.close();
server.close();
System.out.println("Server Closed!");
}
这是我的客户端代码!客户是接收者。
public static void main(String[] args) throws Exception {
System.out.println("i am client");
System.out.println("");
soc = new Socket("localhost", 12345);
System.out.println("Server are connected");
dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i=0;i<filecount;i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filenames : "+filename);
files[i] = new File(dirPath + "/" + filename);
fos = new FileOutputStream(files[i]);
for(int j = 0; j < filelength; j++)
{
fos.write(b);
dis.read(b);
}
}
System.out.println("data received!");
fos.flush();
fos.close();
soc.close();
System.out.println("client closed!");
}
我期待客户端的输出: 文件数:2 文件名:README.txtvcruntime140.dll
在服务器端,您在读取输入文件流时每次循环迭代调用 fis.read()
两次。每次迭代只需调用一次,并且需要将 fis.read()
的 return 值传递给 dos.write()
,以便它知道要写入的正确字节数。
在客户端,在读取文件流时,您在调用 dis.read()
之前调用 fos.write()
以使用数据填充 b
。而且你循环了太多次,因为你没有用每次迭代实际读取的字节数更新你的 j
循环计数器。
尝试更像这样的东西:
服务器:
public static void main(String[] args) throws Exception
{
System.out.println("i am server");
System.out.println("");
ServerSocket server = new ServerSocket(12345);
System.out.println("Server is listening...");
Socket client = server.accept();
System.out.println("Client is connected");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String dir = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
Files[] files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
byte[] b = new byte[4096];
for (File file : files)
{
long filelength = file.length();
dos.writeLong(filelength);
String filename = file.getName();
dos.writeUTF(filename);
System.out.println(filename);
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = DataInputStream(fis);
int loops = (int) (filelength / (long) b.length);
int remainder = (int) (filelength % (long) b.length);
for (int j = 0; j < loops; j++)
{
dis.readFully(b);
dos.write(b);
}
if (remainder > 0)
{
dis.readFully(b, 0, remainder);
dos.write(b, 0, remainder);
}
}
System.out.println("");
dos.close();
server.close();
System.out.println("Server Closed!");
}
客户:
public static void main(String[] args) throws Exception
{
System.out.println("i am client");
System.out.println("");
Socket soc = new Socket("localhost", 12345);
System.out.println("Server is connected");
DataInputStream dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i = 0; i < filecount; i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filename : " + filename);
files[i] = new File(dirPath + "/" + filename);
FileOutputStream fos = new FileOutputStream(files[i]);
int loops = (int) (filelength / (long) b.length);
int remainder = (int) (filelength % (long) b.length);
for (int j = 0; j < loops; j++)
{
dis.readFully(b);
fos.write(b);
}
if (remainder > 0)
{
dis.readFully(b, 0, remainder);
fos.write(b, 0, remainder);
}
}
System.out.println("data received!");
dis.close();
System.out.println("client closed!");
}
举个例子说明如何使用 Google Gauva library, here is your code changed to use a couple of utility classes from Guava, ByteStreams
and Files
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ClientServerGuava {
private static final int PORT = 12345;
public static void main(String[] args) throws IOException {
Thread serverThread = new ServerThread();
serverThread.start();
runClient();
}
private static void runClient() throws IOException {
System.out.println("i am client");
System.out.println("");
Socket soc = new Socket("localhost", PORT);
System.out.println("Server are connected");
DataInputStream dis = new DataInputStream(soc.getInputStream());
int filecount = dis.readInt();
File[] files = new File[filecount];
System.out.println("filecount : " + filecount);
byte[] b = new byte[1024];
for (int i=0;i<filecount;i++)
{
long filelength = dis.readLong();
String filename = dis.readUTF();
System.out.println("filenames : "+filename);
files[i] = new File(filename);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(files[i]));
InputStream limitedStream = ByteStreams.limit(dis, filelength);
ByteStreams.copy(limitedStream, bos);
bos.close();
}
System.out.println("data received!");
dis.close();
soc.close();
System.out.println("client closed!");
}
private static class ServerThread extends Thread {
private static final String DIR = "C:\Users\Nitesh Rathi\Downloads\vcruntime140";
@Override
public void run() {
try {
System.out.println("i am server");
System.out.println("");
ServerSocket server = new ServerSocket(PORT);
System.out.println("Server is listening...");
Socket client = server.accept();
System.out.println("Client are connected");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String dir = DIR;
File[] files = new File(dir).listFiles();
System.out.println("Files Selected : " + files.length);
dos.writeInt(files.length);
for (File file : files) {
dos.writeLong(file.length());
dos.writeUTF(file.getName());
System.out.println(file.getName());
Files.copy(file, dos);
}
System.out.println("");
dos.close();
client.close();
server.close();
System.out.println("Server Closed!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
注意读取循环的消除。您确实应该学习如何编写读取循环的代码,但在实践中,依赖受支持的、经过分析的、成熟的、优化的库,您可能会得到更好的服务。我相信 Apache commons-io 具有类似的功能。