POSIX套接字:如何在Telnet中检测Ctrl-C信号?

5

简短问题
如何在服务器端处理通过Telnet发送的Ctrl-C事件?

长问题
在对套接字调用recv()后,我希望适当地处理一些情况。其中之一是在收到Ctrl-C时返回特定错误代码。如何正确检测此事件?以下方法有效,但似乎不太恰当:

size_t recv_count;
static char ctrl_c[5] = {0xff, 0xf4, 0xff, 0xfd, 0x06};

recv_count = recv(socket, buffer, buffer_size, 0);

if (recv_count == sizeof(ctrl_c) &&
    memcmp(buffer, ctrl_c, sizeof(ctrl_c) == 0)
{
    return CTRL_C_RECEIVED;
}

我在这个UNIX套接字FAQ的侧注中找到了一个关于Ctrl-C的评论:

[...](顺便说一下,out-of-band也经常用于ctrl-C)。

据我所知,使用recv()并将特定标志作为最后一个参数来接收带外数据。但是当我像上面的代码一样使用recv()等待数据时,无法同时读取带外数据。除此之外,我使用没有oob标志的recv()仍然可以获得一些东西。

在 Telnet 中,Ctrl-D 被发送为 ^D (0x04) 字符。 - Vasily Redkin
1个回答

2
使用fcntl()将套接字设置为非阻塞状态,使用select()(在某些系统上为pselect())检查是否有数据到达。这就是如何获取套接字的当前状态,即它是否有数据可供recv()接收,并且是否可以接受send(),或者是否存在异常。不要简单地坐在那里阻塞。
recv()返回与提供的缓冲区大小相同的所有可用信息。如果已配置套接字以接收带外数据(套接字选项SO_OOBINLINE),并且存在未读取的带外数据,则仅返回带外数据。调用ioctl() SIOCATMARK以确定是否还有未读取的带外数据。
当您接收到带外数据时,您不能在单个recv()调用中超过OOB数据包的末尾,因此从这个角度来看,它是防错的。
我不知道什么被认为是最佳实践,但先抓取ctrl-c比其他已缓冲的套接字数据是一个好主意。

实际上,我正在编写一个内部使用的库,为套接字提供便利函数(其中已经包含了一些 fcntl() 和 select() 函数),所以这个问题并不特定于具体应用的实现,而是“我很酷的库可以帮助解决的又一个问题”。我希望能够捕获像 ctrl-c 这样的事件,而不需要 out-of-band 数据,以保持简单。 我同意不只是坐在 recv() 函数里等待,并且我的库支持阻塞和非阻塞模式,但如果能够实现一次,每次都有效就好了(商标)。 不管怎样,感谢你的回答! - Marco Masser
以上链接是一些类似努力的例子,旨在使套接字更简单易用。我认为更复杂的方法可以让您“调整设置”以满足您的确切需求。如果没有在代码中添加大量复杂选项,则可能很难满足“确切需求”。这有点抵消了您的努力意图。 - jim mcnamara
我刚刚看了一下swrapper代码,我认为它并没有做太多的事情,特别是与我的原始问题无关。我已经编写了许多我们应用程序所需的便利函数(获取/设置超时时间、缓冲区大小、延迟状态、阻塞状态等),没有这个Ctrl-C检测也不算太糟糕,只是有这个功能会更好。无论如何,还是谢谢! - Marco Masser
关于语句:“如果套接字已配置为接收带外数据(套接字选项SO_OOBINLINE)且存在未读取的带外数据,则只返回带外数据。”这听起来像是SO_OOBINLINE相反的语义,但它听起来像是使用recv()与MSG_OOB。我不确定这是否正确;同样,我也不确定它是否错误。你能提供一个参考吗? - kittemon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接