Saltar al contenido principal

Comunicarse con WebSockets

Cómo conectarse a un web socket.

Además de las solicitudes HTTP normales, puedes conectarte a servidores utilizando WebSockets. Los WebSockets permiten una comunicación bidireccional con un servidor sin necesidad de realizar sondeos (polling).

En este ejemplo, conéctate a un servidor WebSocket de prueba. El servidor devuelve el mismo mensaje que le envías. Esta receta utiliza los siguientes pasos:

  1. Conectarse a un servidor WebSocket.
  2. Escuchar mensajes del servidor.
  3. Enviar datos al servidor.
  4. Cerrar la conexión WebSocket.

1. Conectarse a un servidor WebSocket

#

El paquete web_socket_channel proporciona las herramientas que necesitas para conectarte a un servidor WebSocket.

El paquete proporciona un WebSocketChannel que te permite tanto escuchar mensajes del servidor como enviar mensajes al servidor.

En Flutter, utiliza la siguiente línea para crear un WebSocketChannel que se conecte a un servidor:

dart
final WebSocketChannel channel = WebSocketChannel.connect(
  Uri.parse('wss://echo.websocket.org'),
);

2. Escuchar mensajes del servidor

#

Ahora que has establecido una conexión, escucha los mensajes del servidor.

Después de enviar un mensaje al servidor de prueba, este devuelve el mismo mensaje.

En este ejemplo, utiliza un widget StreamBuilder para escuchar nuevos mensajes, y un widget Text para mostrarlos.

dart
StreamBuilder(
  stream: channel.stream,
  builder: (context, snapshot) {
    return Text(snapshot.hasData ? '${snapshot.data}' : '');
  },
),

Cómo funciona

#

El WebSocketChannel proporciona un Stream de mensajes desde el servidor.

La clase Stream es una parte fundamental del paquete dart:async. Proporciona una forma de escuchar eventos asíncronas desde una fuente de datos. A diferencia de Future, que devuelve una única respuesta asíncrona, la clase Stream puede entregar muchos eventos a lo largo del tiempo.

El widget StreamBuilder se conecta a un Stream y le pide a Flutter que se reconstruya cada vez que recibe un evento utilizando la función builder() proporcionada.

3. Enviar datos al servidor

#

Para enviar datos al servidor, agrega mensajes con add() al sink proporcionado por el WebSocketChannel.

dart
channel.sink.add('Hello!');

Cómo funciona

#

El WebSocketChannel proporciona un StreamSink para enviar mensajes al servidor.

La clase StreamSink proporciona una forma general de agregar eventos síncronos o asíncronos a una fuente de datos.

4. Cerrar la conexión WebSocket

#

Después de que hayas terminado de usar el WebSocket, cierra la conexión:

dart
channel.sink.close();

Ejemplo completo

#
dart
import 'package:flutter/material.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const title = 'WebSocket Demo';
    return const MaterialApp(
      title: title,
      home: MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  final WebSocketChannel _channel = WebSocketChannel.connect(
    Uri.parse('wss://echo.websocket.org'),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Form(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(labelText: 'Send a message'),
              ),
            ),
            const SizedBox(height: 24),
            StreamBuilder(
              stream: _channel.stream,
              builder: (context, snapshot) {
                return Text(snapshot.hasData ? '${snapshot.data}' : '');
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _sendMessage,
        tooltip: 'Send message',
        child: const Icon(Icons.send),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  void _sendMessage() {
    if (_controller.text.isNotEmpty) {
      _channel.sink.add(_controller.text);
    }
  }

  @override
  void dispose() {
    _channel.sink.close();
    _controller.dispose();
    super.dispose();
  }
}

Demostración de WebSockets