【发布时间】:2018-06-28 16:08:41
【问题描述】:
我有一个服务器通过 TCP 向我发送消息,其中前 4 个字节确定消息其余部分的长度。所以我需要
1) 将 4 个字节读入 UInt32(有效)并将其存储到 bytes_expected
2) 将 bytes_expected 个字节读入 message
现在我的代码如下所示:
private let inputStreamAccessQueue = DispatchQueue(label: "SynchronizedInputStreamAccess")
func inputStreamHandler(_ event: Stream.Event) {
switch event {
case Stream.Event.hasBytesAvailable:
self.handleInput()
...
}
}
func handleInput() {
// **QUESTION: Do I use this barrier wrong?**
self.inputStreamAccessQueue.sync(flags: .barrier) {
guard let istr = self.inputStream else {
log.error(self.buildLogMessage("InputStream is nil"))
return
}
guard 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"))
print("::DEBUG", call, "bytes_expected", bytes_expected)
var message = ""
var bytes_missing = bytes_expected
while bytes_missing > 0 {
//print("::DEBUG", call, "bytes_missing", bytes_missing)
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bytes_missing)
let bytes_read = istr.read(buffer, maxLength: bytes_missing)
print("::DEBUG", call, "bytes_read", bytes_read)
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_read, encoding: .utf8, freeWhenDone: true) else {
log.error("ERROR WHEN READING")
return
}
message = message + partial_message
bytes_missing -= bytes_read
}
self.handleMessage(message)
}
}
我的问题是 istr.read(buffer, maxLength: bytes_missing) 有时不会一次读取所有消息,所以我循环直到我读完我想要的所有消息。但是我仍然看到我的应用程序崩溃(很少),因为再次调用了 handleInput() 而对该方法的另一个调用仍在运行。在这种情况下,bytes_expected 包含随机值,应用程序由于非法内存分配而崩溃。
我想我可以通过使用屏障来避免这种情况。但这似乎不起作用……我是不是用错了屏障?
【问题讨论】:
-
是的,但是 cmets 中的一个人告诉我要提出一个新问题。最后一个问题我不小心使用了一个旧帐户。我删除了旧帐户,将来会使用这个帐户
-
是的,这里有一个新问题是正确的,我只是想知道不同的用户名。
-
我没有时间写一个完整的答案,但我的建议是不要对抗网络IO的异步性质,并且不要 使用屏障。 – 在
handleInput()中,只需在缓冲区中收集可用数据。如果缓冲区包含足够的数据(4 个字节用于计数器 + 预期字节数),则对其进行处理并将其从缓冲区中删除。否则什么都不做,等待更多数据。 -
我没有使用该库的经验,也没有建议,抱歉。
标签: ios swift tcp network-programming inputstream