例如:使用AsyncTask的Andr​​oid的双向网络套接字 [英] Example: Android bi-directional network socket using AsyncTask

查看:128
本文介绍了例如:使用AsyncTask的Andr​​oid的双向网络套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大多数的网络套接字的例子,我发现对于Android只是一个方向。我所需要的双向数据流的溶液。我最终学会了AsyncTask的了。这个例子展示了如何从一个插槽数据并将数据发送回吧。由于正在接收数据,即阻断需要在一个线程比UI线程其他运行插座的阻断性质

为了举例,这code连接到网络服务器。 pressing开始AsyncTask的按钮,将打开插座。一旦插座是开放的,Web服务器等待请求。 pressing发送消息按钮将发送一个请求到服务器。来自服务器的任何响应将显示在所述的TextView。在HTTP的情况下,网络服务器将来自客户机断开,一旦所有的数据已被发送。对于其他的TCP数据流,连接将保持,直到一方断开连接。

截图:

AndroidManifest.xml中:

 < XML版本=1.0编码=UTF-8&GT?;
<舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
      包=com.exampleasynctask
      安卓版code =1
      机器人:VERSIONNAME =1.0>
    <使用-SDK安卓的minSdkVersion =8/>
    <使用-权限的Andr​​oid:名称=android.permission.INTERNET对/>
    <应用机器人:图标=@可绘制/图标机器人:标签=@字符串/ APP_NAME>
        <活动机器人:名称=。MainActivity
                  机器人:标签=@字符串/ APP_NAME>
            <意向滤光器>
                <作用机器人:名称=android.intent.action.MAIN/>
                <类机器人:名称=android.intent.category.LAUNCHER/>
            &所述; /意图滤光器>
        < /活性GT;
    < /用途>
< /舱单>
 

水库\布局\ main.xml中:

 < XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:方向=垂直
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =FILL_PARENT
    >
<按钮机器人:ID =@ + ID / btnStart机器人:layout_width =WRAP_CONTENT机器人:layout_height =WRAP_CONTENT机器人:文本=开始的AsyncTask>< /按钮>
<按钮机器人:ID =@ + ID / btnSend机器人:layout_width =WRAP_CONTENT机器人:layout_height =WRAP_CONTENT机器人:文=发送信息>< /按钮>
< TextView的机器人:ID =@ + ID / textStatus机器人:TEXTSIZE =24sp机器人:layout_width =FILL_PARENT机器人:layout_height =WRAP_CONTENT机器人:文本=状态会在这里,/>
< / LinearLayout中>
 

SRC \ com.exampleasynctask \ MainActivity.java:

 包com.exampleasynctask;

进口java.io.IOException异常;
进口的java.io.InputStream;
进口java.io.OutputStream中;
进口java.net.InetSocketAddress;
进口的java.net.Socket;
进口java.net.SocketAddress;

进口android.app.Activity;
进口android.os.AsyncTask;
进口android.os.Bundle;
进口android.util.Log;
进口android.view.View;
进口android.view.View.OnClickListener;
进口android.widget.Button;
进口android.widget.TextView;

公共类MainActivity延伸活动{
    按钮btnStart,btnSend;
    TextView的textStatus;
    NetworkTask networktask;

    @覆盖
    公共无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.main);
        btnStart =(按钮)findViewById(R.id.btnStart);
        btnSend =(按钮)findViewById(R.id.btnSend);
        textStatus =(TextView中)findViewById(R.id.textStatus);
        btnStart.setOnClickListener(btnStartListener);
        btnSend.setOnClickListener(btnSendListener);
        networktask =新NetworkTask(); //创建初始实例,以便SendDataToNetwork不会引发错误。
    }

    私人OnClickListener btnStartListener =新OnClickListener(){
        公共无效的onClick(视图v){
            btnStart.setVisibility(View.INVISIBLE);
            networktask =新NetworkTask(); // NetworkTask的新实例
            networktask.execute();
        }
    };
    私人OnClickListener btnSendListener =新OnClickListener(){
        公共无效的onClick(视图v){
            textStatus.setText(发送信息给AsyncTask的。);
            networktask.SendDataToNetwork(GET / HTTP / 1.1 \ r \ñ\ r \ N);
        }
    };

    公共类NetworkTask扩展的AsyncTask<太虚,字节[],布尔> {
        插座nsocket; //网络套接字
        InputStream的NIS; //网络输入流
        的OutputStream号; //网络输出流

        @覆盖
        在preExecute保护无效(){
            Log.i(关于preExecute的AsyncTask);
        }

        @覆盖
        保护布尔doInBackground(空... PARAMS){//这个运行在不同的线程
            布尔结果= FALSE;
            尝试 {
                Log.i(AsyncTask的,doInBackground:创建插座);
                SocketAddress的套接字地址=新的InetSocketAddress(192.168.1.1,80);
                nsocket =新的Socket();
                nsocket.connect(套接字地址,5000); // 10第二个连接超时
                如果(nsocket.isConnected()){
                    NIS = nsocket.getInputStream();
                    号= nsocket.getOutputStream();
                    Log.i(AsyncTask的,doInBackground:创建,溪流分配插座);
                    Log.i(AsyncTask的,doInBackground:等待inital数据......);
                    byte []的缓冲区=新的字节[4096];
                    INT读= nis.read(缓冲,0,4096); //这是堵
                    而(读!=  -  1){
                        byte []的TempData的=新的字节[阅读]
                        System.arraycopy(缓冲,0,TempData的,0,读);
                        publishProgress(TempData的);
                        Log.i(AsyncTask的,doInBackground:得到了一些数据);
                        读= nis.read(缓冲,0,4096); //这是堵
                    }
                }
            }赶上(IOException异常E){
                e.printStackTrace();
                Log.i(AsyncTask的,doInBackground:IOException异常);
                结果=真;
            }赶上(例外五){
                e.printStackTrace();
                Log.i(AsyncTask的,doInBackground:异常);
                结果=真;
            } 最后 {
                尝试 {
                    nis.close();
                    nos.close();
                    nsocket.close();
                }赶上(IOException异常E){
                    e.printStackTrace();
                }赶上(例外五){
                    e.printStackTrace();
                }
                Log.i(AsyncTask的,doInBackground:成品);
            }
            返回结果;
        }

        公共无效SendDataToNetwork(字符串CMD){//运行此主线程。
            尝试 {
                如果(nsocket.isConnected()){
                    Log.i(AsyncTask的,SendDataToNetwork:编写收到消息,插座);
                    nos.write(cmd.getBytes());
                } 其他 {
                    Log.i(AsyncTask的,。SendDataToNetwork:不能发送消息关闭套接字);
                }
            }赶上(例外五){
                Log.i(AsyncTask的,SendDataToNetwork:短信发送失败,陷入了异常。);
            }
        }

        @覆盖
        保护无效onProgressUpdate(字节[] ...值){
            如果(values​​.length大于0){
                (接收字节数。+值[0] .length +的AsyncTask,onProgressUpdate); Log.i
                textStatus.setText(新的字符串(值[0]));
            }
        }
        @覆盖
        保护无效onCancelled(){
            Log.i(AsyncTask的,取消);
            btnStart.setVisibility(View.VISIBLE);
        }
        @覆盖
        保护无效onPostExecute(布尔结果){
            如果(结果){
                Log.i(AsyncTask的,onPostExecute:已完成与错误。);
                textStatus.setText(有一个连接错误。);
            } 其他 {
                Log.i(AsyncTask的,onPostExecute:已完成。);
            }
            btnStart.setVisibility(View.VISIBLE);
        }
    }

    @覆盖
    保护无效的onDestroy(){
        super.onDestroy();
        networktask.cancel(真正的); //如果任务当前正在运行
    }
}
 

解决方案

SendDataToNetwork 不会在同一个线程运行doInBackground()。有一种可能性,即 SendDataToNetwork 将开始发送数据套接字准备好了。

要避免这一切只需要使用 SendDataToNetwork 数据和信号保存到后台线程数据准备发送。

由于存在可能性,即用户可以preSS按钮多次,而旧数据仍然被发送,你应该有内部NetworkTask同步队列。然后:

  1. 在后台线程设置了插座连接,然后进入睡眠状态(通过等待())。
  2. 在按钮preSS, SendDataToNetwork 将数据添加到队列并唤醒后台线程(通过通知())。
  3. 当后台线程被唤醒时,它首先检查完成标志。如果设置,关闭连接并退出。如果不是从队列中读取数据,并将其发送到网络,并接着睡。
  4. 您应该完成()方法,设置了一个完成标志(原子变量,如布尔值)和唤醒后台线程。这是一种正常退出后台线程。

看看线程同步是怎么做的: http://www.jchq.net/教程/ 07_03Tut.htm

Most of the network socket examples I found for Android were one directional only. I needed a solution for a bi-directional data stream. I eventually learned of the AsyncTask. This example shows how to get data from a socket and send data back to it. Due to the blocking nature of a socket that is receiving data, that blocking needs to run in a thread other than the UI thread.

For the sake of example, this code connects to a webserver. Pressing the "Start AsyncTask" button will open the socket. Once the socket is open, the web server waits for a request. Pressing the "Send Message" button will send a request to the server. Any response from the server will be displayed in the TextView. In the case of http, a web server will disconnect from the client once all the data has been sent. For other TCP data streams, the connection will stay up until one side disconnects.

Screenshot:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.exampleasynctask"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

res\layout\main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start AsyncTask"></Button>
<Button android:id="@+id/btnSend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Message"></Button>
<TextView android:id="@+id/textStatus" android:textSize="24sp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Status Goes Here" />
</LinearLayout>

src\com.exampleasynctask\MainActivity.java:

package com.exampleasynctask;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    Button btnStart, btnSend;
    TextView textStatus;
    NetworkTask networktask;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btnStart = (Button)findViewById(R.id.btnStart);
        btnSend = (Button)findViewById(R.id.btnSend);
        textStatus = (TextView)findViewById(R.id.textStatus);
        btnStart.setOnClickListener(btnStartListener);
        btnSend.setOnClickListener(btnSendListener);
        networktask = new NetworkTask(); //Create initial instance so SendDataToNetwork doesn't throw an error.
    }

    private OnClickListener btnStartListener = new OnClickListener() {
        public void onClick(View v){
            btnStart.setVisibility(View.INVISIBLE);
            networktask = new NetworkTask(); //New instance of NetworkTask
            networktask.execute();
        }
    };
    private OnClickListener btnSendListener = new OnClickListener() {
        public void onClick(View v){
            textStatus.setText("Sending Message to AsyncTask.");
            networktask.SendDataToNetwork("GET / HTTP/1.1\r\n\r\n");
        }
    };

    public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {
        Socket nsocket; //Network Socket
        InputStream nis; //Network Input Stream
        OutputStream nos; //Network Output Stream

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

        @Override
        protected Boolean doInBackground(Void... params) { //This runs on a different thread
            boolean result = false;
            try {
                Log.i("AsyncTask", "doInBackground: Creating socket");
                SocketAddress sockaddr = new InetSocketAddress("192.168.1.1", 80);
                nsocket = new Socket();
                nsocket.connect(sockaddr, 5000); //10 second connection timeout
                if (nsocket.isConnected()) { 
                    nis = nsocket.getInputStream();
                    nos = nsocket.getOutputStream();
                    Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
                    Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
                    byte[] buffer = new byte[4096];
                    int read = nis.read(buffer, 0, 4096); //This is blocking
                    while(read != -1){
                        byte[] tempdata = new byte[read];
                        System.arraycopy(buffer, 0, tempdata, 0, read);
                        publishProgress(tempdata);
                        Log.i("AsyncTask", "doInBackground: Got some data");
                        read = nis.read(buffer, 0, 4096); //This is blocking
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.i("AsyncTask", "doInBackground: IOException");
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
                Log.i("AsyncTask", "doInBackground: Exception");
                result = true;
            } finally {
                try {
                    nis.close();
                    nos.close();
                    nsocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Log.i("AsyncTask", "doInBackground: Finished");
            }
            return result;
        }

        public void SendDataToNetwork(String cmd) { //You run this from the main thread.
            try {
                if (nsocket.isConnected()) {
                    Log.i("AsyncTask", "SendDataToNetwork: Writing received message to socket");
                    nos.write(cmd.getBytes());
                } else {
                    Log.i("AsyncTask", "SendDataToNetwork: Cannot send message. Socket is closed");
                }
            } catch (Exception e) {
                Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Caught an exception");
            }
        }

        @Override
        protected void onProgressUpdate(byte[]... values) {
            if (values.length > 0) {
                Log.i("AsyncTask", "onProgressUpdate: " + values[0].length + " bytes received.");
                textStatus.setText(new String(values[0]));
            }
        }
        @Override
        protected void onCancelled() {
            Log.i("AsyncTask", "Cancelled.");
            btnStart.setVisibility(View.VISIBLE);
        }
        @Override
        protected void onPostExecute(Boolean result) {
            if (result) {
                Log.i("AsyncTask", "onPostExecute: Completed with an Error.");
                textStatus.setText("There was a connection error.");
            } else {
                Log.i("AsyncTask", "onPostExecute: Completed.");
            }
            btnStart.setVisibility(View.VISIBLE);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        networktask.cancel(true); //In case the task is currently running
    }
}

解决方案

Your SendDataToNetwork does not run on the same thread as doInBackground(). There is a possibility that SendDataToNetwork would start sending data before socket is ready.

To avoid all this just use SendDataToNetwork to save data and signal to background thread that data is ready to be sent.

Since there is possibility that user can press button multiple times, while the old data is still being sent, you should have synchronized Queue inside NetworkTask. Then:

  1. Background thread sets up the socket connection and then goes to sleep (via wait()).
  2. On button press, SendDataToNetwork adds data to queue and wakes up the background thread (via notify()).
  3. When background thread wakes up, it first checks the finish flag. If set, it closes connections and exits. If not it reads data from Queue, sends it to network and goes back to sleep.
  4. You should have finish() method which sets a finish flag (atomic variable, like boolean) and wakes the background thread. This is a way to gracefully exit the background thread.

Take a look at how thread synchronization is done: http://www.jchq.net/tutorial/07_03Tut.htm

这篇关于例如:使用AsyncTask的Andr​​oid的双向网络套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆