如何在Android上建立套接字连接

时间:2016-09-28 21:33:39

标签: java android sockets android-asynctask android-service

我正在尝试创建一个简单的应用,发送一条来自EditText的消息, 使用Java Socket类。我正在尝试使用AsyncTask,但它只能运行一次,我无法返回套接字以便在该类的另一个实例中重用。

你能给我一个后台服务的例子,它打开与服务器的通信并返回Socket吗?

修改
根据 nandsito 的要求;我打算使用Button打开连接,因此该按钮调用beckground进程,该进程创建与服务器的连接,最后返回Socket。当我按下另一个Button我想开始另一个重用套接字的任务时,写入数据(例如Sring)会从服务器接收响应并更新UI。

3 个答案:

答案 0 :(得分:0)

看起来很简单,但我认为你有一个有趣且具有挑战性的问题。如果你想在通过它发送消息后保持套接字打开,你需要维护一个或多个线程来使用该套接字,因为,你知道,Android不允许在主线程上建立网络。

多线程编程很少简单,通常有多种方法可以实现。例如。在Android中,您可以将HandlerLooper s中的HandlerThread或经典Java Thread一起使用。还有AsyncTask,但我认为它不适合这种情况。

您打算如何管理套接字生命周期(即何时打开或关闭),以及在哪些时刻从插槽读取/写入数据?请更好地解释这个问题,以便我建议实施。

修改

这是一个带有两个按钮的示例Activity。一个按钮运行AsyncTask,创建一个套接字及其流,另一个按钮运行另一个AsyncTask,将数据写入套接字。这是一个过度简化的解决方案,但应该可行。请注意,代码需要同步,以便不同的线程访问套接字。

public class MainActivity extends Activity {

    private SocketContainer mSocketContainer;
    private final Object mSocketContainerLock = new Object();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // onClick attribute of one button.
    public void onClickPushMe(View view) {
        String serverAddress;
        int serverPort;
        new CreateSocketAsyncTask(serverAddress, serverPort).execute();
    }

    // onClick attribute of other button.
    public void onClickPushMeToo(View view) {
        String text;
        new WriteSocketAsyncTask(text).execute();
    }

    // Class that contains the socket and its streams,
    // so they can be passed from one thread to another.
    private class SocketContainer {

        private Socket mSocket;
        private InputStream mSocketInputStream;
        private OutputStream mSocketOutputStream;

        private SocketContainer(Socket socket, InputStream socketInputStream, OutputStream socketOutputStream) {
            mSocket = socket;
            mSocketInputStream = socketInputStream;
            mSocketOutputStream = socketOutputStream;
        }

        private Socket getSocket() {
            return mSocket;
        }

        private InputStream getSocketInputStream() {
            return mSocketInputStream;
        }

        private OutputStream getSocketOutputStream() {
            return mSocketOutputStream;
        }
    }

    // AsyncTask that creates a SocketContainer and sets in into MainActivity.
    private class CreateSocketAsyncTask extends AsyncTask<Void, Void, SocketContainer> {

        private final String mServerAddress;
        private final int mServerPort;

        private CreateSocketAsyncTask(String serverAddress, int serverPort) {
            mServerAddress = serverAddress;
            mServerPort = serverPort;
        }

        protected SocketContainer doInBackground(Void... params) {
            try {
                Socket socket = new Socket(mServerAddress, mServerPort);
                return new SocketContainer(socket, socket.getInputStream(), socket.getOutputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        protected void onPostExecute(SocketContainer socketContainer) {
            super.onPostExecute(socketContainer);
            synchronized (mSocketContainerLock) {
                mSocketContainer = socketContainer;
            }
        }
    }

    private class WriteSocketAsyncTask extends AsyncTask<Void, Void, Void> {

        private final String mText;

        private WriteSocketAsyncTask(String text) {
            mText = text;
        }

        @Override
        protected Void doInBackground(Void... params) {
            synchronized (mSocketContainerLock) {
                try {
                    mSocketContainer.getSocketOutputStream().write(mText.getBytes(Charset.forName("UTF-8")));
                    mSocketContainer.getSocketOutputStream().flush();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return null;
        }
    }
}

答案 1 :(得分:0)

使用此代码我连接到聊天,因此您可以使用similliary连接您想要的内容

 public class SocialConnectionManager extends AsyncTask<Void, Void, Void> {

    public static final int SQL_STEP_LOGIN = 0;
    public static final int SQL_STEP_LOGOUT = 1;
    public static final int SQL_STEP_SEND = 2;
    public static final int SQL_STEP_UPDATE = 3;

    final int serverPort = 8080;
    private String message, channel, userName, serverIp;
    private int step;
    private long uniqueId;
    private Activity activity;

    public SocialConnectionManager(String serverIp, long uniqueId, int step, String userName,
                                   String channel, String message, Activity activity) {
        this.message = message;
        this.step = step;
        this.uniqueId = uniqueId;
        this.channel = channel;
        this.userName = userName;
        this.serverIp = serverIp;
        this.activity = activity;
    }

    @Override
    protected Void doInBackground(Void... arg0) {

        Socket socket = null;

        try {
            socket = new Socket(serverIp, serverPort);
            DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
            switch (step) {
                case SQL_STEP_LOGIN:
                    dataOut.writeInt(step);
                    dataOut.writeLong(uniqueId);
                    dataOut.writeUTF(channel);
                    dataOut.writeUTF(userName);
                    break;
                case SQL_STEP_LOGOUT:
                    dataOut.writeInt(step);
                    dataOut.writeLong(uniqueId);
                    dataOut.writeUTF(channel);
                    dataOut.writeUTF(userName);
                    break;
                case SQL_STEP_SEND:
                    long messageId = createRandomId();
                    messageIds.add(messageId);
                    dataOut.writeInt(step);
                    dataOut.writeLong(uniqueId);
                    dataOut.writeUTF(channel);
                    dataOut.writeUTF(userName);
                    dataOut.writeUTF(message);
                    dataOut.writeLong(messageId);
                    break;
                case SQL_STEP_UPDATE:
                    dataOut.writeInt(step);
                    dataOut.writeUTF(message);
                    break;
            }
            dataOut.flush();

        } catch (UnknownHostException e) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ((MainActivity) activity).showNetworkAlertDialog(context.getString
                            (R.string.social_chat_connection_failed));
                }
            });
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    }
}

private class ReceiveTask extends AsyncTask {

    final int clientPort = 5050;

    @Override
    protected Object doInBackground(Object[] params) {
        try {
            serverSocket = new ServerSocket(clientPort);
            while (true) {
                final Socket socket = serverSocket.accept();
                DataInputStream dataIn = new DataInputStream(socket.getInputStream());
                final int step = dataIn.readInt();
                final int userCount = dataIn.readInt();
                final String message = dataIn.readUTF();
                final String userName = dataIn.readUTF();
                switch (step) {
                    case SocialConnectionManager.SQL_STEP_LOGIN:
                        if (isLogging) {
                            activity.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    showProgress(false);
                                }
                            });
                            isLogging = false;
                            isLoggedIn = true;
                        }
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                userCountView.setText(Integer.toString(userCount));
                                addMessage(message, userName, step);
                            }
                        });
                        break;
                    case SocialConnectionManager.SQL_STEP_LOGOUT:
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addMessage(message, userName, step);
                            }
                        });
                        break;
                    case SocialConnectionManager.SQL_STEP_SEND:
                        messageId = dataIn.readLong();
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addMessage(message, userName, step);
                            }
                        });
                        break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

BroadcastReceiver networkStateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String ip = getIpAddress();
        if (ip.equals("")) {
            ((MainActivity) activity).showNetworkAlertDialog(context.getString
                    (R.string.social_chat_connection_lost));
        } else if (!deviceIp.equals(ip)) {
            SocialConnectionManager socialConnectionManager =
                    new SocialConnectionManager(serverIp, 0,
                            SocialConnectionManager.SQL_STEP_UPDATE, null, null, deviceIp,
                            activity);
            socialConnectionManager.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }
    }
};

}

答案 2 :(得分:0)

异步任务不值得实时聊天。 进入firebase以轻松使用。 这可能对你有帮助 - https://www.firebase.com/docs/android/examples.html