gpt4 book ai didi

ios - 从 InputStream 读取 UInt32

转载 作者:搜寻专家 更新时间:2023-11-01 07:05:29 24 4
gpt4 key购买 nike

我需要与具有特殊消息格式的服务器进行通信:每条消息都以 4 个字节(一起是 unsigned long/大端格式的 UInt32)开始,这决定了后续消息的长度。在这 4 个字节之后,消息作为普通字符串发送

所以我首先需要将 4 个字节读入一个整数(32 位无符号)。在 Java 中,我这样做是这样的:

DataInputStream is;
...
int len = is.readInt();

我如何在 Swift 4 中执行此操作?

目前我在用

var lengthbuffer = [UInt8](repeating: 0, count: 4)
let bytecount = istr.read(&lengthbuffer, maxLength: 4)
let lengthbytes = lengthbuffer[0...3]
let bigEndianValue = lengthbytes.withUnsafeBufferPointer {
($0.baseAddress!.withMemoryRebound(to: UInt32.self, capacity: 1) { $0 })
}.pointee
let bytes_expected = Int(UInt32(bigEndian: bigEndianValue))

但这看起来不是最优雅的方式。此外,有时(我无法可靠地复制它)读取错误的值(太大)。当我随后尝试为以下消息分配内存时,应用程序崩溃了:

let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bytes_expected)
let bytes_read = istr.read(buffer, maxLength: bytes_expected)

那么从 InputStream 读取 UInt32 的快速方法是什么?


编辑:

我当前的代码(根据评论实现。谢谢!)如下所示:

private let inputStreamAccessQueue  = DispatchQueue(label: "SynchronizedInputStreamAccess")  // NOT concurrent!!!

// This is called on Stream.Event.hasBytesAvailable
func handleInput() {
self.inputStreamAccessQueue.sync(flags: .barrier) {
guard let istr = self.inputStream, istr.hasBytesAvailable else {
log.error(self.buildLogMessage("handleInput() called when inputstream has no bytes available"))
return
}

let lengthbuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 4)
defer { lengthbuffer.deallocate(capacity: 4) }
let lenbytes_read = istr.read(lengthbuffer, maxLength: 4)

guard lenbytes_read == 4 else {
self.errorHandler(NetworkingError.InputError("Input Stream received \(lenbytes_read) (!=4) bytes"))
return
}

let bytes_expected = Int(UnsafeRawPointer(lengthbuffer).load(as: UInt32.self).bigEndian)
log.info(self.buildLogMessage("expect \(bytes_expected) bytes"))

let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bytes_expected)
let bytes_read = istr.read(buffer, maxLength: bytes_expected)
guard bytes_read == bytes_expected else {
print("Error: Expected \(bytes_expected) bytes, read \(bytes_read)")
return
}

guard let message = String(bytesNoCopy: buffer, length: bytes_expected, encoding: .utf8, freeWhenDone: true) else {
log.error("ERROR WHEN READING")
return
}

self.handleMessage(message)
}
}

这在大多数情况下都有效,但有时 istr.read() 不会读取 bytes_expected 字节,而是 bytes_read < bytes_expected。这会导致另一个 hasbytesAvailable 事件并再次调用 handleInput()。当然,这次读取的前 4 个字节不包含新消息的长度,而是上一条消息的一些内容。但是我的代码不知道,所以第一个字节被解释为长度。在许多情况下,这是一个真正的大值(value) => 分配太多内存 => 崩溃

我认为这是对错误的解释。但是如何解决呢?在 hasBytesAvailable = true 时在流上调用 read()?是否有更好的解决方案?

我会假设当我循环时,hasBytesAvailableEvent 仍然会在每次 read() 之后发生 => handleInput 仍然会过早再次调用......我怎样才能避免这种情况?


编辑 2:我现在已经实现了循环,不幸的是它仍然因同样的错误而崩溃(可能是同样的原因)。相关代码:

let bytes_expected = Int(UnsafeRawPointer(lengthbuffer).load(as: UInt32.self).bigEndian)

var message = ""
var bytes_missing = bytes_expected
while bytes_missing > 0 {
print("missing", bytes_missing)
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bytes_missing)
let bytes_read = istr.read(buffer, maxLength: bytes_missing)

guard bytes_read > 0 else {
print("bytes_read not <= 0: \(bytes_read)")
return
}

guard bytes_read <= bytes_missing else {
print("Read more bytes than expected. missing=\(bytes_missing), read=\(bytes_read)")
return
}

guard let partial_message = String(bytesNoCopy: buffer, length: bytes_expected, encoding: .utf8, freeWhenDone: true) else {
log.error("ERROR WHEN READING")
return
}

message = message + partial_message
bytes_missing -= bytes_read
}

崩溃时我的控制台输出:

missing 1952807028 malloc: * mach_vm_map(size=1952808960) failed (error code=3) * error: can't allocate region *** set a breakpoint in malloc_error_break to debug

所以看起来整个 handleInput() 方法被调用得太早了,虽然我使用了屏障!我做错了什么?

最佳答案

我会这样做(准备粘贴到 Playground 上):

import Foundation

var stream = InputStream(data: Data([0,1,0,0]))
stream.open()
defer { stream.close() }

var buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 4)
defer { buffer.deallocate(capacity: 4) }
guard stream.read(buffer, maxLength: 4) >= 4 else {
// handle all cases: end of stream, error, waiting for more data to arrive...
fatalError()
}
let number = UnsafeRawPointer(buffer).load(as: UInt32.self)
number // 256
number.littleEndian // 256
number.bigEndian // 65536

直接使用 UnsafeRawPointer.load(无需显式重新绑定(bind))对于普通类型是安全的 according to the documentation .普通类型通常是那些不需要 ARC 操作的类型。

Alternatively, you can access the same memory as a different type without rebinding through untyped memory access, so long as the bound type and the destination type are trivial types.

关于ios - 从 InputStream 读取 UInt32,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48309099/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com