【问题标题】:Can one reliably connect a TCP socket to itself?可以可靠地将 TCP 套接字连接到自身吗?
【发布时间】:2016-05-14 17:47:48
【问题描述】:

我想知道是否有可能可靠地将一个 TCP 套接字连接到它自身——也就是说,只获得一个套接字,无论你发送()在哪里,你都会通过 recv()接收回来。我看到这可能会发生(例如,hereherehere),但是这些帖子都没有解释如何以编程方式和可靠地做到这一点(即,这通常被吹捧为一种好奇心,而不是一个会故意使用的功能)。我对适用于 Windows、Mac 和 Linux 的解决方案感兴趣。

为了完整起见,请让我解释一下我对此感兴趣的原因。我正在编写一个基于云的应用程序,其中服务器可以将消息发送到其他服务器,包括它们自己。每台服务器都使用一个套接字与其他服务器通信,因此,为了统一代码并使某些线程问题更简单,如果服务器也可以只使用一个套接字与自己通信就好了。

编辑: @Rufflewind 建议连接到环回适配器。我尝试使用下面的代码,无论是否调用监听。但是,在所有情况下,我都会遇到错误(“无效参数”或“不支持操作”)。我做错了什么?

#include <iostream>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void die(const char* const message) {
    perror(message);
    exit(0);
}

#define CHECK(operation,message) \
    if ((operation) != 0) \
        die(message)

int main(int argc, char* argv[]) {
    sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(40000);
    inet_aton("127.0.0.1", &local.sin_addr);
    int sck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    CHECK(bind(sck, (struct sockaddr *)&local, sizeof(local)), "Error while binding the socket to an address");
//    CHECK(listen(sck, 1), "Error while listening.");
    CHECK(connect(sck, (struct sockaddr *)&local, sizeof(local)), "Error while connecting the socket to self");
    std::cout << "Succeeded in connecting sockets!" << std::endl;
    const char* message = "ABCDEFGH";
    const size_t messageLength = ::strlen(message) + 1;
    const char* currentSend = message;
    ssize_t leftToSend = messageLength;
    while (leftToSend != 0) {
        const ssize_t sent = send(sck, currentSend, leftToSend, 0);
        if (sent == -1)
            die("Can't send.");
        currentSend += sent;
        leftToSend -= sent;
    }
    std::cout << "Sent the message!" << std::endl;
    char buffer[256];
    char* currentRead = buffer;
    size_t leftToRead = messageLength;
    while (leftToRead != 0) {
        const ssize_t read = recv(sck, currentRead, leftToRead, 0);
        if (read == -1)
            die("Can't read.");
        currentRead += read;
        leftToRead -= read;
    }
    std::cout << "Received message: " << buffer << std::endl;
    return 0;
}

【问题讨论】:

  • 您的意思是,例如连接到回显服务器?
  • @MartinJames 我想到了这个:thecodelesscode.com/case/28
  • 是的,类似的东西,虽然如果不涉及外部进程会更好(即,您不需要在单独的线程中运行真正的回显服务器 - 理想情况下都是由 TCP 堆栈处理,因为套接字将具有相同的传出地址和传入地址)。

标签: sockets tcp


【解决方案1】:

最直接的方法是绑定到环回适配器。只需在某个任意端口上收听127.0.0.1 并连接到该端口即可。

这种方法的问题在于端口在机器上是全局的,这意味着 其他 程序也可以连接到它,如果您有多个程序,您可能会遇到冲突或可能会耗尽所有可能的端口。

另一种方法是使用 Unix 域套接字,但这在 Windows 上不受支持。

【讨论】:

  • 谢谢。我已经用一些我尝试过的示例代码更新了我的帖子,但它没有用。如果您能指出我做错了什么,我将不胜感激。
  • 另外,请注意,我希望只有 一个 套接字可以“自行”完成所有循环——也就是说,无需有人读取数据然后写回来。如果最坏的情况发生,我想我总是可以有一个单独的环回线程;但是,我只是希望我能有一个系统提供的“自循环套接字”。
  • 您的代码似乎在我的机器 (Linux) 上运行良好。
  • 嗯,现在我在 Linux 上试过了,它确实有效。最初我使用的是 Mac OS X,但它不起作用。所以似乎没有可移植的方式在我感兴趣的所有平台上实现这一点。无论如何,谢谢你的帮助!
  • 连接回环的方式有点不合常规。正如您所说,最便携的方法需要第二个线程充当执行回显的客户端。
猜你喜欢
  • 2021-09-25
  • 2012-03-03
  • 2011-11-27
  • 2013-12-05
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 2013-05-14
  • 2014-08-02
相关资源
最近更新 更多