我最近一直在学习 Unix 中的网络,并编写了这两个简单的程序,它们等待连接,接收消息,然后将相同的消息发送回发送者:
发送.cpp
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <iostream>
#include <unistd.h>
int main(int argc, char const *argv[])
{
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "2000", &hints, &res);
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (auto error = connect(sockfd, res->ai_addr, res->ai_addrlen) < 0){
std::cout << strerror(errno) << '\n';
exit(1);
}
char msg[] = "Hello, World";
send(sockfd, &msg, sizeof(msg), 0);
char input[sizeof(msg)];
recv(sockfd, &input, sizeof(input), 0);
std::cout << input << '\n';
close(sockfd);
return 0;
}
接收.cpp
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/poll.h>
#include <iostream>
#include <unistd.h>
int main(int argc, char const *argv[])
{
struct addrinfo hints, *res;
int sockfd, new_fd;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "2000", &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
bind(sockfd, res->ai_addr, res->ai_addrlen);
listen(sockfd, 5);
struct sockaddr_storage their_addr1;
socklen_t addr_size;
addr_size = sizeof(their_addr1);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr1, &addr_size);
if (new_fd < 0)
{
std::cout << "Error" << '\n';
std::cout << strerror(errno) << '\n';
exit(1);
}
std::cout << "Accepted" << '\n';
char msg[255];
auto n = recv(new_fd, &msg, 255, 0);
std::cout << msg << '\n';
send(new_fd, &msg, n, 0);
close(sockfd);
close(new_fd);
return 0;
}
如果我运行 receive.cpp
,然后快速(在大约 5 秒内)运行 send.cpp
,(从命令行运行两者)程序运行良好,但如果我需要更长的时间,那么发送程序总是会收到连接拒绝错误并且接收程序永远不会终止。据我了解,accept()
调用会阻止应用程序的其余部分并继续侦听,直到出现有效连接。这不是它的工作原理吗?任何帮助都会非常感谢。
答案 0 :(得分:1)
归功于@n。 1.8e9-where's-my-share m。
问题是绑定失败是由于“地址已在使用”引起的,这是因为 TCP/IP 协议等待特定时间以确保所有数据包都已到达,然后才允许相同的 IP 和端口组合再次使用。
修复:
等待内核放弃端口。
设置套接字选项以允许使用相同的端口重用 setockopt()
int yes=1; if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) { perror("setsockopt"); 退出(1); }