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

时间:2019-03-24 17:46:56

标签: sockets dart flutter base64 ktor

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

  1. 将资产文件夹中存储的图像解析为适当的数据类型
  2. 发送到Echo Server
  3. 在移动(客户端)站点上接收数据
  4. 显示以这种方式发送的图像(确保数据发送正确)

我已经实现了客户端和服务器。客户端在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): ════════════════════════════════════════════════════════════════════════════════════════════════════

此外,我还有其他问题:

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

  2. 是否可以在不将图像数据末尾添加\n的情况下发送此数据?

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

  4. 我应该在服务器代码中进行哪些更改,这使我可以运行一次,并与单个客户端多次连接和断开连接? (这很烦人,我对Flutter代码进行的每项更改都必须重新运行服务器才能使其正常运行?

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

1 个答案:

答案 0 :(得分:0)

我能够使用以下代码从照片库中读取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图像字符串的代码与您的相同,但是对图像进行编码的代码不同。尝试。