2017-04-30 3 views
1

Ich arbeite an diesem UDP-Client-Beispiel in Swift. Ich habe einen Bridging-Header, um die entsprechenden C-Header-Dateien zu integrieren. In dem Beispielprogramm kann ich die richtige Anzahl von Bytes sehen, die gesendet und empfangen werden. Aber wenn ich versuche, die Nachricht an die Konsole zu drucken, bekomme ich nichts. Es sollte der rote Pfeil erscheint eine Meldung sein:UDP Messaging in Swift Bytes lesen, aber keine Nachricht

enter image description here

Ich bin bereit, es zu wetten, ist etwas klein, aber ich habe seit gestern Abend auf diese und ich bin mit der Ratlosigkeit gewichen. Irgendwelche Vorschläge?

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-Rubrik:

#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 */ 

Hauptdatei ausprobieren 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) 
    } 
} 

Antwort

0

Das Problem ist, dass Sie das Array leer vor dem Aufruf recvfrom:

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

recvfrom liest in einem Speicherplatz, aber weiß nichts über die Swift Array Typ und wird nicht Array-Elemente oder aktualisieren seine count anhängen.

Sie müssen stattdessen einen Zeiger auf den Elementspeicher eines nicht leeren Arrays übergeben. Zum Beispiel kann ein Maximum von 1024 Bytes von der Buchse zu lesen:

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 ... 

} 

anzumerken, dass UnsafeMutableRawPointer(mutating: buffer) kann zu &buffer im Aufruf vereinfacht werden.

+0

Ich habe einige Änderungen basierend auf Ihren Aussagen vorgenommen. Aber ich finde, dass der Aufruf removeAll() notwendig ist, um die Anzahl der Bytes auf ein Minimum zu beschränken. Ich habe jetzt Arbeitscode und werde es bald veröffentlichen ... – xBACP

+0

@PartialFrozenOJ: Senden und Empfangen sind unabhängig, und ich habe nicht gesagt, dass Sie removeAll() überall in Ihrem Code entfernen sollten. Wenn Sie jedoch Bytes empfangen, muss das Array die Anzahl der Elemente enthalten, die Sie als Längenparameter an recvfrom übergeben. –

+0

ok dann habe ich dich missverstanden. – xBACP

0

Diese Version der Prozess() Funktion funktioniert:

@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 

enter image description here

Sie den removeAll (keepingCapacity :) scheinen Anrufe notwendig sind oder ich am Ende zu wenigen Bytes zu lesen. Interessanterweise wird der Puffer mit 1024 Elementen erstellt, aber die Kapazität ist ungefähr 1504.

+0

Aufruf von recvfrom mit length = BufferLimit, wenn das Array tatsächlich keine Bytes enthält, ist undefiniertes Verhalten. –