假设我有一个TCP服务器(A)侦听端口8001。
现在,我想使用本地端口8001从服务器(A)打开服务器(B)的TCP套接字。这样,服务器(B)将看到服务器(A)与端口8001的连接。
有可能吗?我是否可以使用已用于侦听传入连接的传出连接端口。
答案 0 :(得分:1)
您可以这样做:socket
后跟setsockopt(SO_REUSEPORT)
,然后是bind
。
man socket(7)
:
SO_REUSEPORT (自Linux 3.9开始)
允许将多个
AF_INET
或AF_INET6
套接字绑定到相同的套接字地址。在调用套接字上的bind(2)
之前,必须在每个套接字(包括第一个套接字)上设置此选项。为防止端口劫持,绑定到同一地址的所有进程必须具有相同的有效UID。此选项可与TCP和UDP套接字一起使用。
这是一个工作示例,它有两个套接字绑定到同一个地址和端口127.0.0.1:2222。一个套接字是监听服务器套接字,另一个是成功连接到127.0.0.1:22(ssh)的客户端:
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <err.h>
#include <unistd.h>
int socket_and_bind() {
int s = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == s)
err(EXIT_FAILURE, "socket");
int flag = 1;
if(-1 == setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof flag))
err(EXIT_FAILURE, "setsockopt(SO_REUSEPORT)");
sockaddr_in sa = {};
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(2222);
sa.sin_family = AF_INET;
if(-1 == bind(s, reinterpret_cast<sockaddr*>(&sa), sizeof sa))
err(EXIT_FAILURE, "bind");
return s;
}
void server(int s) {
int c = accept(s, nullptr, nullptr);
if(-1 == c)
err(EXIT_FAILURE, "accept");
close(c);
}
void client(int s) {
sockaddr_in sa = {};
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(22);
sa.sin_family = AF_INET;
if(-1 == connect(s, reinterpret_cast<sockaddr*>(&sa), sizeof sa))
err(EXIT_FAILURE, "connect");
char buf;
if(1 != recv(s, &buf, sizeof buf, 0))
err(EXIT_FAILURE, "recv");
printf("connected\n");
}
int main() {
int s1 = socket_and_bind();
if(-1 == listen(s1, 1))
err(EXIT_FAILURE, "listen");
int s2 = socket_and_bind();
std::thread t1(server, s1);
std::thread t2(client, s2);
t2.join();
t1.detach();
return EXIT_SUCCESS;
}
在Linux中破坏的一件事是从addr:port连接到相同的:addr port。