我有一些n
个节点,我想通过TCP将它们相互连接。我正在实现以下伪代码:
Node ids in {1, 2, ..., n}
For node having node id k :
act as the client and try to connect to nodes with id > k
act as the server and listen for connection requests from nodes with id < k
while tracking which of the nodes connected in each step
伪代码中的两个步骤都实现为for
循环。 值得注意的是,所有tcp连接都使用相同的端口。该代码适用于2
个节点,但对于3
个节点,第二个侦听功能位于具有id 3
的节点(正在侦听连接)打印错误&#34;地址已在使用&#34; 。我相信对accept()函数的调用会返回错误。
我在C++
和linux
(Ubuntu 15.04)编程(使用套接字)。
我在网上搜索并得出结论,两个以上的客户端可以连接到同一个端口(因为服务器上的套接字不同)。我做错了什么?
编辑:
实际代码(只是相关功能的一小部分)。假设ip_addrs
,node_rank,num_nodes被适当地初始化。
// port for the tcp connection
int port = 25551;
// ip address of the local node
string ip_addr;
// sockets for talking to the nodes
vector <int> sockets;
static int exchange_node_rank(int sock) {
char msg[10];
sprintf(msg, "%d", node_rank);
write(sock, msg, sizeof(msg));
read(sock, msg, sizeof(msg));
int rank;
sscanf(msg, "%d", &rank);
return rank;
}
// servername is only for client, it *is* NULL for server
static pair<int, int> sock_connect(const char *servername) {
struct addrinfo *resolved_addr = NULL;
struct addrinfo *iterator;
char service[6];
int sockfd = -1;
int listenfd = 0;
int tmp;
struct addrinfo hints = {.ai_flags = AI_PASSIVE,
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM};
if(sprintf(service, "%d", port) < 0) goto sock_connect_exit;
/* Resolve DNS address, use sockfd as temp storage */
sockfd = getaddrinfo(servername, service, &hints, &resolved_addr);
if(sockfd < 0) {
fprintf(stderr, "%s for %s:%d\n", gai_strerror(sockfd), servername,
port);
goto sock_connect_exit;
}
/* Search through results and find the one we want */
for(iterator = resolved_addr; iterator; iterator = iterator->ai_next) {
sockfd = socket(iterator->ai_family, iterator->ai_socktype,
iterator->ai_protocol);
if(sockfd >= 0) {
if(servername) {
/* Client mode. Initiate connection to remote */
while((tmp = connect(sockfd, iterator->ai_addr,
iterator->ai_addrlen))) {
}
} else {
/* Server mode.
Set up listening socket an accept a connection */
listenfd = sockfd;
sockfd = -1;
if(bind(listenfd, iterator->ai_addr, iterator->ai_addrlen))
goto sock_connect_exit;
listen(listenfd, 1);
sockfd = accept(listenfd, NULL, 0);
}
}
}
sock_connect_exit:
if(listenfd) close(listenfd);
if(resolved_addr) freeaddrinfo(resolved_addr);
if(sockfd < 0) {
if(servername)
fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port);
else {
perror("server accept");
fprintf(stderr, "accept() failed\n");
}
}
int rank = exchange_node_rank(sockfd);
return pair<int, int>(sockfd, rank);
}
void establish_tcp_connections (const vector <string> & ip_addrs) {
// try to connect to nodes greater than node_rank
for(int i = num_nodes - 1; i > node_rank; --i) {
cout << "trying to connect to node rank " << i << endl;
pair <int, int> p = sock_connect(ip_addrs[i].c_str());
cout << "connected to node rank " << i << endl << endl;
assert(p.second == i);
// set the socket
sockets[i] = p.first;
}
// listen to nodes trying to connect (having id less than node_rank).
// make sure that the caller is correctly identified with its id!
for(int i = node_rank - 1; i >= 0; --i) {
cout << "listening for nodes with lesser rank" << endl;
pair <int, int> p = sock_connect((char *)NULL);
cout << "connected to node rank " << p.second << endl << endl;
assert(p.second < node_rank);
// set the socket
sockets[p.second] = p.first;
}
}