Отображение изображения во флаттере, отправка через сокет - PullRequest
0 голосов
/ 24 марта 2019

Я пытаюсь создать соединение сервер-клиент с использованием сокетов.Сервер - это просто Эхо-сервер.Я хочу отправить туда разные типы данных.Я начал с изображений.Чего я хочу добиться:

  1. Анализировать изображение, хранящееся в папке ресурсов, в соответствующий тип данных
  2. Отправить его на Echo Server
  3. Получить данные обратно на мобильный(клиент) site
  4. Отображение изображения, отправленного таким образом (чтобы убедиться, что данные были отправлены правильно)

Я реализовал и Клиент, и Сервер.Клиент во Флаттере, Сервер в Ктор.Реализация сервера была скопирована из учебника: https://ktor.io/servers/raw-sockets.html. Я вижу, что мой сервер получает изображение и отправляет его обратно правильно, но я не могу его показать.

Код сервера:

fun main() {
    runBlocking {
        val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(InetSocketAddress("localhost", 8080))
        println("Started echo telnet server at ${server.localAddress}")

        while (true) {
            val socket = server.accept()

            launch {
                println("Socket accepted: ${socket.remoteAddress}")

                val input = socket.openReadChannel()
                val output = socket.openWriteChannel(autoFlush = true)

                try {
                    while (true) {
                        val line = input.readUTF8Line()

                        line?.let {
                            println("Client sent: $line")
                            output.writeStringUtf8(it)
                        }
                    }
                } catch (e: Throwable) {
                    println("Closing socket")
                    e.printStackTrace()
                    socket.close()
                }
            }
        }
    }
}

и клиент:

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key key, @required this.title}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  Socket _socket;
  List<int> _connectionTimes = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          RaisedButton(
            child: const Text('Connect to socket'),
            color: Theme.of(context).accentColor,
            elevation: 4.0,
            onPressed: () {
              closeSocket();
              _connectToSocket().then((createdSocket) {
                setState(() {
                  _socket = createdSocket;
                });
              });
            },
          ),
          RaisedButton(
            child: const Text('Send to socket'),
            color: Theme.of(context).accentColor,
            elevation: 4.0,
            onPressed: () {
              _sendMessage();
            },
          ),
          StreamBuilder(
            stream: _socket,
            builder: (context, snapshot) {
              if(snapshot.hasData) {
                final bytes = base64Decode(utf8.decode(snapshot.data));
                return Image.memory(bytes);
              } else {
                return Text("no image");
              }
            },
          ),
        ],
      )),
    );
  }

  Future<Socket> _connectToSocket() async {
    final stopwatch = Stopwatch()..start();
    Socket sock = await Socket.connect('10.0.2.2', 8080);
    print("Connection time was ${stopwatch.elapsedMilliseconds}");
    return sock;
  }

  void _sendMessage() async{
    final imageBytes = await rootBundle.load('assets/images/dog.jpeg');
    final bytesAsString = base64Encode(imageBytes.buffer.asUint8List(imageBytes.offsetInBytes, imageBytes.lengthInBytes));
    print(bytesAsString);
    _socket.write(bytesAsString+"\n");
  }

  void closeSocket() {
    if (_socket != null) {
      _socket.close();
    }
  }

  @override
  void dispose() {
    _socket.close();
    super.dispose();
  }
}

Я получаю ошибку:

E/flutter ( 8235): [ERROR:flutter/lib/ui/painting/codec.cc(97)] Failed decoding image. Data is either invalid, or it is encoded using an unsupported format.
I/flutter ( 8235): ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
I/flutter ( 8235): The following _Exception was thrown resolving an image codec:
I/flutter ( 8235): Exception: operation failed
I/flutter ( 8235): ════════════════════════════════════════════════════════════════════════════════════════════════════

И, кроме того, у меня есть еще несколько вопросов:

  1. Есть ли лучший способ разобрать изображение из ресурсов во Flutter?

  2. Есть ли способ отправить эти данные без добавления \n в концеданные изображения?

  3. Возможно ли, что изображение будет слишком большим, и я не смогу отправить его за один запрос?Если да, что я должен изменить в коде, чтобы он работал?Разделите его на несколько вызовов и используйте буфер на клиенте и на сервере?

  4. Что я должен изменить в коде сервера, чтобы я мог запустить его один раз, а также подключаться и отключаться с помощью одного клиентамногократно?(Это раздражает, что при каждом изменении, которое я вносю в код Flutter, мне приходится перезапускать сервер, чтобы он работал правильно?

Я открыт для изменения реализации сервера на другой каркас / языкЯ хочу использовать Flutter, но это не обязательно должен быть Ktor на сайте сервера. Просто хотел проверить это в действии.

1 Ответ

0 голосов
/ 25 марта 2019

Я могу использовать следующий код для чтения изображения jpg из фотогалереи, отправки на сервер node.js с помощью socket.io, а затем передачи другому клиенту (при этом сохраните изображение в mysql, простокак WhatsApp отправить изображение)

String base64Image1 = '';

// strImage1 is the path of the photo gallery retrieved by the plugin path_provider, plus the file name of the image.
String strImage1 = gv.strHomeImageFileWithPath + '_01.jpg';

var filImage1 = new File(strImage1);

List<int> imageBytes1 = filImage1.readAsBytesSync();

// use the following line if another client wants to display this image in html
// base64Image1 = 'data:image/jpg;base64,' + base64Encode(imageBytes1);

// Or, use the following line if another client wants to display this image in flutter
base64Image1 = base64Encode(imageBytes1);

// Send the b64 image string to the server
gv.socket.emit('PIBRequestPhotoClassify', [base64Image1]);

Кажется, что мои коды для декодирования и отображения строки изображения b64 такие же, как у вас, но коды для кодирования изображения разные, пожалуйста.попробовать.

...