我刚刚开始使用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.");
}
}
}
答案 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资源(输入和输出流,通道),套接字。但更重要的是:如果您使用的“事物”包含close
,dispsose
,shutdown
或任何其他内容,那么它肯定会在内部保留资源。
有一些例外(特别是ByteArrayInputStream
没有资源而是内存),但这些是实现细节:如果你坚持他们的接口(你应该,这是一个“合同”),每个流都应该关闭。登记/>
从Java 7开始,Java API中的大多数这些对象都实现了AutoCloseable
接口,但是许多第三方并不一定将它移植到它们的代码中(可能有些不是出于其他原因)。
作为我公司的代码审核员之一:我停止阅读,一旦看不到对资源的close
方法的安全调用,我就拒绝任何代码。安全我的意思是在finally子句中,保证执行。
您的程序获得的任何资源都应该在finally
子句中释放(有些甚至可以添加:自己的)。
资源的典型生命周期是什么 好吧:
在您的代码中,即
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.
}
是的。这就是我们拥有图书馆的原因。有人可能会说你不应该写这样的代码。使用标准的,行为良好的库,如commons IO,或使用其中一种实用方法。或者更新的JDK方法,例如Files
API,并查看其工作原理。
Commons IO有一套方便的IOUtils.closeQuietly()
方法来关闭流。
“尝试资源”调用中有一些后果比这更深刻。其中包括:如果我想对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)
{
}