Flutter StreamBuilder и Python TCP Socket Server не могут подключиться - PullRequest
0 голосов
/ 08 мая 2020

Я пытаюсь написать приложение флаттера для приложения IoT. Мобильное устройство будет подключаться к оборудованию через Wi-Fi, а данные будут отправляться через TCP-сокет. Оборудование IoT находится в разработке, но мне нужно начать работу с приложением.

Мне немного помог сценарий python, который запускает сокет и выводит 2 синусоидальные волны, которые были слегка рандомизированы. Он работает хорошо, и у меня есть сценарий хоста python, который подключается к нему и отображает данные по мере их поступления. Я собираюсь притвориться, что это данные датчика, поэтому я хочу подключиться к нему с помощью флаттера, чтобы я мог начать работать над своим пользовательским интерфейсом et c.

Я пробовал 1000 вещей, но в основном работал над этим: https://flutter.dev/docs/cookbook/networking/web-sockets.

Еще я пробовал использовать nodejs с socket.io, и мне удалось связаться с flutter с помощью пакета adhara_socket_io, но там так много абстракции, что я беспокоюсь, что это не реплицирует то, что я получу. наше оборудование.

Вот код python:

import queue
import time

#import matplotlib.pyplot as plt
import math
from queue import Queue

import numpy as np
import random
import socket
import threading
import asyncio


# A Queue in which the wave threads will store their values
# We will use this queue to get the data we need to send to our clients
Q = queue.Queue()

# replace this with your own host ip
HOST = '192.168.0.13'
PORT = 65432
Afrequency = float(input('give the frequency of the data output wave A: '))
Aperiod = int(input('give the output period (multiples of pi) of wave A: '))
Bfrequency = float(input('give the frequency of data output wave B: '))
Bperiod = int(input('give the output period (multiples of pi) of wave B: '))

# this function will continuosly generate x and y values for a given sine wave
# it waits 1/freq seconds so our frequency matches the given input


def generateTuples(name, outputfrequency, outputperiod):

    sincurveshift = 10
    rmax = 1.25
    rmin = 0.75
    outputperiod = outputperiod * math.pi
    numberOfPoints = outputfrequency * outputperiod
    increment = (2 * math.pi) / numberOfPoints
    xcounter = 0

    while True:
        jitterValue = rmin + (random.random() * (rmax - rmin))
        x = xcounter * increment
        sinValue = 5 * math.sin(x) + sincurveshift * jitterValue
        partOfTheMessage = '%s(%09.2f,%09.2f)*' % (name, x, sinValue)
        xcounter += 1
        Q.put(partOfTheMessage)
        time.sleep(1/outputfrequency)


# this is a thread that will be created each time a client connects
# it sends the total string with values from wave A and B
class clientThread(threading.Thread):
    def __init__(self, clientAddress, clientSocket, q):
        threading.Thread.__init__(self)
        self.clientSocket = clientSocket

        print("New client connected with address: " + str(clientAddress))

    def run(self):
        while True:
            self.clientSocket.send(bytes(Q.get(), 'utf-8'))
            time.sleep(0.1)


def main():
    # first we start up 2 threads that will each generate a y value every 1/freq seconds
    # we let them run in the background so we can move on to listening for clients
    print('starting sine wave 1')
    print('starting sine wave 2')
    wave1 = threading.Thread(target=generateTuples, args=(
        'A', Afrequency, Aperiod), daemon=True)
    wave2 = threading.Thread(target=generateTuples, args=(
        'B', Bfrequency, Bperiod), daemon=True)
    wave1.start()
    wave2.start()
    time.sleep(1)

    print('starting transmission')

    # here we set up the host
    # we continously look for clients and give each of them their own thread
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((HOST, PORT))
        s.listen()
        while True:
            conn, addr = s.accept()
            client = clientThread(addr, conn, queue)
            client.start()


if __name__ == "__main__":

    main()

А вот мой код флаттера.

import 'package:flutter/foundation.dart';
import 'package:web_socket_channel/io.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'MyApp Mobile'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final channel = IOWebSocketChannel.connect('ws://192.168.0.13:65432');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: StreamBuilder(
        stream: channel.stream,
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
            case ConnectionState.none:
              print('trying to connect');
              return LinearProgressIndicator();
            case ConnectionState.active:
              print("OMG ITS CONNECTED");
              print(snapshot.data);
              return Text(snapshot.data);
            case ConnectionState.done:
              return Text('Its done ${snapshot.data}');
          }

          return Text(snapshot.hasData ? '${snapshot.data}' : 'No Data');
        },
      )),
    );
  }
}

Я использую свой телефон для запуска разрабатываемого приложения - не уверен, что это имеет значение. Любая помощь приветствуется!

N

EDIT - теперь я вижу ошибку в консоли python:

New client connected with address: ('192.168.0.16', 65020)
Exception in thread Thread-24:
Traceback (most recent call last):
  File "C:\Users\nickc\AppData\Local\Programs\Python\Python38-32\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "host.py", line 62, in run
    self.clientSocket.send(bytes(Q.get(), 'utf-8'))
ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine

Так что похоже, что он подключается а затем прерывает соединение?

Как уже упоминалось shubham в одном из ответов, я могу успешно подключиться и распечатать входящие данные на консоли с помощью:

Socket socket = await Socket.connect(host, port);
socket.listen((event) {
  print(String.fromCharCodes(event));
});

1 Ответ

0 голосов
/ 09 мая 2020

Я не очень хорошо разбираюсь в пакете каналов веб-сокетов, но когда я попытался запустить ваш код, у меня возникла ошибка сломанной трубы в коде python, как только мой клиент (телефон) подключился и после прохождения этого post Я думаю, что клиентский сокет каким-то образом закрывается.

Но я могу подключиться к вашему python сокету с помощью пакета сокетов dart Вот код

Socket socket = await Socket.connect(host, port);
socket.listen((event) {
  log(String.fromCharCodes(event));
});

Вот результат, который я получил

[log] B(000051.07,000013.89)*
[log] B(000051.11,000013.26)*
[log] B(000051.14,000016.09)*
[log] B(000051.18,000013.77)*
[log] B(000051.21,000015.63)*
[log] B(000051.25,000013.78)*
[log] B(000051.29,000013.49)*
[log] B(000051.32,000016.75)*
[log] A(000103.50,000012.36)*
[log] A(000103.58,000009.93)*
[log] A(000103.67,000007.72)*
[log] A(000103.75,000009.02)*
[log] A(000103.83,000008.28)*
...