0

私は CFNetwork と協力して iPad 用のクライアント アプリケーションを作成しました。これは小さなアプリケーションであり、派手なものではありません。

これは、サーバーへの接続を作成する方法です(Windowsで実行)。

- (void) startConnection
{
    char ip[] = "192.168.0.244";
    NSString *ipAddress = [[NSString alloc] initWithCString:ip];

    /* Build our socket context; this ties an instance of self to the socket */
    CFSocketContext CTX = { 0, self, NULL, NULL, NULL };

    /* Create the server socket as a TCP IPv4 socket and set a callback */
    /* for calls to the socket's lower-level connect() function */  
    TCPClient = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP,
                               kCFSocketDataCallBack, (CFSocketCallBack)DataCallBack, &CTX);

    if (TCPClient == NULL)
        return;

    /* Set the port and address we want to listen on */
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);// PORT = 5001
    addr.sin_addr.s_addr = inet_addr([ipAddress UTF8String]);

    CFDataRef connectAddr = CFDataCreate(NULL, (unsigned char *)&addr, sizeof(addr));
    CFSocketConnectToAddress(TCPClient, connectAddr, -1);
    CFRunLoopSourceRef sourceRef =
    CFSocketCreateRunLoopSource(kCFAllocatorDefault, TCPClient, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
    CFRelease(sourceRef);
    CFRunLoopRun();
} 

ご覧のとおり、サーバー ソケットを作成するときに、サーバーからの着信データをリッスンするコールバックを登録します。

次に、CFRunLoopAddSource(...) および CFRunLoopRun() メソッドを使用して、このコールバックをバックグラウンドでリッスンします。

さて、これが私の send メソッドの外観です

- (void) send
{
    if (TCPClient == NULL)
        return;

    Byte byteData[3];   
    for (int i = 1; i <= 25; i++) {
        receivedLastAnswer = NO;
        globalPos = i;
        byteData[0] = i;
        byteData[1] = 4;
        byteData[2] = 0;
        int len = 3;//strlen(byte)+1;               
        CFDataRef refData = CFDataCreate(kCFAllocatorDefault, byteData, len);
        CFSocketSendData(TCPClient, NULL, refData, 0);
        while (!receivedLastAnswer) {
            //this while is to wait until a response is send by the server
         }
    }
}

私がやりたいことは、サーバーにコマンドを送信し (表示される 3 バイトの配列がコマンドです)、次のコマンドを送信する前にサーバーが応答するのを待つことです。これを行うには、しばらく使用します。変数「receivedLastAnswer」は私の DataCallBack メソッドが呼び出されたときに設定されるフラグ。サーバーが応答すると、コールバックが呼び出され、フラグが true に設定されるため、while が終了し、次のコマンドが送信されます。

もちろん、これは私がコードを残すつもりの方法ではありません。これはテスト用であり、それが機能するかどうかを確認するためのものです。後で、サーバーが応答しない場合に備えて、タイムアウト条件という別の条件を while に追加する必要があります。まったく。

さて、私の問題は、私のアプリケーションであるクライアントがコールバック メソッドを起動していないため、無限に循環することです。コールバックを発生させない理由は、while サイクルでアプリケーションがビジーであるためだと思います。実際、サイクルを削除すると、コールバックが発生しますが、コールバック メソッドが想定されていないため、これは意味がありません。別のスレッドで実行されていること (それが CFRunLoopRun() の目的ではありませんか?) であり、別のスレッドで実行されているため、メイン スレッドがサイクル内にあるかどうかは問題ではありません。または、これがどのように機能するかを完全に誤解しています。 ?

また、while サイクルではなく Sleep() 関数を使用してみましたが、同じで、コールバックは発生しません。

なぜこれが起こっているのか、どうすればこれを達成できるのか分かりますか?

ありがとう。

4

1 に答える 1

0

実際、メイン スレッドがビジー状態またはブロックされている場合、データ コールバックは呼び出されないと思います。そのため、Callback メソッドをメイン スレッドに残し、send メソッドを別のスレッドに配置することで、実際にはかなりうまく機能しました。ただし、別の方法があるかどうかはまだ迷っていますが、今のところ、必要なことを行っているので、それに固執します。

于 2010-06-18T21:57:34.240 に答える