![](/img/trans.png)
[英]SocketException: sendto failed: EBADF (Bad file descriptor)
[英]SocketException bad file descriptor when reading from InputStream
我正在嘗試構建一個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客戶端asynctask的代碼,我已指出發生錯誤的位置:
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();
}
}
這是服務器用來發送響應的方法:
public void sendResponse(byte[] response) {
OutputStream out;
try {
out = sock.getOutputStream();
out.write(response, 0, response.length);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
根據 Socket#getOutputStream
類的文檔 :
getOutputStream
OutputStream getOutputStream()
返回此套接字的輸出流。
如果此套接字具有關聯的通道,則結果輸出流會將其所有操作委托給該通道。 如果通道處於非阻塞模式,則輸出流的寫操作將引發IllegalBlockingModeException。
關閉返回的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的公共接口來通知調用活動套接字超時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.