我正在通过Socket向ServerSocket发送文件及其名称。 它“部分地”工作-服务器获取文件并将其保存到磁盘,但是 它不会退出ClientSession类的copy()方法中的循环。
public class Client{
DataOutputStream dos =null;
DataInputStream dis=null;
File f =new File("c:/users/supernatural.mp4");
public static void main(String[]ar) throws Exception{
try {
System.out.println("File upload started");
Socket socc = new Socket("localhost",8117);
dos = new DataOutputStream(socc.getOutputStream());
//send file name
dos.writeUTF(f.getName());
//send the file
write(f,dos);
//Files.copy(f.toPath(),dos);
//this prints
System.out.println("Data has been sent...waiting for server to respond ");
dis = new DataInputStream(socc.getInputStream());
//this never reads; stuck here
String RESPONSE = dis.readUTF();
//this never prints prints
System.out.println("Server sent: "+RESPONSE);
} catch(Exception ex) {
ex.printStackTrace();
} finally {
//close the exceptions
clean();
}
}
private static void write(File f,DataOutputStream d) throws Exception{
int count;
DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(f)));
byte array[] = new byte[1024*4];
while((count =din.read(array)) >0){
d.write(array,0,count);
}
d.flush();
//this prints
System.out.println(" done sending...");
din.close();
}
}
//Server
public class MySocket implements Runnable{
int worker_thread=2;
volatile boolean shouldRun =false;
ServerSocket server;
String port = "8117";
//ExecutorService services;
static ExecutorService services;
public MySocket() {
this.server = new ServerSocket(Integer.valueOf(port));
services = Executors.newFixedThreadPool(this.worker_thread);
}
//A METHOD TO RUN SERVER THREAD
@Override
public void run(){
while(this.shouldRun){
Socket client =null;
try{
client = server.accept();
}catch(Exception ex){
ex.printStackTrace();
}
//hand it over to be processed
this.services.execute(new ClientSessions(client));
}
}
public static void main(String[]ar) throws Exception{
Thread t = new Thread(new MySocket());
t.start();
}
}
//the ClientSession
public class ClientSessions implements Runnable{
Socket s;
public ClientSessions(Socket s){
this.s = s;
}
DataInputStream dis=null;
DataOutputStream dos=null;
boolean success =true;
@Override
public void run(){
//get the data
try{
//get inside channels
dis = new DataInputStream(this.s.getInputStream());
//get outside channels
dos = new DataOutputStream(this.s.getOutputStream());
//read the name
//this works
String name=dis.readUTF();
String PATH_TO_SAVE ="c://folder//"+name;
//now copy file to disk
File f = new File(PATH_TO_SAVE);
copy(f,dis);
//Files.copy(dis,f.toPath());
//this doesnt print, stuck in the copy(f,dis) method
System.out.println("I am done");
success =true;
}catch(Exception ex){
ex.printStackTrace();
}finally{
//clean resources...
clean();
}
}
//copy from the stream to the disk
private void copy(File f,DataInputStream d)throws Exception{
f.getParentFile().mkdirs();
f.createNewFile();
int count =-1;
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[1024*8];
count =d.read(array);
while(count >0){
out.write(array,0,count);
count =d.read(array);
System.out.println("byte out: "+count);
}
//this never prints
System.out.println("last read: "+count);
out.flush();
out.close();
if(success)dos.writeUTF("Succesful");
else dos.writeUTF("error");
}
}
//for the clean method i simply have
void clean(){
if(dis!=null)dis.close();
if(dos!=null)dos.close();
}
我对此进行了评论//Files.copy(dis,f.toPath());来自服务器 因为它在将文件写入磁盘后不会转到下一行,有时甚至卡在那里。
可以请我指出正确的道路吗,我相信我在这里做错了什么 不知道这是否有帮助,但是客户端在Eclipse中运行,服务器在netbeans中运行
答案 0 :(得分:0)
考虑一下您的procotol:
但是由于客户端正在等待响应,因此流永远不会关闭,因此您的协议中存在死锁。
通常可以通过以下方式解决此问题:首先发送文件大小,然后让服务器准确读取那么多字节。
或者,您可以使用TCP的单向关机功能向服务器发送一个信号,指出套接字的输出流已关闭。可以使用socc.shutdownOutput();
并且请使用try-with-resources以避免资源泄漏(您也必须关闭Socket)。
固定客户端:
try {
System.out.println("File upload started");
try (Socket socc = new Socket("localhost", 8117);
DataOutputStream dos = new DataOutputStream(socc.getOutputStream());
DataInputStream dis = new DataInputStream(socc.getInputStream())) {
// send file name
dos.writeUTF(f.getName());
// send the file
Files.copy(f.toPath(), dos);
dos.flush();
System.out.println("Data has been sent...waiting for server to respond ");
// signal to server that sending is finished
socc.shutdownOutput();
String RESPONSE = dis.readUTF();
// this never prints prints
System.out.println("Server sent: " + RESPONSE);
}
} catch (Exception ex) {
ex.printStackTrace();
}
服务器:
public class MySocket implements Runnable {
int worker_thread = 2;
volatile boolean shouldRun = true;
ServerSocket server;
int port = 8117;
ExecutorService services;
public MySocket() throws IOException {
this.server = new ServerSocket(port);
services = Executors.newFixedThreadPool(this.worker_thread);
}
// A METHOD TO RUN SERVER THREAD
@Override
public void run() {
while (this.shouldRun) {
Socket client = null;
try {
client = server.accept();
} catch (Exception ex) {
ex.printStackTrace();
}
// hand it over to be processed
this.services.execute(new ClientSessions(client));
}
}
public static void main(String[] ar) throws Exception {
new MySocket().run();
}
}
class ClientSessions implements Runnable {
Socket s;
public ClientSessions(Socket s) {
this.s = s;
}
@Override
public void run() {
// get the data
try (DataInputStream dis = new DataInputStream(this.s.getInputStream());
DataOutputStream dos = new DataOutputStream(this.s.getOutputStream())) {
// read the name
// this works
String name = dis.readUTF();
String PATH_TO_SAVE = name;
// now copy file to disk
File f = new File("c://folder", PATH_TO_SAVE);
Files.copy(dis, f.toPath());
dos.writeUTF("Succesful");
System.out.println("I am done");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
答案 1 :(得分:0)
代码的问题是,您从套接字的输入流中读取了它,但从未关闭。
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[1024*8];
count =d.read(array);
while(count >0){
out.write(array,0,count);
count =d.read(array);
System.out.println("byte out: "+count);
}
//this never prints
System.out.println("last read: "+count);
d.read(array)
正在积极尝试从套接字读取数据,直到收到内容为止一直阻塞。由于InputStream处于主动阻塞状态,因此它永远不会返回小于或等于0的值。这是因为流正在等待Socket另一端的下一个包。
在发送文件后关闭Socket应该可以为您提供帮助。在这种情况下,到达Stream的末尾,然后InputStream返回。
注意:您正在读取的InputStream(如果套接字已关闭)将返回-1,如您在JavaDoc中所见。
根据您的情况,这可能不可行!
您要用“好”或“错误”回答客户。如果关闭插座,则无法通过同一插座进行应答。解决这个问题的方法可能很复杂。
这种情况有些棘手。那里的大多数框架都有一个Thread,它从SocketInputStream读取并将返回值传递给某种处理程序(在阻塞IO中)。您的while循环基本上是Thread内部的这个主要阅读循环。仅当连接断开并且因此System.out.println("last read: "+count);
可以更改为System.out.println("disconnected");
为简单起见:您可以估算文件的大小为 big ,并且(仅出于测试目的)编写如下内容:
DataOutputStream out = new DataOutputStream(new
BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[/* Big enough */ 1024 * 1024 * 8];
d.read(array); // Read the file content
out.write(array); // Write to the file
//this never prints
System.out.println("last read: "+count);
我在这里忽略了所有错误检查!这意味着您只能从服务器读取一个程序包,该程序包必须是File。