卡住试图在 OS X 中的套接字上打开写入流

Posted

技术标签:

【中文标题】卡住试图在 OS X 中的套接字上打开写入流【英文标题】:Stuck trying to open write stream on socket in OS X 【发布时间】:2016-01-02 04:10:29 【问题描述】:

在网上看了很多例子之后,我试着写了一个简短的简单程序来测试两台计算机之间的套接字连接。我有这两台电脑

客户端,192.168.0.116,运行下面的程序 服务器,192.168.0.118,在端口 6237 上以服务器侦听模式运行 http://sockettest.sourceforge.net/

我从一个更简单的同步设计开始,但当它不起作用时,我转向了 runloop/async。

症状:CFWriteStreamOpen 返回 true(成功),但流无限期地停留在 kCFStreamStatusOpening 状态。永远不会调用回调来确认打开是否完成(实际上它永远不会为任何事件调用)。

我怀疑我可能有网络问题(防火墙等)可能会阻止此连接。为了反驳这个理论,我也在客户端上运行了http://sockettest.sourceforge.net/,客户端和服务器连接正常。

#include <iostream>
#include <CoreFoundation/CFStream.h>
using namespace std;

CFStreamClientContext myContext = 0,NULL,NULL,NULL,NULL;

#define SA_HOST "192.168.0.118"
//#define SA_HOST "127.0.0.1"
#define SA_PORT 6237
UInt8 buf[5] =  0, 1, 2, 3, 4 ;
UInt8 *wp = buf;
UInt16 bytesQueued = 5;
UInt16 bytesSent = 0;

static const CFOptionFlags kWriteStreamEvents =
kCFStreamEventEndEncountered |
kCFStreamEventErrorOccurred |
kCFStreamEventCanAcceptBytes |
kCFStreamEventOpenCompleted |
kCFStreamEventNone;

void WriteStreamCB(CFWriteStreamRef writeStream, CFStreamEventType event, void *clientCallBackInfo)

    switch (event)
    
        case kCFStreamEventEndEncountered:
        
            cout << "in CallBack: kCFStreamEventEndEncounteredd" << endl;
            CFWriteStreamClose(writeStream);
            break;
        
        case kCFStreamEventErrorOccurred:
        
            cout << "in CallBack: kCFStreamEventErrorOccurred" << endl;
            CFStreamError err = CFWriteStreamGetError(writeStream);
            cout << "in Callback: stream error, domain: " << err.domain << ", value: " << err.error << endl;
            break;
        
        case kCFStreamEventCanAcceptBytes:
        
            cout << "in CallBack: kCFStreamEventCanAcceptBytes" << endl;

            bytesSent = CFWriteStreamWrite(writeStream, buf, 5);
            if (bytesSent > 0)
            
                bytesQueued -= bytesSent;
                wp += bytesSent;
                cout << "CFWriteStreamWrite wrote " << bytesSent << " bytes, " << bytesQueued << " left" << endl;
            
            else
            
                cout << "CFWriteStreamWrite returned " << bytesSent << endl;
            
            break;
        
        case kCFStreamEventNone:
        
            cout << "in CallBack: kCFStreamEventNone" << endl;
            break;
        
        case kCFStreamEventOpenCompleted:
        
            cout << "in CallBack: kCFStreamEventNone" << endl;
            break;
        
    


int main(int argc, const char * argv[]) 
    CFWriteStreamRef   writeStream;
    CFStringRef host = CFSTR(SA_HOST);
    UInt32 port = SA_PORT;

    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, NULL, &writeStream);
    CFWriteStreamSetClient(writeStream, kWriteStreamEvents, WriteStreamCB, &myContext);
    CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

    if (!CFWriteStreamOpen(writeStream))
    
        return -1;
    

    while (true);

    return 0;

【问题讨论】:

也许可以尝试使用与此海报相同的技术创建主机:***.com/questions/7829228/… 具体而言:CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault,(CFStringRef)iHostname); 也许while (true); 是一个太紧的循环。你能把它换成while (1) sleep(10);吗?如果这没有帮助,我会使用straceltrace 仔细查看。 您不允许运行循环运行。看看您是否可以让代码与 RunLoopController 一起使用,我编写该代码是为了更轻松地将使用 runloop 的 API 与控制台程序集成。 CFHost 在我使用的 CoreFoundation.framework 中似乎不可用。此外,CFWriteStreamCreatePairWithSocketToHost 不采用 CFHostRef 而是采用我正在使用的 CoreFoundation.framework 中的“CFStringRef 主机”。我确实鄙视 Objective-C 代码,我真的希望我正在尝试的东西可以用 C++ 实现。我确实看到 CPU 与调试挂钩,所以紧的 while 循环是使 runloop 挨饿的一个问题……但是当我添加 sleep(10) 时,它并没有改变上面的症状。在这种情况下,我需要 RunLoopController 提供的东西吗? ~3 天后我遇到了这个问题,最后发现 CFRunLoopRun() 必须在 CFWriteStreamOpen 之后调用。没有记录在任何地方。为那些稍后搜索并找到它的人干杯。 【参考方案1】:

您不允许运行循环运行。

.

~在我遇到这个问题 3 天后,终于发现 CFRunLoopRun() 必须在 CFWriteStreamOpen 之后调用。没有记录在任何地方。为那些稍后搜索并找到它的人干杯

引用 cmets 以获得可见性。关键是,如果你的 CF 套接字代码挂起,你可能需要运行你的运行循环。

此外,如果您没有使用基于运行循环和回调的 API 使用模式,即使用 CFWriteStreamWrite 进行阻塞 IO 并且没有设置“流客户端”,您也可能会因为错误而被挂起比如超时。

【讨论】:

以上是关于卡住试图在 OS X 中的套接字上打开写入流的主要内容,如果未能解决你的问题,请参考以下文章

将 Spark 流输出写入套接字

通过套接字流发送对象

使用ssh转发unix数据报套接字?

java套接字/输出流写入:它们阻塞吗?

您可以同时写入套接字输入和输出流吗?

NodeJS在写入后无法从telnet套接字接收数据