ZetCode

Dart RawSocket

最后修改于 2025 年 4 月 4 日

Dart 中的 RawSocket 类提供了低级的网络套接字通信功能。它允许直接进行 TCP/IP 套接字操作。

RawSocket 是 Dart 的 dart:io 库的一部分,与 HttpClient 或 WebSocket 等更高级的替代方案相比,它提供了更多的控制权。

基本定义

RawSocket 代表一个原始网络套接字连接。它在没有协议处理的情况下直接访问套接字事件和数据流。

主要功能包括基于事件的通信、直接字节流访问和细粒度的连接控制。它对于自定义协议很有用。

基本的 RawSocket 客户端

本示例展示了一个基本的 RawSocket 客户端连接到服务器。

main.dart
import 'dart:io';

void main() async {
  try {
    var socket = await RawSocket.connect('example.com', 80);
    print('Connected to ${socket.remoteAddress.address}');
    
    socket.listen((event) {
      if (event == RawSocketEvent.read) {
        var data = socket.read();
        print('Received: ${String.fromCharCodes(data)}');
      }
    });
    
    socket.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'.codeUnits);
  } catch (e) {
    print('Error: $e');
  }
}

我们连接到 example.com 的 80 端口创建一个 TCP 连接。listen 方法处理套接字事件。我们发送一个 HTTP 请求并打印响应。

$ dart main.dart
Connected to 93.184.216.34
Received: HTTP/1.1 200 OK
...

处理多个套接字事件

本示例演示了如何处理不同的套接字事件。

main.dart
import 'dart:io';

void main() async {
  var socket = await RawSocket.connect('localhost', 8080);
  
  socket.listen((event) {
    switch (event) {
      case RawSocketEvent.read:
        var data = socket.read();
        print('Data: ${String.fromCharCodes(data)}');
        break;
      case RawSocketEvent.write:
        print('Ready to write');
        break;
      case RawSocketEvent.closed:
        print('Connection closed');
        break;
      default:
        print('Unknown event: $event');
    }
  });
  
  socket.write('Hello server'.codeUnits);
  await Future.delayed(Duration(seconds: 1));
  socket.close();
}

我们分别处理 read、write 和 closed 事件。switch 语句将不同的套接字事件路由到适当的处理程序进行处理。

$ dart main.dart
Ready to write
Data: Hello client
Connection closed

创建一个简单的回显服务器

本示例展示了一个使用 RawSocket 的基本回显服务器。

server.dart
import 'dart:io';

void main() async {
  var server = await ServerSocket.bind('127.0.0.1', 8080);
  print('Listening on ${server.address.address}:${server.port}');
  
  server.listen((client) {
    client.listen((event) {
      if (event == RawSocketEvent.read) {
        var data = client.read();
        print('Received: ${String.fromCharCodes(data)}');
        client.write(data);
      }
    });
  });
}

服务器绑定到 localhost 的 8080 端口。它将任何接收到的数据回显回去。每个客户端连接都有自己的事件监听器来处理消息。

$ dart server.dart
Listening on 127.0.0.1:8080
Received: Test message

套接字超时处理

本示例演示了如何实现连接超时。

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

void main() async {
  try {
    var socket = await RawSocket.connect('example.com', 80)
      .timeout(Duration(seconds: 3));
    
    socket.listen((event) {
      if (event == RawSocketEvent.read) {
        print('Data received');
      }
    });
    
    print('Connection successful');
  } on TimeoutException {
    print('Connection timed out');
  } on SocketException catch (e) {
    print('Socket error: $e');
  }
}

我们在连接尝试中添加了 3 秒的超时。如果连接未及时建立,timeout 方法将抛出 TimeoutException。

$ dart main.dart
Connection successful

二进制数据传输

本示例展示了如何发送和接收二进制数据。

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

void main() async {
  var socket = await RawSocket.connect('localhost', 9000);
  
  // Send binary data
  var bytes = Uint8List.fromList([0, 1, 2, 3, 255]);
  socket.write(bytes);
  
  socket.listen((event) {
    if (event == RawSocketEvent.read) {
      var response = socket.read();
      print('Received bytes: $response');
    }
  });
  
  await Future.delayed(Duration(seconds: 1));
  socket.close();
}

我们创建一个包含二进制值的 Uint8List 并通过套接字发送它。套接字透明地处理二进制数据,无需任何转换。

$ dart main.dart
Received bytes: [0, 1, 2, 3, 255]

最佳实践

来源

Dart RawSocket 文档

本教程介绍了 Dart 的 RawSocket 类,并通过实际示例展示了基本用法、事件处理、二进制数据和服务器实现。

作者

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

列出 所有 Dart 教程