2017-04-30 9 views
1

私はSwiftでこのUDPクライアントの例を取り上げています。適切なCヘッダーファイルを組み込むためのブリッジヘッダーがあります。この例のプログラムでは、適切なバイト数が送受信されていることがわかります。しかし、コンソールにメッセージを印刷しようとすると何も得られません。Swift BytesでUDPメッセージを読むがメッセージはありません

enter image description here

私はそれは小さなものですが、私は昨日の夜から、このにされていると私はアイデアを実行しています賭けることを喜ん:赤い矢印が表示されたメッセージがあるはずです。助言がありますか?

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

答えて

0

問題は、あなたが呼び出す前に配列を空にするということですrecvfrom

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

recvfromメモリ位置に読み込むが、 スウィフトArrayタイプについて何も知らないし、配列の要素を追加したり、その countを更新しません。

代わりに空でない 配列の要素ストレージへのポインタを渡す必要があります。 UnsafeMutableRawPointer(mutating: buffer)通話中&bufferに を簡略化することができること

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

} 

注:例えば、ソケットから1024バイトの最大値を読み取ります。

+0

私はあなたのステートメントに基づいていくつかの変更を加えました。しかし、バイト数を最小限に保つために必要なremoveAll()呼び出しがあることがわかりました。私は現在作業コードを持っていて、すぐにそれを投稿します... – xBACP

+0

@ PartialFrozenOJ:送信と受信は独立しており、コード内のどこでもremoveAll()を削除する必要はありません。しかし、バイトを受け取るとき、配列には、recvfromにlengthパラメータとして渡す要素の数が含まれていなければなりません。 –

+0

私はあなたを誤解しました。 – xBACP

0

プロセスのこのバージョンは、()関数は動作します:

@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

のremoveAll(keepingCapacity :)呼び出しが必要であるか、私はいくつかのバイトを読み終わるようです。興味深いことに、バッファは1024要素で作成されますが、容量は1504と同じです。

+0

配列に実際にバイトが含まれていない場合、length = BufferLimitのrecvfromを呼び出すと、未定義の動作になります。 –

関連する問題