[英]UDP Messaging in Swift Bytes Read But No Message
我正在研究Swift中的這個UDP客戶端示例。 我有一個橋接頭來合並適當的C頭文件。 在示例程序中,我可以看到正在發送和接收的正確字節數。 但是,當我嘗試將消息打印到控制台時,我什么也得不到。 應該會出現紅色箭頭出現的消息:
我願意打賭這是小事,但我從昨天晚上就開始這樣做了,我的想法已經不多了。 有什么建議么?
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橋接標頭:
#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 */
試用客戶端的主文件:
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)
}
}
問題是你在調用recvfrom
之前清空了數組:
buffer.removeAll(keepingCapacity: true)
// ...
recvfrom(mySocket, UnsafeMutableRawPointer(mutating: buffer), 1024, 0, UnsafeMutablePointer<sockaddr>($0), &slen)
recvfrom
讀入內存位置,但對Swift Array
類型一無所知,也不會附加數組元素或更新其count
。
您必須將指針傳遞給非空數組的元素存儲。 例如,要從套接字讀取最多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 ...
}
請注意, UnsafeMutableRawPointer(mutating: buffer)
可以簡化為調用中的&buffer
。
此版本的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
似乎removeAll(keepsCapacity :)調用是必要的,或者我最終讀取到幾個字節。 有趣的是,緩沖區是使用1024個元素創建的,但容量類似於1504。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.