在 Android Studio 中使用套接字的异常

Posted

技术标签:

【中文标题】在 Android Studio 中使用套接字的异常【英文标题】:Exception Using Sockets in Android Studio 【发布时间】:2016-04-09 10:53:19 【问题描述】:

我刚刚启动我的第一个 android 应用程序,但在 Android Studio 中使用套接字时遇到问题。

我正在尝试建立与服务器的连接。我正在使用异步任务执行此操作。当我启动应用程序时,创建了套接字并发送第一个包工作正常。但是当我尝试发送另一个包时,它会抛出一个异常,说套接字已关闭。

我尝试了很多事情,例如在发送第二个包之前检查套接字是否连接,如果没有,则创建一个新包。 Android Studio 中的调试告诉我,套接字“nsocket”永远不会关闭。这是我调试代码的截图:Debugging-Screenshot

这是我的异步任务代码:

public class NetworkTask extends AsyncTask<Void, byte[], Boolean> 
    private boolean finished = false;
    private boolean socket = false;
    private boolean messageSuccess = false;
    Socket nsocket; //Network Socket
    InputStream nis; //Network Input Stream
    OutputStream nos; //Network Output Stream
    SocketAddress sockaddr;

    Client c = new Client();
    Context context = getApplicationContext();

    @Override
    protected void onPreExecute() 
        Log.i("AsyncTask", "onPreExecute");
    

    @Override
    protected Boolean doInBackground(Void... params)  //This runs on a different thread
        socket = false;
        try 
            Log.i("AsyncTask", "doInBackground: Creating socket");
            sockaddr = new InetSocketAddress(SERVERHOST, SERVERPORT);
            nsocket = new Socket();
            nsocket.connect(sockaddr, 10000); //10 second connection timeout
            socket = true;
            while (finished) 
                finished = false;
                if (nsocket.isConnected()) 
                    Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
                    Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
                
                else 
                
            
         catch (IOException e) 
            e.printStackTrace();
            Log.i("AsyncTask", "doInBackground: IOException");
            socket = false;
         catch (Exception e) 
            e.printStackTrace();
            Log.i("AsyncTask", "doInBackground: Exception");
            socket = false;
        
        return socket;
    
    public boolean closeSocket() 
        try 
            //nis.close();
            nos.close();
            nsocket.close();
            Log.i("AsyncTask", "closeSocket: Finished");
            socket = false;
            return true;
         catch (IOException e) 
            Log.i("AsyncTask", "closeSocket: IO Failed");
            e.printStackTrace();
            return false;
         catch (NullPointerException e) 
            Log.i("AsyncTask", "closeSocket: Socket or output Stream already closed.");
            e.printStackTrace();
            socket = false;
            return false;
        catch (Exception e) 
            Log.i("AsyncTask", "closeSocket: Failed");
            e.printStackTrace();
            return false;
        

    

    public boolean SendDataToNetwork(final String cmd)  //You run this from the main thread.

        if (!nsocket.isClosed()) 
            Log.i("AsyncTask", getString(R.string.StatusSendAlarm));
            Log.i("AsyncTask", cmd);
            messageSuccess = false;
            publishProgress("1".getBytes());
            try 
                new Thread(new Runnable() 
                    public void run() 
                        try 
                            nos = nsocket.getOutputStream();
                            nos.write(cmd.getBytes());
                            nos.flush();
                            nos.close();

                            finished = true;
                            messageSuccess = true;
                        catch (Exception e) 
                            e.printStackTrace();
                            Log.i(TAG, "SendDataToNetwork: Message send failed. Caught an exception");
                            publishProgress("2".getBytes());
                        
                    
                ).start();
             catch (Exception e) 
                Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Caught an exception");
                publishProgress("3".getBytes());
            
        
        Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Socket closed");
        return messageSuccess;
    

    @Override
    protected void onProgressUpdate(byte[]... values) 
        if (values.length > 0) 
            if (values[0].equals("1"))
                Log.i("AsyncTask", "onProgressUpdate: " + values[0].length + " bytes received.");
                c.toastmessage(context, getString(R.string.StatusSendAlarm), Toast.LENGTH_SHORT);
            
            else if (values[0].equals("2")) 
                Log.i("AsyncTask", "onProgressUpdate2: " + values[0].length + " bytes received.");
                c.toastmessage(context, getString(R.string.StatusSendAlarmFail)+" 2", Toast.LENGTH_SHORT);
            
            else if (values[0].equals("3")) 
                Log.i("AsyncTask", "onProgressUpdate3: " + values[0].length + " bytes received.");
                c.toastmessage(context, getString(R.string.StatusSendAlarmFail)+" 3", Toast.LENGTH_SHORT);
            
            //textStatus.setText(new String(values[0]));
        
    

    @Override
    protected void onCancelled() 
        Log.i("AsyncTask", "Cancelled.");
    
    @Override
    protected void onPostExecute(Boolean result) 

        if (socket) 
            Log.d("AsyncTask", getString(R.string.socket_success));
            if (nos != null) 
                if (messageSuccess) 
                    c.toastmessage(context, getString(R.string.alarm_success),Toast.LENGTH_LONG);
                    mCheckBox.toggle();
                
                else 
                    c.toastmessage(context, getString(R.string.alarm_fail),Toast.LENGTH_LONG);
                    mCheckBox.toggle();
                
            
        
        else 
            Log.d("AsyncTask", getString(R.string.socket_fail));
        


    

任何想法为什么会这样?

编辑:这是他的代码,其中调用了“SendDataToNetwork”函数:

 private OnClickListener btnSendListener = new OnClickListener() 
    public void onClick(View v) 
        //toastmessage(context, "Sending Message to AsyncTask.", Toast.LENGTH_LONG);

        EditText at = (EditText) findViewById(R.id.alarmText);
        Long tsLong = System.currentTimeMillis()/1000;
        String ts = tsLong.toString();
        String atext = at.getText().toString();

        if (atext.length() > 0) 
            String alarmtext = "<event>\n" +
                    "<address>" + EINHEIT + "</address>\n" +
                    "<timestamp>" + ts + "</timestamp>\n" +
                    "<message>" + atext + "</message>\n" +
                    "</event>";
            networktask.SendDataToNetwork(alarmtext);
        
    
;

这是我的 onCreate 函数,用于建立套接字连接。

public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    btnSend = (Button)findViewById(R.id.sendButton);
    btnSend.setOnClickListener(btnSendListener);
    mButton=(Button)findViewById( R.id.sendButton);
    mCheckBox= ( CheckBox ) findViewById( R.id.checkBox_send);
    mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() 
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
            if (isChecked) 
                mButton.setEnabled(true);
                mButton.setTextColor(Color.parseColor("#ffffff"));

             else 
                mButton.setEnabled(false);
                mButton.setTextColor(Color.parseColor("#7c0000"));
            

        
    );
    context = getApplicationContext();
    networktask = new NetworkTask(); //New instance of NetworkTask
    networktask.execute();

【问题讨论】:

可能服务器收到第一条消息后关闭了连接。 'public boolean SendDataToNetwork(final String cmd) //你从主线程运行这个。'。确实。因此,从您的 AsyncTask 类中删除此函数并将其放入您的活动中。然后显示你第一次和第二次调用它的时间和方式。 当我按下 UI 上的按钮时,该函数被调用。我添加了上面的代码 你为什么不评论我的第一条评论? Repeat: '从你的 AsyncTask 类中移除这个函数,然后把它放到你的活动中'。 【参考方案1】:
    nos.close();

您自己正在关闭流并因此关闭套接字。

  nos = nsocket.getOutputStream();

你应该只做一次。不是每条消息。

【讨论】:

不幸的是,当我没有关闭输出流时,它没有发送消息。 我按照你一开始说的方式得到了它,在想知道为什么它没有发送消息之后,我关闭了输出流并且它起作用了。 好的。当发送者的nos.write(cmd.getBytes()); 与接收者的read() 不匹配时,经常会发生这种情况。接收者试图读取什么?一些字节?一条线?我认为你没有发送一条线。 我要发送的文本是 "\n" + EINHEIT + "\n" + ts + "\n " + atext + "\n" 接收端是第三方程序,可以通过套接字连接接收这种字符串。 尝试在末尾发送一个\n。或者两个。所以nos.write((cmd + "\n").getBytes());nos.write((cmd + "\n\n").getBytes());你必须找出接收者期望的消息结束。询问制作接收器的人。你没有回答我的问题接收者试图阅读什么。【参考方案2】:

我找到了解决问题的方法。我采纳了您的建议(连接、发送、阅读一项任务)并实施了它。现在调用了异步任务,当我按下按钮并将字符串传递给 doInBackground 函数时。我在那里创建套接字连接,打开 OutputStream 并发送消息。之后我关闭所有连接。

我不得不继续使用“nos.close()”,因为发送“\n”或“\n\n”不起作用。

异步任务调用

private OnClickListener btnSendListener = new OnClickListener() 
    public void onClick(View v) 
        EditText at = (EditText) findViewById(R.id.alarmText);
        Long tsLong = System.currentTimeMillis()/1000;
        String ts = tsLong.toString();
        String atext = at.getText().toString();

        if (atext.length() > 0) 
            String alarmtext = 
                    "<event>\n" +
                    "<address>" + EINHEIT + "</address>\n" +
                    "<timestamp>" + ts + "</timestamp>\n" +
                    "<message>" + atext + "</message>\n" +
                    "</event>";

            networktask = new NetworkTask(); //New instance of NetworkTask
            networktask.execute(alarmtext);
        
        else 
            toastmessage(context, getString(R.string.noText), Toast.LENGTH_LONG);
        
    
;

创建套接字

protected Boolean doInBackground(String... params)  //This runs on a different thread
        messageSuccess = false;
        String alarmtext = params[0];
        try 
            Log.i("AsyncTask", "Background Task: Creating socket...");
            sockaddr = new InetSocketAddress(SERVERHOST, SERVERPORT);
            nsocket = new Socket();
            nsocket.connect(sockaddr, 10000); //10 second connection timeout
            Log.i("AsyncTask", "Background Task: Socket created");
            nos = nsocket.getOutputStream();
            nos.write(alarmtext.getBytes());
            closeSocket();
            messageSuccess = true;
         catch (IOException e) 
            e.printStackTrace();
            Log.e("AsyncTask", "Background Task: IOException");
            Log.i("AsyncTask", getString(R.string.socket_fail));
            messageSuccess = false;
         catch (Exception e) 
            e.printStackTrace();
            Log.e("AsyncTask", "Background Task: Exception");
            Log.i("AsyncTask", getString(R.string.socket_fail));
            messageSuccess = false;
        
        return messageSuccess;
    

感谢 greenapps 的帮助

【讨论】:

一些备注:如果你只在 doInBackground 中使用 messageSuccess、sockaddr 和 nsocket(我认为你这样做),然后在那里声明它们。进一步使用 e.getMessage() 来查看正确的消息。 Log.e("AsyncTask", "后台任务:IOException:" + e.getMessage());

以上是关于在 Android Studio 中使用套接字的异常的主要内容,如果未能解决你的问题,请参考以下文章

在 Unity 中使用 Android Studio 上的类

无法使用 java 套接字将图像从 android studio 发送到 pc,filePath 返回 null

在Android Studio中关闭手机上的应用程序时如何不关闭套接字

我如何获得可在 Linux 上的异​​步套接字上读取的字节数?

Visual Studio C++ 到 C# 套接字程序

Visual Studio 上的 IPC