import java.io.*;
import java.net.*;public class FileServer implements Runnable 
{
private ServerSocket server;

public FileServer(int port)
{
try
{
server = new ServerSocket(port);
}
catch (IOException e)
{
e.printStackTrace();
}
}

public void run()
{
try
{
Socket socket = server.accept();

File file = new File("d:\\2.bmp");
FileOutputStream fileOut = new FileOutputStream(file);
InputStream socketIn = socket.getInputStream();
OutputStream socketOut = socket.getOutputStream();
DataInputStream dataIn = new DataInputStream(socketIn);
PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(socketOut));

byte[] bytes = new byte[1024];
while ((dataIn.read(bytes)) != -1)
{
fileOut.write(bytes);
}
fileOut.close();

//writerOut.println("OK");
//writerOut.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
}

public static void main(String[] args)
{
new Thread(new FileServer(9999)).start();
}
}import java.io.*;
import java.net.*;public class FileClient implements Runnable
{
private Socket socket;

public FileClient(String ip, int port)
{
try 
{
socket = new Socket(ip, port);
}
catch (IOException e) 
{
e.printStackTrace();
}
}

public void run()
{
try
{
InputStream socketIn = socket.getInputStream();
File file = new File("d:\\1.bmp");
FileInputStream fileIn = new FileInputStream(file);
OutputStream socketOut = socket.getOutputStream();
BufferedReader readerIn = new BufferedReader(new InputStreamReader(socketIn));
DataOutputStream dataOut = new DataOutputStream(socketOut); byte[] bytes = new byte[1024];
while ((fileIn.read(bytes)) != -1)
{
dataOut.write(bytes);
}
dataOut.close();

//String str = readerIn.readLine();
//System.out.println(str);
}
catch (IOException e)
{
e.printStackTrace();
}
}

public static void main(String[] args)
{
new Thread(new FileClient("localhost", 9999)).start();
}
}
这段代码这样写是没有问题的,可以实现文件传输功能,但是为什么加上被注释掉的语句后就出现错误了呢?错误的大致原因是这样的,Client在执行String str = readerIn.readLine();这句话地时候,并没有像以往一样变成阻塞态,而是直接抛出了一个错误。我不是很明白为什么会抛出一个错误,请高手帮忙解释一下,顺便也帮忙修改一下,谢谢了。

解决方案 »

  1.   

    1:已经close了,如何读到?
    2:flush好像会是post方式发送。
      

  2.   

    客户端写完之后 dataOut.close(),关闭流的同时 也关闭了socket,所以服务器还没有读完就抛异常了。
    我通常的做法是 
             客户端关闭前给服务器端发送一个close指令,然后客户端线程睡眠1000ms等待服务器端流,socket                      关闭。
             服务端收到close指令后进行流关闭,socket关闭的操作,最后客户端睡醒后,同样进行流关闭,socket关闭的操作。
      

  3.   

    因为两边的代码执行不是同步的,而是有个时间差(即使是同一台电脑也会有时间差)。传输完成之后,客户端马上执行了readLine,而此时,服务器可能还没收到最后的数据包,或者还没有来得及发送OK,因此你readLine会有问题。
    你可以在客户端加上对readerIn.available()的判断。比如
    long start = System.currentTimeMillis();
    while (readIn.available() <= 0) { // 其实更好是判断 < "OK".length(),因为可能有一个物理包,正好到O为止,K要在下一个buffer里面才能收到,而恰巧此时,客户端代码被执行。
      Thread.sleep(500);
      if (System.currentTimeMillis() - start >= 10000) {
        throw new RuntimeException("Timeout");
      }
    }
    readIn.readLine();
      

  4.   

    我修改了一下,并在注释中说明了你出的问题。import java.io.*;
    import java.net.*;public class FileServer implements Runnable
    {
        private ServerSocket server;    public FileServer(int port)
        {
            try
            {
                server = new ServerSocket(port);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }    public void run()
        {
            try
            {
                Socket socket = server.accept();            
                File file = new File("2.jpg");
                FileOutputStream fileOut = new FileOutputStream(file);
                InputStream socketIn = socket.getInputStream();
                OutputStream socketOut = socket.getOutputStream();
                DataInputStream dataIn = new DataInputStream(socketIn);
                PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(socketOut));
                byte[] bytes = new byte[1024];
                boolean flag=true;
                try{
                    //你这里,read返回-1的时候就停止接收,其实你这样做,是很不科学的
                    //因为,read什么时候会返回-1,如果是读取文件,读到文件尾标记会返回-1
                    //而对于从TCP获得的输入流而言,当对方的输出流关闭后,你这输入流的read
                    //才会返回-1。那么这样做的坏处有几点
                    //1:就如你这里的程序一样,对方的输出流关闭的话,引发Socket连接关闭,你就
                    //不能再传递信息了。所以对方不能关闭,可是对方不关闭,你就不会返回-1。
                    //那你的程序就无限等待了
                    //2:你这里只传输一个文件,如果是一批呢,难道你不停关闭再不停打开?
                    //所以,正宗的做法应该是在传递的数据中加上一些标记信息,通过这些标记
                    //信息来判断什么时候传输结束,什么时候传输开始,等等
                    while ((dataIn.read(bytes)) != -1)
                    {
                        //不过呢,我这里没有加标记信息,而对方读完后也没关闭流。我干的
                        //是设置了socket的接收超时时间为100ms。当然,其实这样很不科学滴。
                        //不过演示给你看是没问题的。
                        //我是在dataIn第一次读完才设置的。这是防止你先启动FileServer再启动
                        //FileClient的时候不够快,这里已经超时了。
                        //设置超时以后。对方传完了,并不关闭流。而你还在read,超时100ms后
                        //会抛出异常,不过我在接收异常的代码中什么也没有做
                        //因为下面就是按你的意思去发送那个信息
                        if(flag){
                            socket.setSoTimeout(100);
                            flag=false;
                        }
                        fileOut.write(bytes);
                    }
                }catch(Exception e){
                    if(e instanceof SocketException){
                        
                    }
                }
                fileOut.close();            writerOut.println("OK");
                writerOut.flush();
                //对了,最后再说一下,你用流式传输文件,是相当不好滴。因为流式传输,速度相当的慢的。
                //应该用数据报传输
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }    public static void main(String[] args)
        {
            new Thread(new FileServer(9999)).start();
        }
    }import java.io.*;
    import java.net.*;public class FileClient implements Runnable
    {
        private Socket socket;    public FileClient(String ip, int port)
        {
            try
            {
                socket = new Socket(ip, port);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }    public void run()
        {
            try
            {
                InputStream socketIn = socket.getInputStream();
                File file = new File("screen.jpg");
                FileInputStream fileIn = new FileInputStream(file);
                OutputStream socketOut = socket.getOutputStream();
                BufferedReader readerIn = new BufferedReader(new InputStreamReader(socketIn));
                DataOutputStream dataOut = new DataOutputStream(socketOut);            byte[] bytes = new byte[1024];
                while ((fileIn.read(bytes)) != -1)
                {
                    dataOut.write(bytes);
                }
                //dataOut.close();
                String str = readerIn.readLine();
                System.out.println(str);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }    public static void main(String[] args)
        {
            new Thread(new FileClient("localhost", 9999)).start();
        }
    }
      

  5.   

    我晕 楼主你这
    Client是在发送数据,而Server实在接受数据。
    socket = new Socket(ip, port);  //client端
    Socket socket = server.accept(); //server端。而楼主你在Client端
    InputStream socketIn = socket.getInputStream(); 你认为你能得到什么数据?这里是源头,根本就没数据吗。
    然后又 BufferedReader readerIn = new BufferedReader(new InputStreamReader(socketIn));
    本身这里面这有TCP的确认信息,没有任何数据,所以你read的时候就是-1;
    而Server端
     OutputStream socketOut = socket.getOutputStream(); //你还要想发送回去数据么?out是往外发送的。
     PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(socketOut));
    writerOut.println("OK"); 
    writerOut.flush();这样就会发送空数据出去了,因为out中没有内容所以一直是-1以上只是我的意见。不知道这么久了记的正确不。
      

  6.   

    客户端想打印出数据,你可以在write的时候打印出来、或者把读取到的byte数据封装成一个大的文件数组最后一期打印、或者while之后close后重新读取一遍文件流。然后按行打印。推荐第一种,但是中文可能会被截取一般的字