繁体   English   中英

多个线程从同一个套接字读取

[英]Multiple threads reading from same socket

我正在开发一个显示服务器数据的应用程序。 服务器不是我的,它不是很稳定。 连接太多会导致服务器崩溃。

我在主要活动中有一个到服务器的套接字,但有时我想打开读取数据并显示它的子活动。 我的问题是我无法使用相同的套接字实现此功能,并且必须为每个活动打开一个新套接字。 每个活动都有一个线程,它从套接字读取并根据需要更新该活动的UI元素。

为了在多个活动中使用相同的套接字,我尝试在开始新活动之前关闭活动的inputReader,但这只是让应用程序挂起。 如果我将其保持打开状态,则新活动中的新线程永远不会收到任何数据。 在开始新活动之前杀死线程是不可能的,因为线程通常被read()函数阻止。

无论如何我有一个集中的线程来执行读取,然后将数据发送到其他活动中的所有其他线程,这样我就不必在每个活动中打开新的套接字了吗?

我觉得这是我要问的一个非常基本的问题,但我无法找到解决方案。

基本上你自己回答了你的问题:

我可以有一个集中的线程来执行读取,然后将数据发送到其他活动中的所有其他线程。

意义:当然,这样的事情是可能的。 但你必须坐下来,设计并实施它。 您首先要定义一个合理的接口,允许您的其他线程与该中央服务进行通信 ,例如:

enum RequestType { DO_THIS, DO_THAT };

interface ServerConnectionService<T> {
   List<T> performRequest(RequestType request);
}

含义:不是让你的不同线程在该套接字上进行“低级别”交谈,而是创建一个抽象,允许你说:“当我需要这种信息时,我会使用我的服务;它会返回一些特定的答案当然,这是一个非常通用的答案,但是,你的问题也不完全具体。

接下来的步骤是对该接口进行一些中心(可能是单例)实现; 它在自己的线程上运行,并且可以由其他线程以同步的,明确定义的方式使用。

最后的警告:如果您没有该服务器,并且它质量低并且给您带来麻烦 - 这不是一个好的设置。 因为无论你在代码中做了什么,如果服务器做得不好,用户就会认为你的应用程序是问题所在。 由于某些远程服务器崩溃,用户不关心操作是否失败。 所以你问题的另一个方面是:现在,你处在一个不好的地方。 你应该花一些时间来寻找出路。 否则,您将浪费大量时间为您正在处理的服务器构建变通方法。

一个非常简单明了的方法如下:

  1. 您创建一个在后台运行并通过套接字与服务器通信的新Service
  2. Service从套接字接收数据并通过使用LocalBroadcastManager将其转发/广播到您有兴趣接收它的所有活动(例如更新UI)
  3. 您的所有活动都实现了BroadcastReceiver并在onReceive()方法中从您的Service接收数据

要实现这一点,您应该阅读ServicesBroadcastReceivers的介绍,以了解它们的工作原理。 另外,为了首先获得基本概述,您应该阅读有关可用的App组件的信息

编辑,回答评论中的问题:

您可以随时停止Service调用stopService()但你也可以做到这一点不同,如果你不希望/需要的所有功能Service 代替的Service ,你也可以创建一个简单的ThreadHandlerThread与服务器communinicates。 从Thread内部,您可以使用上面提到的技术( LocalBroadcastManager )将数据转发/广播到您的活动。


只是为了给你一个基本结构的例子(尽管代码未经测试):

class SocketThread implements Runnable
{
    static final String SOCKET_DATA_RECEIVED = "com.your.package.SOCKET_DATA_RECEIVED";
    static final String SOCKET_DATA_IDENTIFIER = "com.your.package.SOCKET_DATA";
    private Context context;

    SocketThread(Context c) {
        context = c.getApplicationContext();
    }

    @Override
    public void run() { // code running in your thread
        // fetch data from socket ...
        Intent intent = new Intent();
        intent.putExtra(SOCKET_DATA_IDENTIFIER, data); // store data in your intent
        // send data to registered receivers
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        // your code ...
    }
}

然后你有你的活动,例如MyActivity1MyActivity2 ,... MyActivityN 它们都注册了它们的嵌入式SocketDataReceiver以接收由您的线程发送的广播意图SOCKET_DATA_RECEIVED

onReceive()方法中,您可以使用标识符SOCKET_DATA_IDENTIFIERintent对象中提取数据。

public class MyActivity1 extends Activity
{
    private SocketDataReceiver socketDataReceiver;

    @Override
    protected void onResume() {
        super.onResume();
        socketDataReceiver = new SocketDataReceiver();
        LocalBroadcastManager.getInstance(this).registerReceiver(
                socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
    }

    @Override
    protected void onPause() {
        super.onPause();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
    }

    private class SocketDataReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent) {
            // intent contains your socket data,
            // get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM