2017-05-06 98 views
0

我有一个小问题:我的服务器明白他不能接受新的连接,但客户端仍认为他已连接。 我不知道如何解决这个问题。拒绝连接到服务器C套接字编程

我的客户端代码:

#include<stdio.h> //printf 
#include<string.h> //strlen 
#include<sys/socket.h> //socket 
#include<arpa/inet.h> //inet_addr 
#include <fcntl.h> // for open 
#include <unistd.h> // for close 

int main(int argc , char *argv[]){ 
    int sock; 
    struct sockaddr_in server; 
    char message[1000] , server_reply[2000]; 

    //Create socket 
    sock = socket(AF_INET , SOCK_STREAM , 0); 
    if (sock == -1){ 
     printf("Could not create socket"); 
    } 
    puts("Socket created"); 

    server.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    server.sin_family = AF_INET; 
    server.sin_port = htons(8080); 

    //Connect to remote server 
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0){ 
     perror("connect failed. Error"); 
     return 1; 
    } 

    puts("Connected\n"); 

    //keep communicating with server 
    while(1){ 
     printf("Enter message : "); 
     scanf("%s" , message); 

     //Send some data 
     if(send(sock , message , strlen(message) , 0) < 0){ 
      puts("Send failed"); 
      return 1; 
     } 

     //Receive a reply from the server 
     if(recv(sock , server_reply , 2000 , 0) < 0){ 
      puts("recv failed"); 
      break; 
     } 

     puts("Server reply :"); 
     puts(server_reply); 
    } 

    close(sock); 
    return 0; 
} 

而我的服务器代码:

#include<stdio.h> 
#include<string.h> //strlen 
#include<stdlib.h> //strlen 
#include<sys/socket.h> 
#include<arpa/inet.h> //inet_addr 
#include<unistd.h> //write 
#include<pthread.h> //for threading , link with lpthread 

#define MAX_PLAYER 4 

void *connection_handler(void *); 

int nbrePlayer = 0; 

int main(int argc , char *argv[]){ 
    int socket_desc , client_sock , c , *new_sock; 

    struct sockaddr_in server , client; 

    //Create socket 
    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
    if (socket_desc == -1) 
    { 
    printf("Could not create socket"); 
    } 
    puts("Socket created"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(8080); 

    //Bind 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0){ 
    //print the error message 
    perror("bind failed. Error"); 
    return 1; 
    } 
    puts("bind done"); 

    //Listen 
    if(listen(socket_desc , 4)<0){ 
    perror("listen"); 
    return 1; 
    } 

    //Accept and incoming connection 
    puts("Waiting for incoming connections..."); 
    c = sizeof(struct sockaddr_in); 

    while((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))>0){ 
    if(nbrePlayer>=MAX_PLAYER){ 
     puts("connection refused"); 
     close(client_sock); 
     continue; 
    } else { 
     puts("Connection accepted"); 
    } 
    nbrePlayer++; 
    pthread_t sniffer_thread; 
    new_sock = malloc(1); 
    *new_sock = client_sock; 

    if(pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0){ 
     perror("could not create thread"); 
     return 1; 
    } 

    //Now join the thread , so that we dont terminate before the thread 
    //pthread_join(sniffer_thread , NULL); 
    puts("Handler assigned"); 
    printf("%d\n",nbrePlayer); 
    } 

    if (client_sock < 0){ 
    perror("accept failed"); 
    return 1; 
    } 

    return 0; 
} 

/* 
* This will handle connection for each client 
* */ 
void *connection_handler(void *socket_desc){ 
    //Get the socket descriptor 
    int sock = *(int*)socket_desc; 
    int read_size; 
    char *message , client_message[2000]; 

    //Receive a message from client 
    while((read_size = recv(sock , client_message , 2000 , 0)) > 0){ 
    //Send the message back to client 
    write(sock , client_message , strlen(client_message)); 
    } 

    if(read_size == 0){ 
    puts("Client disconnected"); 
    fflush(stdout); 
    } 
    else if(read_size == -1){ 
    perror("recv failed"); 
    } 

    //Free the socket pointer 
    free(socket_desc); 
    `nbrePlayer`--; 
    //Delete the player for the shared memory 
    return 0; 
} 

THX着您的答案

+0

你的服务器理解这一点,客户的意思以为它连接?它是如何显示的?究竟发生了什么? –

+0

OT:这个......接受(...,(socklen_t *)&c)'是坏的。想象一下'int'和'socklen_t'将会有不同的大小!直接将'c'定义为'socklen_t'。 – alk

+0

OT:当服务器开始发送“更大”的数据量时,这个'if(recv(sock,server_reply,2000,0)<0)'会开始给你头痛。请仔细阅读“recv()”文档,以了解对N字节的send()调用可能会导致N次调用recv()来接收发送的N个字节。 – alk

回答

0

这是因为在这里你正在检查,如果连接最初正确启动,如果超过了一定数量的球员,则不是。

为了达到您喜欢的程度,您可能希望创建与您的程序可用的数据有关的特殊消息。

例如:连接时,如果超过了播放器的数量,服务器会向客户端发送一条消息,告诉他他的请求被拒绝,然后关闭套接字服务器端。收到此消息后,客户端在关闭自己的套接字之前会向用户显示一个很好的错误。

这样你就可以在两端都有适当的连接拒绝和套接字关闭。

+0

你的回应对于一个务实的程序员来说是好的,但是如何让服务器拒绝连接(不接受他们说某事并断开客户端)呢?问题不是关于游戏,而是关于socket API的工作原理。 –

1

在您的应用程序中,服务器首先接受连接,然后关闭它,当它满足一定条件时,客户端在套接字发送连接到服务器时,套接字发送并不总是检测到关闭/断开的连接,但recv总是检测它。 因此,您应该考虑设计应用程序,以便客户端在连接后首先执行recv(期待欢迎消息),以便从服务器检测到关闭的套接字。

另一种方式可能是,如果条件nbrePlayer == MAX_PLAYER-1符合,您不应该调用accept,以便在客户端的connect()获取错误 为此,您需要将1作为backlog参数传递给listen()所以没有进入插座放在队列由听(),等待获得通过接受()调用 但积压的行为是受对底层平台按本实施后接受 listen() ignores the backlog argument?

1

刚落听值为listen(sock_fd, 0);将禁止任何传入连接,而服务器不在accept(2)系统调用。客户端将收到来自connect(2)系统调用的ECONNREF(“拒绝连接”)。

注:

刚才试了,它不工作... Linux内核默默地忽略0值(或指使用默认,只需要检查)

另一种可能是关闭接受套接字描述符,在这种情况下,您可能会失去对下一个连接中同一端口的访问,但它并未被使用,因此内核如何知道您要保留。附加的是一个简单的回声服务器,它实现了接受描述符的关闭,它的工作原理!(我已经包含的代码来获得分配的端口的连接内核,如果你不这样做bind(2)系统调用,因此它的同一端口下一次)

/* $Id: srv.c,v 1.6 2012/01/21 18:14:31 luis Exp $ 
* Author: Luis Colorado <[email protected]> 
* Date: Thu Feb 26 12:44:15 MET 1998 
*/ 

#define PROGNAME "srv" 

#include <sys/types.h> 
#include <sys/time.h> 
#include <time.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <netdb.h> 

extern char *optarg; 
extern int optind, opterr, optopt; 

int bind_port = 0; 
int listen_val = 0; 

int main (int argc, char **argv) 
{ 
    int opt, sd, res; 

    /* process the program options... */ 
    while ((opt = getopt(argc, argv, "b:l:")) != EOF) { 
      switch (opt) { 
     case 'b': bind_port = atol(optarg); break; 
     case 'l': listen_val = atol(optarg); break; 
      } /* switch */ 
    } /* while */ 

    /* Construct the sockaddr_in for the connect system call */ 
    for(;;) { 
     sd = socket (AF_INET, SOCK_STREAM, 0); 
     if (sd < 0) { 
      perror (PROGNAME ": socket"); 
     } /* if */ 
     if (bind_port) { 
      struct sockaddr_in srv_name; 
      srv_name.sin_family = AF_INET; 
      srv_name.sin_port = htons(bind_port); 
      srv_name.sin_addr.s_addr = INADDR_ANY; 
      int res = bind(sd, 
        (const struct sockaddr *)&srv_name, 
        sizeof srv_name); 
      if (res < 0) { 
       perror(PROGNAME ": bind"); 
       exit(1); 
      } 
      printf(PROGNAME ": bound to port %d\n", bind_port); 
     } 
     if (listen_val >= 0) { 
      int res = listen(sd, listen_val); 
      if (res < 0) { 
       perror(PROGNAME ": listen"); 
       exit(1); 
      } 
      printf(PROGNAME ": listen set to %d\n", listen_val); 
     } 
     { 
      struct sockaddr_in server; 
      int server_sz = sizeof server; 
      int res = getsockname(sd, 
        (struct sockaddr *) &server, 
        &server_sz); 
      bind_port = ntohs(server.sin_port); 
      printf("bound to port %d\n", bind_port); 
     } 

     struct sockaddr_in client; 
     int client_sz = sizeof client; 
     int cd = accept(sd, 
       (struct sockaddr *)&client, 
       &client_sz); 
     if (cd == -1) { 
      perror (PROGNAME ": accept"); 
      break; 
     } /* if */ 

     /************************************************* 
     * THIS IS THE TRICK... JUST CLOSE THE ACCEPTING 
     * SOCKET AND THE SERVER WILL REFUSE INCOMING 
     * CONNECTIONS FROM THEN ON. 
     *************************************************/ 
     close(sd); 

     printf("Accepted connection from %s:%d\n", 
       inet_ntoa(client.sin_addr), 
       ntohs(client.sin_port)); 
     char *greeting = PROGNAME": This is the echo " 
       "server ready for input\r\n"; 
     write(cd, greeting, strlen(greeting)); 

     char buffer[1024]; 
     ssize_t n; 

     while ((n = read(cd, buffer, sizeof buffer)) > 0) { 
      printf("Recibido: [%.*s]\n", n, buffer); 
      write(cd, buffer, n); 
     } /* while */ 
     if(n < 0) { 
      perror(PROGNAME ": read"); 
     } else { /* == 0 */ 
      printf("Recibido: EOF\n"); 
      char *greeting = "\r\n" PROGNAME ": Have a nice day :)\r\n"; 
      write(cd, greeting, strlen(greeting)); 
     } 
     close(cd); 
    } /* for (;;) */ 

} /* main */