gpt4 book ai didi

ios - 为什么我没有得到服务器中图像的所有字节?

转载 作者:可可西里 更新时间:2023-11-01 02:50:09 24 4
gpt4 key购买 nike

我正在构建一个 iOS 应用程序,它可以拍摄照片并将其发送到在我的计算机上运行的 TCP 服务器。我这样做的方式是像这样配置与 Streams 的连接:

func setupCommunication() {
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
"192.168.1.40" as CFString, 2323, &readStream, &writeStream)

outputStream = writeStream!.takeRetainedValue()
outputStream.schedule(in: .current, forMode: .common)
outputStream.open()
}

然后,当我按下相机按钮时,照片被拍摄并通过 outputStream 发送。由于 TCP 服务器不知道它要读取多少数据,因此前 8 个字节对应于图像的大小,图像紧随其后发送,正如我们在这段代码中看到的:

func photoOutput(_ output: AVCapturePhotoOutput,
didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {

if let image = photo.fileDataRepresentation() {
print(image)
print(image.count)

var nBytes = UInt64(image.count)
let nData = Data(bytes: &nBytes, count: 8)
_ = nData.withUnsafeBytes({
outputStream.write($0, maxLength: nData.count)
})

_ = image.withUnsafeBytes({
outputStream.write($0, maxLength: image.count)
})

outputStream.close()
}
}

在用 C 编写的服务器端,我执行以下操作:

读取前 8 个字节以了解图像的大小

printf("\n[*] New client connected\n");

while (n_recv < sizeof(uint64_t)) {
if ((n = read(client_sd, buffer, BUF_SIZ)) == -1) {
printf("\n[-] Error reading data from the client\n");
close(client_sd);
close(server_sd);
return 0;
}

n_recv += n;
}

memcpy(&img_size, buffer, sizeof(uint64_t));

printf("\n[+] Client says he's going to send %llu bytes\n", img_size);

分配足够的内存来存储接收到的图像,如果我们已经读取了图像大小旁边的任何字节,则复制它。

if ((img_data = (uint8_t *) malloc(img_size)) == NULL) {
printf("\n[-] Error allocating memory for image\n");
close(client_sd);
close(server_sd);
return 0;
}

n_recv -= sizeof(uint64_t);
if (n_recv > 0) {
memcpy(img_data, buffer, n_recv);
}

从现在开始,n_recv 只是图像接收到的字节数,不包括大小的前 8 个字节。然后一直读到最后。

while (n_recv < img_size) {
if ((n = read(client_sd, buffer, BUF_SIZ)) == -1) {
printf("\n[-] Error reading data from the client\n");
close(client_sd);
close(server_sd);
return 0;
}

memcpy(img_data + n_recv, buffer, n);
n_recv += n;
}

printf("\n[+] Data correctly recived from client\n");

close(client_sd);
close(server_sd);

这在开始时工作得很好。事实上,我可以看到我每次都得到了正确的图像大小数字:

enter image description here

但是,我没有得到完整的图像,服务器只是在读取函数中等待阻塞。为了看看发生了什么,我添加了这个

printf("%llu\n", n_recv);

在读取图像的循环内,观察接收到的字节数。它停在图像中间,出于某种原因我无法解释:

enter image description here

导致通信停止的问题是什么?是服务器代码中的问题还是与 iOS 应用程序相关的问题?

最佳答案

首先,C 代码在我看来没问题..但你意识到你缺少 Swift 中的返回代码/结果处理?

在 C 代码中,您正在检查 recv 的返回值以了解字节是否已读取。 IE:您正在检查 read 是否返回 -1..

但是,在 swift 代码中,您假设所有数据都已写入。您从未检查过 OutputStream 上的 write 操作的结果,它告诉您如何写入了很多字节或失败时返回 -1..

你应该做同样的事情(毕竟,你是用 C 做的)。对于这种情况,我创建了两个扩展:

extension InputStream {
/**
* Reads from the stream into a data buffer.
* Returns the count of the amount of bytes read from the stream.
* Returns -1 if reading fails or an error has occurred on the stream.
**/
func read(data: inout Data) -> Int {
let bufferSize = 1024
var totalBytesRead = 0

while true {
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
let count = read(buffer, maxLength: bufferSize)
if count == 0 {
return totalBytesRead
}

if count == -1 {
if let streamError = self.streamError {
debugPrint("Stream Error: \(String(describing: streamError))")
}
return -1
}

data.append(buffer, count: count)
totalBytesRead += count
}
return totalBytesRead
}
}

extension OutputStream {
/**
* Writes from a buffer into the stream.
* Returns the count of the amount of bytes written to the stream.
* Returns -1 if writing fails or an error has occurred on the stream.
**/
func write(data: Data) -> Int {
var bytesRemaining = data.count
var bytesWritten = 0

while bytesRemaining > 0 {
let count = data.withUnsafeBytes {
self.write($0.advanced(by: bytesWritten), maxLength: bytesRemaining)
}

if count == 0 {
return bytesWritten
}

if count < 0 {
if let streamError = self.streamError {
debugPrint("Stream Error: \(String(describing: streamError))")
}
return -1
}

bytesRemaining -= count
bytesWritten += count
}

return bytesWritten
}
}

用法:

var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?

//For testing I used 127.0.0.1
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, "192.168.1.40" as CFString, 2323, &readStream, &writeStream)


//Actually not sure if these need to be retained or unretained might be fine..
//Again, not sure..
var inputStream = readStream!.takeRetainedValue() as InputStream
var outputStream = writeStream!.takeRetainedValue() as OutputStream

inputStream.schedule(in: .current, forMode: .common)
outputStream.schedule(in: .current, forMode: .common)

inputStream.open()
outputStream.open()


var dataToWrite = Data() //Your Image
var dataRead = Data(capacity: 256) //Server response -- Pre-Allocate something large enough that you "think" you might read..

outputStream.write(data: dataToWrite)
inputStream.read(data: &dataRead)

现在你得到了错误处理(打印)并且你已经缓冲了读/写..毕竟,你不能保证套接字或管道或w/e..流附加到已经读/写了你所有的一次字节..因此读取/写入 block 。

关于ios - 为什么我没有得到服务器中图像的所有字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53270893/

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