简体   繁体   English

快速字节中的UDP消息传递读取但没有消息

[英]UDP Messaging in Swift Bytes Read But No Message

I am working on this UDP client example in Swift. 我正在研究Swift中的这个UDP客户端示例。 I have a bridging header to incorporate the appropriate C-header files. 我有一个桥接头来合并适当的C头文件。 In the example program, I can see the proper number of bytes are being send and received. 在示例程序中,我可以看到正在发送和接收的正确字节数。 But, when I try to print the message to the console I get nothing. 但是,当我尝试将消息打印到控制台时,我什么也得不到。 There should be a message the red arrow appears: 应该会出现红色箭头出现的消息:

在此输入图像描述

I am willing to bet it is something small, but I have been on this since yesterday night and I am running out of ideas. 我愿意打赌这是小事,但我从昨天晚上就开始这样做了,我的想法已经不多了。 Any suggestions? 有什么建议么?

UDPClient: UDPClient:

import Foundation

enum UDPClientError: Int, LocalizedError {

case noSocket = -999
case bindSocket
case badAddress
case alreadyInProgress
case setupForNonBlocking
case threadLock

var localizedDescription: String {

    switch self {

    case .alreadyInProgress:
        return "operation in progress"
    case .badAddress:
        return "Address string given is not valid"
    case .bindSocket:
        return "Could not bind socket"
    case .noSocket:
        return "Could not obtain socket"
    case .setupForNonBlocking:
        return "Could not setup socket for non-blocking operation"
    case .threadLock:
        return "Could not obtain thread lock"
    }

}
}

class UDPClient {

private var mySocket: Int32 = 0

private var myAddress = sockaddr_in()

private var otherAddress = sockaddr_in()

let name: String

private var receiveQueue = [String]()

private var sendQueue = [String]()

private var okToRun = false

private var threadLock = pthread_mutex_t()

init(name: String, port: UInt16, otherIPAddress: String, otherPort: UInt16) throws {

    self.name = name

    mySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)

    if mySocket == -1 {

        throw UDPClientError.noSocket
    }

    if fcntl(mySocket, F_SETFL, O_NONBLOCK) == -1 {

        throw UDPClientError.setupForNonBlocking
    }

    myAddress.sin_family = sa_family_t(AF_INET)
    myAddress.sin_port = in_port_t(port)
    myAddress.sin_addr.s_addr = in_addr_t(INADDR_ANY)

    let retCode = withUnsafeMutablePointer(to: &myAddress) {

        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

            bind(mySocket, UnsafeMutablePointer<sockaddr>($0), socklen_t(MemoryLayout<sockaddr_in>.size))
        }
    }

    if retCode == -1 {

        throw UDPClientError.bindSocket
    }

    otherAddress.sin_family = sa_family_t(AF_INET)
    otherAddress.sin_port = in_port_t(otherPort)

    var buffer: [Int8] = Array(otherIPAddress.utf8CString)

    if inet_aton(&buffer, &otherAddress.sin_addr) == 0 {

        throw UDPClientError.badAddress
    }

    if pthread_mutex_init(&threadLock, nil) != 0 {

        throw UDPClientError.threadLock
    }

    print("done")
}


func beginOperation() {

    okToRun = true
    _ = Thread.detachNewThreadSelector(#selector(process), toTarget: self, with: nil)
    //processThread.start()

}

func endOperation() {

    okToRun = false
}

func send(message: String) {

    pthread_mutex_lock(&threadLock)

    sendQueue.append(message)

    pthread_mutex_unlock(&threadLock)

}

func getMessage() -> String? {

    pthread_mutex_lock(&threadLock)

    let flag = receiveQueue.isEmpty

    pthread_mutex_unlock(&threadLock)

    if flag {
        print("no message")
        return nil
    }

    pthread_mutex_lock(&threadLock)

    let message = receiveQueue.remove(at: 0)

    pthread_mutex_unlock(&threadLock)

    return message
}

@objc private func process() {

    //let bufferLimit = 1024
    var buffer = [UInt8](repeating: 0, count: 1024)
    buffer.removeAll(keepingCapacity: true)

    var slen = socklen_t(MemoryLayout<sockaddr_in>.size)

    print("Process running for " + name)

    var bytesRead = 0
    var bytesSent = 0

    while okToRun {

        if sendQueue.isEmpty == false {

            buffer.removeAll(keepingCapacity: true)

            pthread_mutex_lock(&threadLock)

            buffer.append(contentsOf: sendQueue.remove(at: 0).utf8)

            pthread_mutex_unlock(&threadLock)

            bytesSent = withUnsafeMutablePointer(to: &otherAddress) {

                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

                    sendto(mySocket, buffer, buffer.count, 0, UnsafePointer<sockaddr>($0), socklen_t(MemoryLayout<sockaddr_in>.size))
                }
            }

            if bytesSent != -1 {

                print("First buffer character: \(buffer[0])")
                print("\(name): sendto() bytes sent: \(bytesSent)")
            }

            buffer.removeAll(keepingCapacity: true)
        }

        bytesRead = withUnsafeMutablePointer(to: &otherAddress) {

            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

                recvfrom(mySocket, UnsafeMutableRawPointer(mutating: buffer), 1024, 0, UnsafeMutablePointer<sockaddr>($0), &slen)
            }
        }

        if bytesRead != -1 {

            print("\(name): Bytes read = \(bytesRead) bytes: \(buffer)")

            pthread_mutex_lock(&threadLock)

            receiveQueue.append(String(bytes: buffer, encoding: .utf8)!)

            pthread_mutex_unlock(&threadLock)

            slen = socklen_t(MemoryLayout<sockaddr_in>.size)
        }

        bytesRead = 0
        bytesSent = 0

    } // end processing loop

} // end process

}

UDP-Bridging-Header: UDP桥接标头:

#ifndef UDP_Bridging_Header_h
#define UDP_Bridging_Header_h

#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <pthread.h>

#endif /* UDP_Bridging_Header_h */

Main file to try out client: 试用客户端的主文件:

import Foundation

var client_1: UDPClient?
var client_2: UDPClient?


do {

    try client_1 = UDPClient(name: "Client A", port: 9990, otherIPAddress: "192.168.2.4", otherPort: 9992)
}
catch {

    print(error.localizedDescription)
}

do {

    try client_2 = UDPClient(name: "Client B", port: 9992, otherIPAddress: "192.168.2.4", otherPort: 9990)
}
catch {

    print(error.localizedDescription)
}

if client_1 != nil && client_2 != nil {

    client_1!.send(message: "Try this out")

    client_1!.beginOperation()
    client_2!.beginOperation()

    Thread.sleep(forTimeInterval: 5.0)

    if let msg = client_2!.getMessage() {

        print(msg)
    }
}

The problem is that you empty the array before calling recvfrom : 问题是你在调用recvfrom之前清空了数组:

buffer.removeAll(keepingCapacity: true)
// ...
recvfrom(mySocket, UnsafeMutableRawPointer(mutating: buffer), 1024, 0, UnsafeMutablePointer<sockaddr>($0), &slen)

recvfrom reads into a memory location, but knows nothing about the Swift Array type and will not append array elements or update its count . recvfrom读入内存位置,但对Swift Array类型一无所知,也不会附加数组元素或更新其count

You have to pass a pointer to the element storage of a non-empty array instead. 您必须将指针传递给非空数组的元素存储。 For example, to read a maximum of 1024 bytes from the socket: 例如,要从套接字读取最多1024个字节:

buffer = [UInt8](repeating: 0, count: 1024)
bytesRead = withUnsafeMutablePointer(to: &otherAddress) {
    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        recvfrom(mySocket, &buffer, buffer.count, 0, $0, &slen)
    }
}
if bytesRead != -1 {
    buffer.removeSubrange(bytesRead ..< buffer.count)
    // process buffer ...

}

Note that UnsafeMutableRawPointer(mutating: buffer) can be simplified to &buffer in the call. 请注意, UnsafeMutableRawPointer(mutating: buffer)可以简化为调用中的&buffer

This version of the process() function works: 此版本的process()函数有效:

@objc private func process() {

    //let bufferLimit = 1024
    var buffer = [UInt8](repeating: 0, count: BufferLimit)

    var slen = socklen_t(MemoryLayout<sockaddr_in>.size)

    print("Process running for " + name)

    var bytesRead = 0
    var bytesSent = 0

    while okToRun {

        if sendQueue.isEmpty == false {

            buffer.removeAll(keepingCapacity: true)

            pthread_mutex_lock(&threadLock)

            buffer.append(contentsOf: sendQueue.remove(at: 0).utf8)

            pthread_mutex_unlock(&threadLock)

            bytesSent = withUnsafeMutablePointer(to: &otherAddress) {

                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

                    sendto(mySocket, buffer, buffer.count, 0, $0, slen)
                }
            }

            if bytesSent != -1 {

                print("\(name): bytes sent = \(bytesSent)")
            }

            buffer.removeAll(keepingCapacity: true)
        }

        bytesRead = withUnsafeMutablePointer(to: &otherAddress) {

            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {

                recvfrom(mySocket, &buffer, BufferLimit, 0, $0, &slen)
            }
        }

        if bytesRead != -1 {

            print("\(name): bytes read = \(bytesRead)")

            pthread_mutex_lock(&threadLock)

            receiveQueue.append(String(bytes: buffer, encoding: .utf8)!)

            pthread_mutex_unlock(&threadLock)

            slen = socklen_t(MemoryLayout<sockaddr_in>.size)

            buffer.removeAll(keepingCapacity: true)
        }

        bytesRead = 0
        bytesSent = 0

    } // end processing loop

} // end process

在此输入图像描述

It seems the removeAll(keepingCapacity:) calls are necessary or I end up reading to few bytes. 似乎removeAll(keepsCapacity :)调用是必要的,或者我最终读取到几个字节。 Interestingly, the buffer is created with 1024 elements but the capacity is something like 1504. 有趣的是,缓冲区是使用1024个元素创建的,但容量类似于1504。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM