gpt4 book ai didi

c - 如何检查c套接字中的TCP端口是否可用?

转载 作者:行者123 更新时间:2023-11-30 19:04:35 26 4
gpt4 key购买 nike

我正在编写一个程序,两个玩家想要连接到服务器来玩石头剪刀布。第一个玩家连接到端口 60000,当第二个玩家想要连接时,它会尝试连接到端口 60000。如果它失败了,它将连接到端口 60001。此时我不知道如何实现第二个播放器。

客户:

int sock = 0;
char *hostname = "127.0.0.1";
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}

memset(&serv_addr, '0', sizeof(serv_addr));

serv_addr.sin_family = AF_INET;


// Clear this field; sin_zero is used for padding for the struct.
memset(&(serv_addr.sin_zero), 0, 8);
// Lookup host IP address.
struct hostent *hp = gethostbyname(hostname);
if (hp == NULL) {
fprintf(stderr, "unknown host %s\n", hostname);
exit(1);
}
serv_addr.sin_addr = *((struct in_addr *) hp->h_addr);

serv_addr.sin_port = htons(PORT);


if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}

//getting the user name
printf("please enter your name:");
scanf("%s",buffer);
send(sock , buffer , strlen(buffer) , 0 );

//initializing the game
read( sock , buffer, 1024);

//playing the game until the user enters e
do{
printf("%s",buffer);
memset(buffer,0,sizeof(buffer));
scanf("%s",buffer);
while(check_input(buffer)==0){
printf("wrong input,try again:");
memset(buffer,0,sizeof(buffer));
scanf("%s",buffer);
}
send(sock , buffer , strlen(buffer) , 0 );//sending the input to the server
printf("client:sent %s\n",buffer);
read( sock , buffer, 1024);
printf("client:received %s\n",buffer);
}while(is_over(buffer)==2);
return 0;

在服务器中:

char player1Name[1024];
char player2Name[1024];
int p1_score = 0;
int p2_score = 0;
char buffer[1024] = {0};
int server_fd;
int server_fd2;
int player1_socket;
int player2_socket;
struct sockaddr_in player1;
struct sockaddr_in player2;
int opt = 1;
int opt2=1;
int player1len = sizeof(player1);
int player2len = sizeof(player2);

// Creating socket file descriptor for player 1
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}

// Creating socket file descriptor for player 2
if ((server_fd2 = socket(AF_INET, SOCK_STREAM, 0)) == 0){
perror("socket failed");
exit(EXIT_FAILURE);
}

// making the first socket reusable
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt))){
perror("setsockopt");
exit(EXIT_FAILURE);
}

// making the second socket reusable
if (setsockopt(server_fd2, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt2, sizeof(opt2))){
perror("setsockopt");
exit(EXIT_FAILURE);
}

//specifying the address of the first player
player1.sin_family = AF_INET;
player1.sin_addr.s_addr = INADDR_ANY;
player1.sin_port = htons( PORT1 );

//specifying the address of the second player
player2.sin_family = AF_INET;
player2.sin_addr.s_addr = INADDR_ANY;
player2.sin_port = htons( PORT2 );

// Forcefully attaching socket to the port 6000
if (bind(server_fd, (struct sockaddr *)&player1, sizeof(player1))<0){
perror("bind failed");
exit(EXIT_FAILURE);
}


if (listen(server_fd, 1) < 0){
perror("listen");
exit(EXIT_FAILURE);
}


if ((player1_socket = accept(server_fd, (struct sockaddr *)&player1,(socklen_t*)&player1len))<0){
perror("accept");
exit(EXIT_FAILURE);
}

get_playerName(player1Name,&player1_socket);

// Forcefully attaching socket to the port 6001
if (bind(server_fd2, (struct sockaddr *)&player2, sizeof(player2))<0){
perror("bind failed");
exit(EXIT_FAILURE);
}


if (listen(server_fd2, 1) < 0){
perror("listen");
exit(EXIT_FAILURE);
}


if ((player2_socket = accept(server_fd2, (struct sockaddr *)&player2,(socklen_t*)&player2len))<0){
perror("accept");
exit(EXIT_FAILURE);
}

get_playerName(player2Name,&player2_socket);
char input1;
char input2;
do{
input1=get_nextMoves(player1Name,buffer,&player1_socket);
printf("%c\n",input1);
input2=get_nextMoves(player2Name,buffer,&player2_socket);
printf("%c\n",input2);
evaluate(input1,input2,&p1_score,&p2_score);
}while(input1!='e' && input2!='e');
strcpy(buffer,result(1,p1_score,p2_score));
send(player1_socket , buffer , strlen(buffer) , 0 );
strcpy(buffer,result(2,p1_score,p2_score));
send(player2_socket , buffer , strlen(buffer) , 0 );
return 0;

此时,为了进行实验,我正在为玩家 1 和玩家 2 运行此代码。当我运行玩家 2 代码时,它就会卡住。我希望出现错误(更具体地说是 EADDRINUSE)。发生了什么事?我怎样才能进一步使用我的代码?

最佳答案

为了让您收到错误,服务器必须在第一个客户端连接时关闭正在端口 6000 上监听的套接字。否则,您的连接将成功,但会挂起,因为服务器不会再次调用 accept()

如果服务器这样做,那么第二个客户端应该收到错误ECONNREFUSED,并且它可以尝试第二个端口。

if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
if (errno == ECONNREFUSED) {
serv_addr.sin_port = htons(PORT + 1);
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
} else {
printf("\nConnection Failed \n");
return -1;
}
}

但请注意,由于时间窗口的原因,这具有潜在的故障模式。如果两个客户端几乎同时尝试连接,则第二个客户端的连接请求可能会在服务器关闭监听套接字之前到达,因此对 connect() 的调用仍然会成功,即使服务器从不处理该连接。

解决方案需要更复杂的服务器设计,它接受第二个连接并返回一个响应,表明该端口已被使用。不过,如果它可以做到这一点,那么您一开始就不需要两个端口。

关于c - 如何检查c套接字中的TCP端口是否可用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51757831/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com