0

我有一个结构对象。还有一个方法,它的输入是有效载荷。现在我正在创建一个名为 的 mutableData packet,它的可变字节指的是 ICMPHeader 结构。

struct ICMPHeader {
    var type:UInt8
    var code:UInt8
    var checksum:UInt16
    var identifier:UInt16
    var sequenceNumber:UInt16
};


func createPacket(payload:NSData) -> NSData(){
    var packet:NSMutableData?
    var icmpPtr:ICMPHeader = ICMPHeader(type: 0, code: 0, checksum: 0, identifier: 0, sequenceNumber: 0)
    packet = NSMutableData(length: Int(MemoryLayout<ICMPHeader>.size + payload.length))

    if packet != nil {

       icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee

       icmpPtr.type = type
       icmpPtr.code = 0
       icmpPtr.checksum = 0
       icmpPtr.identifier = CFSwapInt16BigToHost(identifier)
       icmpPtr.sequenceNumber = CFSwapInt16HostToBig(identifier)
       memcpy(&icmpPtr + 1, payload.bytes, payload.length)

       if (requiresChecksum) {
           icmpPtr.checksum = in_cksum(packet!.bytes, bufferLen: packet!.length);
       }

   }
   return packet
}

可变字节已成功绑定到 struct,并且值也在 struct 中更新ICMPHeader

问题是更改 struct 中的值不会更改 mutable data 的值packet

如果,我试图在创建结构后重新创建数据包,那么它就会崩溃。

package = NSMutableData(bytes: unsafeBitCast(icmpPtr, to: UnsafeMutableRawPointer.self), length: Int(MemoryLayout<ICMPHeader>.size + payload.length))
4

1 回答 1

0

我在 XCode 8.1 Swift 发行说明中找到了答案。

在结构对象中进行更改后,icmpPtr我将其更改回缓冲区指针。

var byteBuffer = [UInt8]()
withUnsafeBytes(of: &icmpPtr) {
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes
}
package.replaceBytes(in: NSMakeRange(0, byteBuffer.count), withBytes: byteBuffer)

因此,我没有创建新的 Data 对象,而是替换了字节,它就像一个魅力。

根据文档:

XCode 8.1 发行说明: https ://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html Swift 部分:

新的 withUnsafeBytes(of:) 函数将值在内存中的表示形式公开为 UnsafeRawBufferPointer。此示例将异构结构复制到同构字节数组中:

struct Header {
 var x: Int
 var y: Float
}

var header = Header(x: 0, y: 0.0)
var byteBuffer = [UInt8]()

withUnsafeBytes(of: &header) {
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes
}

新的 Array.withUnsafeBytes 方法将数组的底层缓冲区公开为 UnsafeRawBufferPointer。此示例将整数数组复制到字节数组中:

let intArray = [1, 2, 3]
var byteBuffer = [UInt8]()

intArray.withUnsafeBytes {
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes
}

所以最终的实现是

struct ICMPHeader {
    var type:UInt8
    var code:UInt8
    var checksum:UInt16
    var identifier:UInt16
    var sequenceNumber:UInt16
};


func createPacket(payload:NSData) -> NSData(){
    var packet:NSMutableData?
    var icmpPtr:ICMPHeader = ICMPHeader(type: 0, code: 0, checksum: 0, identifier: 0, sequenceNumber: 0)
    packet = NSMutableData(length: Int(MemoryLayout<ICMPHeader>.size + payload.length))

    if packet != nil {

       icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee

       icmpPtr.type = type
       icmpPtr.code = 0
       icmpPtr.checksum = 0
       icmpPtr.identifier = CFSwapInt16BigToHost(identifier)
       icmpPtr.sequenceNumber = CFSwapInt16HostToBig(identifier)
       memcpy(&icmpPtr + 1, payload.bytes, payload.length)

       if (requiresChecksum) {
           icmpPtr.checksum = in_cksum(packet!.bytes, bufferLen: packet!.length);
       }

       var byteBuffer = [UInt8]()
       withUnsafeBytes(of: &icmpPtr) {
         (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes
       }
       packet.replaceBytes(in: NSMakeRange(0, byteBuffer.count), withBytes: byteBuffer)

   }
   return packet
}
于 2016-11-03T16:59:39.600 回答