为什么后台监听的 DataCallBack 方法没有被调用?
我一直在与 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() 方法让此回调在后台侦听。
现在,这就是我的发送方法,
- (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 字节数组就是命令)并等待服务器响应,然后再发送下一个命令,为此我使用 while,变量“receivedLastAnswer”是调用我的 DataCallBack 方法时设置的标志,因此如果服务器响应,则调用回调,它将标志设置为 true,从而 while 退出并发送下一个命令。
当然这不是我打算留下代码的方式,这只是为了测试并看看它是否有效,因为稍后我将不得不在 while 中添加另一个条件,一个超时条件,以防服务器没有响应根本不。
现在,我的问题是我的应用程序(客户端)没有触发回调方法,因此它只是无限循环;我认为不触发回调的原因是因为应用程序在 while 循环中很忙,事实上,如果我删除循环,回调就会被触发,但这对我来说没有意义,因为回调方法不是应该的在不同的线程上运行(这不是 CFRunLoopRun() 的目的吗?)并且因为它在不同的线程中运行,所以主线程处于循环中并不重要,或者我完全误解了它是如何工作的?
另外,我尝试不使用 while 循环,而是使用 Sleep() 函数,但它是相同的,不会触发回调。
您知道为什么会发生这种情况或者我该如何实现这一点,
谢谢。
I've been working with CFNetwork to create a client application for iPad, it is a small application, nothing fancy.
This is how I create the connection to the server (running in 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();
}
As you can see, when I create the server socket I register a callback to listen to incoming data from the server.
Then I use the CFRunLoopAddSource(...) and CFRunLoopRun() methods to have this callback listen in the background.
Now, this is how it looks my send method
- (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
}
}
}
What I want to do is send a command to the server (the 3 bytes array you see is the command) and wait for the server to respond before sending the next command, to do this I use a while, the variable "receivedLastAnswer" is a flag that is set when my DataCallBack method is invoked, so if the server responds, the callback is invoked, it sets the flag to true and thus the while exits and the next command is send.
Of course this is not how I intend to leave the code, this is just for testing and to see if it works, cause later I will have to add another condition to the while, a timeout condition, in case the server doesn't respond at all.
Now, my problem is that my application, the client, is not firing the callback method, and thus it just cycles infinitely; I think the reason for not firing the callback is because the application is busy in the while cycle, in fact if I remove the cycle, the callback is fired, but this doesn't makes sense to me because isn't the callback method supposed to be running on a different thread (isn't that the purpose of CFRunLoopRun()?) and because it is running in a different thread it shouldn't matter that the main thread be in a cycle or am I completely misunderstanding how this works?
Also, I tried not using a while cycle, but a Sleep() function, but it is the same, no callback is fired.
Do you have any idea why this may be happening or how can I accomplish this,
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,我认为,如果主线程繁忙或阻塞,实际上我的数据回调不会被调用,所以我所做的是将回调方法留在主线程上,并将我的发送方法放在另一个线程中,它实际上工作得很好,然而,我仍在徘徊是否还有其他方法,但目前它满足了我的需要,所以我将坚持下去。
Well I think that in deed my data Callback wont be called if the main thread is busy or blocked, so what I did was to leave the Callback method on the main thread and put my send method in another thread, it worked pretty well actually, however I'm still wandering if there would be another way, but for now it does what I need so I'm going to stick to it.