在 Flutter 中显示图像,通过套接字连接发送

Posted

技术标签:

【中文标题】在 Flutter 中显示图像,通过套接字连接发送【英文标题】:Displaying image in Flutter, send through socket connection 【发布时间】:2019-08-15 00:56:18 【问题描述】:

我正在尝试使用套接字创建服务器-客户端连接。服务器只是一个回声服务器。我想在那里发送不同类型的数据。我从图像开始。我想要实现的是:

    将存储在资产文件夹中的图像解析为适当的数据类型 发送到 Echo 服务器 在移动(客户端)网站上接收回数据 显示以这种方式发送的图像(可以肯定的是,数据发送正确)

我已经实现了客户端和服务器。客户端在 Flutter,服务器在 Ktor。 服务器实现复制自教程: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): ════════════════════════════════════════════════════════════════════════════════════════════════════

此外,我还有一些问题:

    在 Flutter 中是否有更好的方法从资产中解析图像?

    有没有办法在图像数据末尾不添加\n 的情况下发送此数据?

    图像是否可能太大,我无法在一个请求中发送它?如果是,我应该更改代码以使其正常工作?将其拆分为多个调用并在客户端和服务器上使用缓冲区?

    我应该对服务器代码进行哪些更改,这样我才能运行一次,并与单个客户端多次连接和断开连接? (很烦人,每次更改 Flutter 代码时,我都必须重新运行服务器才能正常工作?

我愿意将服务器实现更改为另一种框架/语言。我想使用 Flutter,但它不一定是服务器站点上的 Ktor。只是想检查一下。

【问题讨论】:

我不知道您的问题的答案,但我会首先记录您发送的数据并返回并比较它们(发送时base64编码之后,base64解码之前接收 - 可能使用尽可能小的图像以使字符串更短以进行测试)。 所以我尝试了非常小的图像(64x64 像素)并且我的代码有效。我还添加了检查,它比较发送到服务器和从服务器接收的字节(作为字符串)。对于小图像,它是正确的,显示图像。在更大的图像(225x225)上面写的错误被抛出,我从服务器收到的字符串(字节)完全不同。 我比较了大图,服务器上接收到的字符串。它完全一样,因为它是从客户端发送的。但是将其发送回客户端会以完全不同的方式解决。 【参考方案1】:

我可以使用以下代码从照片库中读取一张jpg图片,通过socket.io发送到node.js服务器,然后传输到另一个客户端(同时将图片保存在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图像字符串的代码和你的一样,但是编码图像的代码不同,请。试试看。

【讨论】:

如果我将文件放在assets/images/dog.jpeg 下,我应该输入filename of an image 什么?我试过这样做:final appPath = await getApplicationDocumentsDirectory(); String strImage1 = appPath.path + '/assets/images/dog_small.jpeg'; 它导致错误:[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: FileSystemException: Cannot open file, path = '/data/user/0/com.example.flutterclient/app_flutter/assets/images/dog_small.jpeg'

以上是关于在 Flutter 中显示图像,通过套接字连接发送的主要内容,如果未能解决你的问题,请参考以下文章

在聊天应用程序中使用 Web 套接字 Api 无法正确显示图像

Flutter中如何保存每个列表对象的状态

如何通过共享将文件发送到 Flutter 应用程序?

通过 java android 套接字发送图像

通过套接字从客户端发送缓冲图像到服务器

套接字编程/通过无线发送二进制图像数据