[英]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.