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

如何在c套接字中检查TCP端口是否可用?,c,sockets,C,Sockets,我正在编写一个程序,有两个玩家想要连接到服务器来玩石头、布和剪刀。第一个玩家连接到端口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_STRE

我正在编写一个程序,有两个玩家想要连接到服务器来玩石头、布和剪刀。第一个玩家连接到端口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;
intsock=0;
char*hostname=“127.0.0.1”;
服务地址中的结构sockaddr\u;
字符缓冲区[1024]={0};
if((sock=socket(AF_INET,sock_STREAM,0))<0)
{
printf(“\n套接字创建错误\n”);
返回-1;
}
memset(&serv_addr,'0',sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
//清除此字段;sin_zero用于填充结构。
memset(&(服务地址sin_zero),0,8);
//查找主机IP地址。
结构hostent*hp=gethostbyname(主机名);
如果(hp==NULL){
fprintf(stderr,“未知主机%s\n”,主机名);
出口(1);
}
serv_addr.sin_addr=*((_addr*中的结构)hp->h_addr);
serv_addr.sin_port=htons(端口);
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{
printf(“\n连接失败\n”);
返回-1;
}
//获取用户名
printf(“请输入您的姓名:”);
scanf(“%s”,缓冲区);
发送(sock,buffer,strlen(buffer),0);
//初始化游戏
读取(sock,buffer,1024);
//玩游戏直到用户输入e
做{
printf(“%s”,缓冲区);
memset(buffer,0,sizeof(buffer));
scanf(“%s”,缓冲区);
while(检查输入(缓冲区)==0){
printf(“输入错误,请重试:”);
memset(buffer,0,sizeof(buffer));
scanf(“%s”,缓冲区);
}
send(sock,buffer,strlen(buffer),0);//将输入发送到服务器
printf(“客户端:已发送%s\n”,缓冲区);
读取(sock,buffer,1024);
printf(“客户端:收到%s\n”,缓冲区);
}而(超过(缓冲)=2);
返回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;
charplayer1name[1024];
charplayer2name[1024];
int p1_得分=0;
int p2_得分=0;
字符缓冲区[1024]={0};
int server_fd;
int server_fd2;
int播放器1_插座;
int播放器2_插座;
player1中的结构sockaddr_;
player2中的结构sockaddr_;
int opt=1;
int opt2=1;
int player1len=sizeof(player1);
int player2len=sizeof(player2);
//正在为播放器1创建套接字文件描述符
if((服务器fd=socket(AF\u INET,SOCK\u STREAM,0))==0){
perror(“套接字失败”);
退出(退出失败);
}
//为播放器2创建套接字文件描述符
if((服务器\u fd2=socket(AF\u INET,SOCK\u STREAM,0))==0){
perror(“套接字失败”);
退出(退出失败);
}
//使第一个套接字可重用
if(setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR | SO_REUSEPORT,&opt,sizeof(opt))){
perror(“setsockopt”);
退出(退出失败);
}
//使第二个套接字可重用
if(setsockopt(服务器fd2、SOL_套接字、SO_REUSEADDR、SO_REUSEPORT和opt2、sizeof(opt2))){
perror(“setsockopt”);
退出(退出失败);
}
//指定第一个播放机的地址
player1.sin_family=AF_INET;
player1.sin_addr.s_addr=INADDR\u ANY;
player1.sinu端口=htons(端口1);
//指定第二个播放机的地址
player2.sin_family=AF_INET;
player2.sin_addr.s_addr=INADDR\u ANY;
player2.sinu端口=htons(端口2);
//将插座强制连接至端口6000

如果(bind(server_fd,(struct sockaddr*)&player1,sizeof(player1))为了让您获得错误,服务器必须在第一个客户端连接时关闭侦听端口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;
    }
}
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0
{
if(errno==econnreflused){
serv_addr.sin_port=htons(端口+1);
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{
printf(“\n连接失败\n”);
返回-1;
}
}否则{
printf(“\n连接失败\n”);
返回-1;
}
}
但是,请注意,由于时间窗口的原因,这有一种潜在的故障模式。如果两个客户端尝试同时连接,则第二个客户端的连接请求可能在服务器关闭侦听套接字之前到达,因此对
connect()的调用
仍将成功,即使服务器从未处理该连接


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

如果有人需要我提供任何其他信息,请告诉我。请尽快接受、阅读和发布MCVE和我们可能可以帮助您。事实上,您甚至不告诉我们正在执行哪个代码路径。您是否尝试在调试器中单步执行它?为什么它们连接到不同的端口?客户端必须连接到服务器正在侦听的同一端口。服务器为什么要侦听不同的端口?您向我们显示的代码越少,问题就越严重我们必须自己写更多的东西。这更不诚实。感谢您的回复,我确实在我创建的第二个套接字中第二次调用了accept,但我无法关闭第一个套接字,因为我想同时从两个客户端获取输入关闭侦听套接字对已接受的套接字没有影响。哦,别担心,非常感谢。我一时忘记了自己的密码。