Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从InputStream读取时SocketException错误的文件描述符_Java_Android_Sockets_Inputstream - Fatal编程技术网

Java 从InputStream读取时SocketException错误的文件描述符

Java 从InputStream读取时SocketException错误的文件描述符,java,android,sockets,inputstream,Java,Android,Sockets,Inputstream,我正在尝试构建一个android应用程序,用户可以在其中创建一个新帐户,并由服务器执行帐户创建,并将信息添加到数据库中 在服务器完成(或未能完成)此任务后,我希望将一个响应发送回客户端,指示任务的成功或失败;我正在从作为异步任务类成员的同一套接字打开一个inputstream和一个outputstream 似乎代码在从客户端发送到服务器时执行得很好,服务器正确地接收到了所有内容。但是,当客户端从服务器接收到响应时,我遇到了一个错误: 09-02 15:58:02.266 30979-32154/

我正在尝试构建一个android应用程序,用户可以在其中创建一个新帐户,并由服务器执行帐户创建,并将信息添加到数据库中

在服务器完成(或未能完成)此任务后,我希望将一个响应发送回客户端,指示任务的成功或失败;我正在从作为异步任务类成员的同一套接字打开一个
inputstream
和一个
outputstream

似乎代码在从客户端发送到服务器时执行得很好,服务器正确地接收到了所有内容。但是,当客户端从服务器接收到响应时,我遇到了一个错误:

09-02 15:58:02.266 30979-32154/com.example.zemcd.messagebottle E/NewAccountTask: error connecting
    java.net.SocketException: recvfrom failed: EBADF (Bad file descriptor)
        at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:588)
        at libcore.io.IoBridge.recvfrom(IoBridge.java:552)
        at java.net.PlainSocketImpl.read(PlainSocketImpl.java:481)
        at java.net.PlainSocketImpl.-wrap0(PlainSocketImpl.java)
        at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
        at libcore.io.Streams.readSingleByte(Streams.java:41)
        at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:233)
        at com.example.zemcd.messagebottle.NewAccountTask.doInBackground(NewAccountTask.java:50)
        at com.example.zemcd.messagebottle.NewAccountTask.doInBackground(NewAccountTask.java:17)
        at android.os.AsyncTask$2.call(AsyncTask.java:295)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)
    Caused by: android.system.ErrnoException: recvfrom failed: EBADF (Bad file descriptor)
        at libcore.io.Posix.recvfromBytes(Native Method)
        at libcore.io.Posix.recvfrom(Posix.java:189)
        at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
        at libcore.io.IoBridge.recvfrom(IoBridge.java:549)
以下是我的android客户端异步任务的代码,我已经指出了错误发生的位置:

public class NewAccountTask extends AsyncTask<Void, Void, Void> {
private static final String TAG = "NewAccountTask";
private static final String AUTH_KEY = "9LEF1D97001X!@:";
private static final String REQUEST_NEW_ACCOUNT = "0";
private static final int PORT = 5555;

private String mContactId;
private String mPassword;
private Context mContext;


private Socket mSocket;
private String response;

public NewAccountTask(String contactId, String password, Context context){
    mContactId = contactId + ":";
    mPassword = password + ":";
    mContext = context;
}

@Override
protected Void doInBackground(Void... params) {
    try{
        mSocket = new Socket("192.168.0.111", PORT);
        OutputStream out = mSocket.getOutputStream();
        InputStream in  = mSocket.getInputStream();
        //write key to server
        byte[] buffer = (AUTH_KEY + mContactId + mPassword + REQUEST_NEW_ACCOUNT).getBytes();
        out.write(buffer, 0, buffer.length);
        out.flush();
        out.close();

        //i posted a log message here this one runs
        int c;
        while((c = in.read()) != -1) { <--ERROR OCCURS HERE!
            response += (char) c;
        }
        //and here this one never runs

        in.close();

        Log.i(TAG, "connection success!");
    }catch (IOException ioe){
        Log.e(TAG, "error connecting", ioe);
    }

    return null;
}

@Override
public void onPostExecute(Void result){
    Toast.makeText(mContext, response, Toast.LENGTH_LONG).show();
}
}
Socket#getOutputStream
类中:

getOutputStream

OutputStream getOutputStream()

返回此套接字的输出流

如果此套接字具有关联的通道,则结果输出 流将其所有操作委托给通道。如果频道 处于非阻塞模式,则输出流的写入操作将 抛出非法BlockingModeException

关闭返回的OutputStream将关闭关联的套接字

这里需要注意的是:

关闭返回的OutputStream将关闭关联的套接字

在代码中,在写入输出流后:

out.write(buffer,0,buffer.length)

您关闭了输出流

out.flush();
out.close();
根据文档,它关闭套接字,从而关闭关联的
InputStream
。这就是例外

在执行两个操作后,只需关闭套接字连接,而不是单独关闭每个流

还请注意,
flush()
Socket#getOutputStream
类的
close()
之前是非常无用的:

getOutputStream

OutputStream getOutputStream()

返回此套接字的输出流

如果此套接字具有关联的通道,则结果输出 流将其所有操作委托给通道。如果频道 处于非阻塞模式,则输出流的写入操作将 抛出非法BlockingModeException

关闭返回的OutputStream将关闭关联的套接字

这里需要注意的是:

关闭返回的OutputStream将关闭关联的套接字

在代码中,在写入输出流后:

out.write(buffer,0,buffer.length)

您关闭了输出流

out.flush();
out.close();
根据文档,它关闭套接字,从而关闭关联的
InputStream
。这就是例外

在执行两个操作后,只需关闭套接字连接,而不是单独关闭每个流


还要注意的是,
flush()
close()

之前是非常无用的,我使用了其他答案中的建议以及针对这个问题发布的评论来解决这个问题。然而,仍然存在一个主要问题。如果一次发送消息的尝试失败,那么服务器将永远无法完成并发送响应。我用来解决这个问题的方法是在连接的套接字上设置超时。我将读取循环替换为:

mSocket = new Socket();
mSocket.setSoTimeout(500);
SocketAddress socketAddress = new InetSocketAddress("192.168.0.111", PORT);
mSocket.connect(socketAddress);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
Log.d(TAG, "streams aquired");

out.write(AUTH_KEY + mContactId + mPassword + REQUEST_NEW_ACCOUNT);
Log.d(TAG, "data sent");
out.newLine();
out.flush();

Log.d(TAG, "read began");
response = in.readLine();
out.close();
in.close();
Log.d(TAG, "streams closed");

Log.i(TAG, "connection success!");

并使用OnFailureListener的公共接口通知调用活动套接字超时。

我使用其他答案中的建议以及针对此问题发布的评论来解决此问题。然而,仍然存在一个主要问题。如果一次发送消息的尝试失败,那么服务器将永远无法完成并发送响应。我用来解决这个问题的方法是在连接的套接字上设置超时。我将读取循环替换为:

mSocket = new Socket();
mSocket.setSoTimeout(500);
SocketAddress socketAddress = new InetSocketAddress("192.168.0.111", PORT);
mSocket.connect(socketAddress);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
Log.d(TAG, "streams aquired");

out.write(AUTH_KEY + mContactId + mPassword + REQUEST_NEW_ACCOUNT);
Log.d(TAG, "data sent");
out.newLine();
out.flush();

Log.d(TAG, "read began");
response = in.readLine();
out.close();
in.close();
Log.d(TAG, "streams closed");

Log.i(TAG, "connection success!");

并使用OnFailureListener的公共接口通知调用活动套接字超时。

请注意,这是Android中的一个错误。它应该抛出
SocketException:socketclosed
@EJP:根据我掌握的有限知识,看起来异常是正确的。根据文档,
close()
也将关闭套接字,因此将关闭关联的
InputStream
read()
操作(实际上引发异常)位于关闭的
InputStream
(因此实际上与套接字没有直接关系)对于关闭的
InputStream
,问题中的异常是可以的。我错过什么了吗?“你能纠正我吗?”我已经按照你的建议做了,但我有一个新问题。当我在执行这两个操作后尝试关闭这两个流时,应用程序在读操作时会被卡住。我在我的代码中发布了一个编辑,指出了它被卡住的地方。它抛出一个异常是正确的,但它抛出这个异常是不正确的。它应该按照我说的做,比如Oracle JRE。它通过文件描述符与套接字直接相关。它应该抛出
SocketException:socketclosed
@EJP:根据我掌握的有限知识,看起来异常是正确的。根据文档,
close()
也将关闭套接字,因此将关闭关联的
InputStream
read()
操作(实际上引发异常)位于关闭的
InputStream
(因此实际上与套接字没有直接关系)对于关闭的
InputStream
,问题中的异常是可以的。我错过什么了吗?“你能纠正我吗?”我已经按照你的建议做了,但我有一个新问题。当我尝试在执行后关闭两个流时