在以下服务器/客户端套接字代码中,服务器尝试从0到1023发送整数。客户端收到正确数量的整数但它们换行为255.为什么这是正确的方法?
import 'dart:async';
import 'dart:io';
main() async {
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket) {
print('Got connected ${socket.remoteAddress}');
for(int i=0; i<1024; i++) {
socket.add([i]);
}
socket.close();
print('Closed ${socket.remoteAddress}');
});
}
import 'dart:async';
import 'dart:io';
main() async {
final client = await Socket.connect('127.0.0.1', 4041);
client.listen(
(var data) => print('Got $data'),
onDone: () { print('Done'); client.close(); },
onError: (e) { print('Got error $e'); client.close(); });
print('main done');
}
此外,感觉Socket api有点不同 - 比其他语言更像Dartish支持读取流的方式。但是,如果您只想读取 N 字节呢?你是如何实现这一目标的?我看到采用方法( Stream take(int count))但我不清楚 count 正在采取什么,特别是在术语上已读取的字节数。因为Socket实现了 Stream&lt;列表&lt; int&gt; &gt; 因为int实际上不是一个固定大小的实体(我想??),你怎么知道已经读取了多少字节?
答案 0 :(得分:3)
这对我有用,我不确定这是最优雅的解决方案
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
main() async {
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket) {
print('Got connected ${socket.remoteAddress}');
var toByte = new StreamTransformer<List<int>, Uint8List>.fromHandlers(
handleData: (data, sink) {
sink.add(new Uint64List.fromList(data).buffer.asUint8List());
});
var streamController = new StreamController<List<int>>();
streamController.stream.transform(toByte).pipe(socket);
for (int i = 0; i < 1024; i++) {
streamController.add([i]);
}
streamController.close();
print('Closed ${socket.remoteAddress}');
});
}
import 'dart:io';
import 'dart:async';
main() async {
final Socket client = await Socket.connect('127.0.0.1', 4041);
var fromByte = new StreamTransformer<List<int>, List<int>>.fromHandlers(
handleData: (data, sink) {
sink.add(data.buffer.asInt64List());
});
client.transform(fromByte).listen((e) => e.forEach(print));
print('main done');
}
原始尝试:
import 'dart:io';
import 'dart:typed_data';
main() async {
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket) {
print('Got connected ${socket.remoteAddress}');
for(int i=0; i<1024; i++) {
socket.add(new Uint64List.fromList([i]).buffer.asUint8List());
}
socket.close();
print('Closed ${socket.remoteAddress}');
});
}
import 'dart:io';
import 'dart:typed_data';
main() async {
final Socket client = await Socket.connect('127.0.0.1', 4041);
client.listen(
(var data) {
var ints = new Uint8List.fromList(data).buffer.asInt64List();
ints.forEach((i) => print('Got $i'));
},
onDone: () { print('Done'); client.close(); },
onError: (e) { print('Got error $e'); client.close(); });
print('main done');
}
如果您不需要Int64的范围,您也可以使用Int32,Int16或某些UIntXX类型或最适合您的值范围,以节省一些冗余传输的0字节。
我怀疑使用像https://www.dartlang.org/articles/converters-and-codecs/这样解释的转换器可以更优雅地使用它。这似乎相似https://gist.github.com/xxgreg/9104926但我不得不承认我无法将这些示例应用于您的用例。
<强>更新强>
我的工作方式如上面链接的文章中所示
import 'dart:convert';
import 'dart:typed_data';
class IntConverter extends Converter<List<int>, List<int>> {
const IntConverter();
List<int> convert(List<int> data) {
if (data is Uint8List) {
return data.buffer.asInt64List();
} else {
return new Uint64List.fromList(data).buffer.asUint8List();
}
}
IntSink startChunkedConversion(sink) {
return new IntSink(sink);
}
}
class IntSink extends ChunkedConversionSink<List<int>> {
final _converter;
// fales when this type is used
// final ChunkedConversionSink<List<int>> _outSink;
final _outSink;
IntSink(this._outSink) : _converter = new IntConverter();
void add(List<int> data) {
_outSink.add(_converter.convert(data));
}
void close() {
_outSink.close();
}
}
import 'dart:io';
import 'dart:typed_data';
main() async {
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket) {
print('Got connected ${socket.remoteAddress}');
for (int i = 0; i < 1024; i++) {
socket.add(new Uint64List.fromList([i]).buffer.asUint8List());
}
socket.close();
print('Closed ${socket.remoteAddress}');
});
}
import 'dart:io';
import 'byte_converter.dart';
main() async {
final Socket client = await Socket.connect('127.0.0.1', 4041);
client.transform(new IntConverter()).listen((e) => e.forEach(print));
print('main done');
}
答案 1 :(得分:3)
要明确的一点是,尽管dart:io
中的大多数方法都在List<int>
上运行,但Dart中所有IO的基础假设是这些列表是字节列表值。文档可能不那么准确。
这意味着您可以在发送字节时使用您喜欢的任何List
实现 - 包括类型化数据,例如
var socket = ...
socket.add([1, 2, 3]);
socket.add(new List<int>.generate(3, (int index) => index * index);
socket.add('ASCII'.codeUnits);
socket.add(UTF8.encode('Søren'));
var typedData = new Uint8List(8);
var data = new ByteData.view(typedData.buffer);
data.setInt32(0, 256 * 256 - 1);
data.setInt32(4, 256 * 256 - 1, Endianness.LITTLE_ENDIAN);
socket.add(typedData)
从套接字接收数据时,Socket
流上传递的数据是从OS传送的字节块。您不能预测当时接收的字节数。如果您希望能够读取特定数量的字节,一个选项是实现一个字节读取器,它具有如下方法:
Future<List<int>> read(int numBytes);
然后可以使用List<int>
流初始化此字节阅读器并处理框架。你可以做的是有一个缓冲区(可能使用dart:io
中的BytesBuilder
)收集收到的数据。调用read
时,Future
在有足够的字节可用时完成。这样的字节读取器也可以在缓冲数据量达到一定限度时暂停流,并在读取数据时再次恢复。