ZetCode

Dart RawServerSocket

最后修改于 2025 年 4 月 4 日

Dart 中的 RawServerSocket 类提供了低级的 TCP 服务器套接字功能。它是 Dart 的 dart:io 库的一部分,用于非 Web 应用程序。

RawServerSocket 允许与 TCP 客户端进行直接的字节级通信。它适用于自定义协议、性能关键型应用程序和二进制数据。

基本定义

RawServerSocket 是一个服务器端套接字,用于监听传入的 TCP 连接。它提供原始字节流,不进行更高级别的协议处理。

主要功能包括异步操作、连接事件处理以及对套接字流的直接访问。它是构建自定义网络服务器的基础。

基本回显服务器

此示例展示了一个使用 RawServerSocket 的简单回显服务器。

main.dart
import 'dart:io';

void main() async {
  var server = await RawServerSocket.bind('127.0.0.1', 4040);
  print('Echo server listening on ${server.address}:${server.port}');

  server.listen((client) {
    client.listen((data) {
      client.add(data); // Echo back received data
    }, onDone: () => client.close());
  });
}

我们创建一个在 localhost 端口 4040 上监听的服务器。当客户端连接时,我们会将它们发送的任何数据回显回去。服务器异步处理多个客户端。

$ dart main.dart
Echo server listening on 127.0.0.1:4040

处理客户端连接

此示例演示了详细的客户端连接处理。

main.dart
import 'dart:io';

void main() async {
  var server = await RawServerSocket.bind('0.0.0.0', 4041);
  print('Server started on port ${server.port}');

  server.listen((client) {
    print('Client connected from ${client.remoteAddress.address}');
    
    client.handleError((error) {
      print('Client error: $error');
    }, test: (error) => true);
    
    client.listen((data) {
      print('Received ${data.length} bytes');
      client.add([0x01, 0x02, 0x03]); // Send response
    }, onDone: () {
      print('Client disconnected');
      client.close();
    });
  });
}

我们记录客户端连接,处理错误,并发送固定响应。remoteAddress 属性用于标识连接的客户端。错误处理可确保服务器的稳定性。

$ dart main.dart
Server started on port 4041
Client connected from 127.0.0.1
Received 5 bytes
Client disconnected

广播服务器

此示例展示了一个将消息广播到所有连接客户端的服务器。

main.dart
import 'dart:io';
import 'dart:async';

void main() async {
  var server = await RawServerSocket.bind('127.0.0.1', 4042);
  var clients = <RawSocket>[];
  
  server.listen((client) {
    clients.add(client);
    print('New client (${clients.length} total)');
    
    client.listen((_) {}, onDone: () {
      clients.remove(client);
      print('Client disconnected (${clients.length} remaining)');
    });
  });

  // Broadcast timer
  Timer.periodic(Duration(seconds: 2), (_) {
    var message = 'Server time: ${DateTime.now()}\n'.codeUnits;
    for (var client in clients) {
      client.add(message);
    }
  });
}

我们维护一个已连接客户端列表,并每 2 秒广播一次时间更新。服务器跟踪客户端的连接和断开连接。

$ dart main.dart
New client (1 total)
New client (2 total)
Client disconnected (1 remaining)

端口扫描器

此示例演示了如何使用 RawServerSocket 检查端口可用性。

main.dart
import 'dart:io';

Future<bool> isPortAvailable(int port) async {
  try {
    var server = await RawServerSocket.bind('127.0.0.1', port);
    await server.close();
    return true;
  } catch (e) {
    return false;
  }
}

void main() async {
  var ports = [80, 4040, 8080, 3000];
  
  for (var port in ports) {
    var available = await isPortAvailable(port);
    print('Port $port: ${available ? 'available' : 'in use'}');
  }
}

我们尝试绑定到每个端口以检查可用性。成功绑定意味着该端口可用。服务器在检查后立即关闭。

$ dart main.dart
Port 80: in use
Port 4040: available
Port 8080: in use
Port 3000: available

自定义协议服务器

此示例实现了一个简单的自定义二进制协议服务器。

main.dart
import 'dart:io';

void main() async {
  var server = await RawServerSocket.bind('127.0.0.1', 4043);
  print('Custom protocol server started');

  server.listen((client) {
    var buffer = <int>[];
    
    client.listen((data) {
      buffer.addAll(data);
      
      // Process complete messages (delimited by 0xFF)
      while (buffer.contains(0xFF)) {
        var messageEnd = buffer.indexOf(0xFF);
        var message = buffer.sublist(0, messageEnd);
        buffer.removeRange(0, messageEnd + 1);
        
        print('Received message: $message');
        client.add([...message.reversed, 0xFF]); // Send reversed
      }
    }, onDone: () => client.close());
  });
}

我们实现了一个简单的协议,其中消息以 0xFF 结尾。服务器处理完整的消息并以反转的数据响应。部分消息会被缓冲。

$ dart main.dart
Custom protocol server started
Received message: [72, 101, 108, 108, 111]

最佳实践

来源

Dart RawServerSocket 文档

本教程通过实际示例介绍了 Dart 的 RawServerSocket 类,展示了服务器创建、客户端处理和自定义协议实现。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程