Django Channels 不向 Android App 发送消息

Posted

技术标签:

【中文标题】Django Channels 不向 Android App 发送消息【英文标题】:Django Channels dont sent message to Android App 【发布时间】:2019-07-25 11:23:03 【问题描述】:

我想将https://channels.readthedocs.io/en/latest/tutorial/part_2.html 的官方 django 频道教程应用到一个简单的 android 应用程序中。

在https://medium.com/@ssaurel/learn-to-use-websockets-on-android-with-okhttp-ba5f00aea988,我找到了一个简单的项目,但它使用http://www.websocket.org/echo.html 提供的Echo WebSocket 服务器。

我复制粘贴了同一个项目,但使用 django 通道将 Echo WebSocket 服务器替换为我自己的 websocket 服务器。

代码如下:

public class MainActivity extends AppCompatActivity 

    private static final String TAG = "MainActivity";
    private Button start;
    private TextView output;
    private OkHttpClient client;



    private final class EchoWebSocketListener extends WebSocketListener 
        private static final int NORMAL_CLOSURE_STATUS = 1000;

        @Override
        public void onOpen(WebSocket webSocket, Response response) 
            Log.d(TAG, "onOpen() is called.");
            JSONObject obj = new JSONObject();
            JSONObject obj2 = new JSONObject();
            try 
                obj.put("message" , "Hello");
                obj2.put("message", "Goodbye!");
             catch (JSONException e) 
                e.printStackTrace();
            

            webSocket.send(obj.toString());

            //webSocket.send("What's up ?");
            //webSocket.send(ByteString.decodeHex("deadbeef"));
            webSocket.close(NORMAL_CLOSURE_STATUS, obj2.toString());
        

        @Override
        public void onMessage(WebSocket webSocket, String text) 
            Log.d(TAG, "onMessage() for String is called.");
            output("Receiving : " + text);
        

        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) 
            Log.d(TAG, "onMessage() for ByteString is called.");
            output("Receiving bytes : " + bytes.hex());
        

        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) 
            Log.d(TAG, "onClosing() is called.");
            webSocket.close(NORMAL_CLOSURE_STATUS, null);
            output("Closing : " + code + " / " + reason);
        

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) 
            Log.d(TAG, "onFailure() is called.");
            output("Error : " + t.getMessage());
        
    

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start = (Button) findViewById(R.id.start);
        output = (TextView) findViewById(R.id.output);
        client = new OkHttpClient();
        start.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                start();
            
        );
    

    void start() 
        Request request = new Request.Builder().url("ws://192.168.122.1:8080/ws/chat/lobby/").build();
        EchoWebSocketListener listener = new EchoWebSocketListener();
        WebSocket ws = client.newWebSocket(request, listener);
        client.dispatcher().executorService().shutdown();
    
    private void output(final String txt) 
        runOnUiThread(new Runnable() 
            @Override
            public void run() 
                output.setText(output.getText().toString() + "\n\n" + txt);
            
        );
    

要向/从服务器发送和接收消息,他们使用 okhttp3 库中的 WebSocketListener。

我的consumers.py 文件与 Django 频道教程中的相同。更具体地说,我使用了相同的设置。 尽管如此,为了在同一页面上,我发布了我的 consumers.py 文件的样子:

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json

class SignallingConsumer(WebsocketConsumer):
    def connect(self):
        print("connect() is called.")
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        # Join room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )

        self.accept()

    def disconnect(self, close_code):
        print("disconnect() is called.")

        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data):
        print("receive() is called with " + text_data)
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        print("message contains: " + message)

        # Send message to room group
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            
                'type': 'chat_message',
                'message': message
            
        )

     # Receive message from room group
    def chat_message(self, event):
        print("the message from the event is: " + event['message'])
        message = event['message']

        # Send message to WebSocket
        self.send(text_data=json.dumps(
            'message': message
        ))

我添加了一些打印内容以更好地了解幕后情况,并更改了消费者的名称,因为我想稍后在了解基础知识后将其用作另一个项目的信号服务器。

在控制台上,我得到以下信息:

System check identified no issues (0 silenced).
July 25, 2019 - 10:34:24
Django version 2.2.3, using settings 'signalingserver.settings'
Starting ASGI/Channels version 2.2.0 development server at http://192.168.122.1:8080/
Quit the server with CONTROL-C.
WebSocket HANDSHAKING /ws/chat/lobby/ [192.168.122.1:54194]
connect() is called.
WebSocket CONNECT /ws/chat/lobby/ [192.168.122.1:54194]
receive() is called with "message":"Hello"
message contains: Hello
WebSocket DISCONNECT /ws/chat/lobby/ [192.168.122.1:54194]
the message from the event is: Hello
disconnect() is called.

我的 LogCat 输出如下:

07-25 12:35:22.754 5297-5319/com.celik.abdullah.simplewebsocketproject D/MainActivity: onOpen() is called.
07-25 12:35:22.810 5297-5319/com.celik.abdullah.simplewebsocketproject D/MainActivity: onClosing() is called.

从这些输出中,我假设连接和发送部分正在运行。但是从 websocket 服务器接收数据不起作用,因为我的客户端(android 应用程序)上的 onMessage() 没有被调用。

如何解决?

提前谢谢你。

【问题讨论】:

【参考方案1】:

如果其他人看到这一点,问题是因为您在有机会从服务器接收任何返回之前关闭了 onOpen 方法中的 Web 套接字。您应该删除该行:

webSocket.close(NORMAL_CLOSURE_STATUS, obj2.toString());

当您不再使用网络套接字连接时,稍后调用 close。

其他一切看起来都很棒,并且按原样工作。

【讨论】:

以上是关于Django Channels 不向 Android App 发送消息的主要内容,如果未能解决你的问题,请参考以下文章

django 频道 channels.exceptions.Channels Full

Django不向管理员发送电子邮件

Django Channels 是不是使用 ws:// 协议前缀在 Django 视图或 Channels 应用程序之间进行路由?

Django使用Channels实现WebSocket--下篇

Vue axios 不向服务器发送标头(django simplejwt)

Django Channels 测试失败