Java套接字在方法之间传递

时间:2014-07-30 20:45:02

标签: java sockets bufferedreader printwriter

我刚刚开始使用Java Socket Programming,我一直在阅读关于套接字here的文献。下面的代码是我所采用的教科书中的一个示例,它要求我找到该错误。虽然我没有看到任何错误,但与文献相比。 socket,bufferedreader和printwriter的创建似乎是正确的,它们也被try-catch块包围。在try-catch块中也正确地“close()”。将这些传递给process()时是否有错误?任何帮助将不胜感激。

import java.net.*;
import java.io.*;

class main{

public void process(PrintWriter out, BufferedReader in, Socket echoSocket){
//....
}

public void processData() {
    Socket echoSocket;
    PrintWriter out;
    BufferedReader in;
    try{
        echoSocket = new Socket("server.company.com", 8081);
        out = new PrintWriter(echoSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
    }
    catch (Exception e) {
        System.err.println("Exception has occured");
        return;
    }
    process(out, in, echoSocket);
    try {
        out.close();
        in.close();
        echoSocket.close();
    }
    catch(IOException e) {
        System.err.println("IOException has occurred.");
    }
  }
}

3 个答案:

答案 0 :(得分:4)

public void process(){PrintWriter out, BufferedReader in, Socket echoSocket){

应该是

public void process(PrintWriter out, BufferedReader in, Socket echoSocket){

否则一切似乎都很好

答案 1 :(得分:3)

尽管存在错别字,但人们只能猜出实际的“错误”是什么,这段代码存在错误处理问题。具体而言,在处理资源方面。

关于资源的讨论

什么是资源?

基本上:任何依赖底层操作系统级资源的Java Object。主要是:IO资源(输入和输出流,通道),套接字。但更重要的是:如果您使用的“事物”包含closedispsoseshutdown或任何其他内容,那么它肯定会在内部保留资源。
有一些例外(特别是ByteArrayInputStream没有资源而是内存),但这些是实现细节:如果你坚持他们的接口(你应该,这是一个“合同”),每个流都应该关闭。登记/> 从Java 7开始,Java API中的大多数这些对象都实现了AutoCloseable接口,但是许多第三方并不一定将它移植到它们的代码中(可能有些不是出于其他原因)。

作为我公司的代码审核员之一:我停止阅读,一旦看不到对资源的​​close方法的安全调用,我就拒绝任何代码。安全我的意思是在finally子句中,保证执行。

关于资源的经验法则

您的程序获得的任何资源都应该在finally子句中释放(有些甚至可以添加:自己的)。

资源的典型生命周期是什么 好吧:

  1. 你得到它
  2. 你用它
  3. 你发布它
  4. 在您的代码中,即

    ResourceObject myObject = null;
    try {
        myObject = getResource();
        processResource(myObject);
    } finally {
        if(myObject != null) {
            try {
                myObject.close();
            } catch (Exception e) {
                // Usually there is nothing one can do but log
            }
        }
    }
    

    从Java 7开始,如果资源对象实现了AutoCloseable,那么你就有了一种新的编写方式,它被称为“try with resources”。

    try(ResourceObject myObject = getResource()) {
        process(myObject);
    }
    

    你没有看到finally,但它就在那里,编译器会为你编写finally子句。

    多个资源怎么样?

    嗯:多个资源,多个终结者。这个想法是在不同的finally子句中分离失败的原因。 假设您要复制文件...

    public void myCopy() throws IOException {
    InputStream source = null;
        try {
        source = new FileInputStream("yourInputFile");
            // If anything bad happens, I have a finally clause that protects this now   
            OutputStream destination = null;
        try {
            destination = new FileOutputStream("yourOurputFile"); // If fails, my Input will be closed thanks to its own finally
                performCopy(source, destination); // If this fail, my destination will also be closed thanks to its own finally
            } finally {
                if(destination!=null) { try { destination.close(); } catch (Exception e) {/* log*/ }}
            }
        } finally {
            if(source!=null) { try { source.close(); } catch (Exception e) {/* log*/ }}
        }
    }
    

    或者,使用Java 7语法,我们有更短的(免责声明:我现在没有Java7,因此无法真正检查是否编译):

    try(
        InputStream input = new FileInputStream("in");
        OutputStream output = new FileOutputStream("out")) {
        performCopy(input, output);
    } catch(IOException e) {
        // You still have to deal with it of course.
    }
    

    这是太多的BOILERPLATE!

    是的。这就是我们拥有图书馆的原因。有人可能会说你不应该写这样的代码。使用标准的,行为良好的库,如commons IO,或使用其中一种实用方法。或者更新的JDK方法,例如Files API,并查看其工作原理。

    Commons IO有一套方便的IOUtils.closeQuietly()方法来关闭流。

    尝试使用资源Gotchas

    “尝试资源”调用中有一些后果比这更深刻。其中包括:如果我想对finally子句中发生的异常做些什么怎么办?如何将其与performCopy期间发生的异常区分开来? 另一个案例是:这里发生了什么:

    try(Reader reader = new InputStreamReader(new FileInputStream("in"), "an encoding that is not supported")) {
      // Whatever
    }
    

    发生了UnsupportedEncodingException,但在 FileInputStream实例化后。但由于FileInputStream不是try子句的主题,因此它不会被关闭。你有一个文件描述符泄漏。尝试了一千次,你的JVM将无法再打开文件,操作系统会告诉你“超出最大打开文件数”(ulimit通常在UNIX中执行此操作)

    回到你的插座

    那你的资源是什么?

    嗯,首先,我们可以注意到你只有一个真正的资源,你的Socket实例,因为Socket javadoc说(javadoc):

     * <p> Closing this socket will also close the socket's
     * {@link java.io.InputStream InputStream} and
     * {@link java.io.OutputStream OutputStream}.
    

    因此,您的输入和输出流与您的Socket绑定,这就足够了。

    您的代码有什么问题

    在原始代码中添加注释:

    try{
        echoSocket = new Socket("server.company.com", 8081);
        out = new PrintWriter(echoSocket.getOutputStream(), true); // This can throw IOException
        in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // Ditto
    }
    catch (Exception e) {
        // If an exception was thrown getting any of the streams, we get there
        System.err.println("Exception has occured");
        // And you return without closing the socket. It's bad !
        return;
    }
    // Let's assume everything worked, no exception.
    process(out, in, echoSocket); // This may throw an exception (timeout, socket closed by peer, ...) 
                                  // that is uncaught (no catch clause). Your socket will be left unclosed as a result.
    try {
        out.close();              // This can fail
        in.close();               // This too
        echoSocket.close();       // And this too - although nothing you can do about it
    }
    catch(IOException e) {
        // if out.close fails, we get here, and in.close and socket.close 
        // never got a chance to be called. You may be leaking resources 
        System.err.println("IOException has occurred.");
    }
    

    安全实施

    Socket echoSocket = null;
    try {
        // open socket, 
        echoSocket = new Socket("server.company.com", 8081); // protected by finally
        out = new PrintWriter(echoSocket.getOutputStream(), true); // protected
        in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // protected
         process(out, in, echoSocket); // Still protected
    } catch (Exception e) {
        // Your current error handling
    } finally {
        // Anyway, this close will be called if needs be.
        if(echoSocket != null) { 
            try { echoSocket.close(); } catch (Exception e) { /* log */}
            // See javadoc, this has closed the in & out streams too.
        }
    }
    

答案 2 :(得分:0)

尝试这个我认为你错过了一个分号

public void processData() {
Socket echoSocket;
PrintWriter out;
BufferedReader in;
try{
    echoSocket = new Socket("localhost", 8080);
    out = new PrintWriter(echoSocket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
}
catch (IOException e) {
    System.err.println("Exception has occured");
    return;
}
process(out, in, echoSocket);
try {
    out.close();
    in.close();
    echoSocket.close();
}
catch(IOException e) {
    System.err.println("IOException has occurred.");
}


}
public void process (PrintWriter out,  BufferedReader in, Socket echoSocket)
{

}