2015-11-09 102 views
0

我在寫一個聊天室程序,使用TCP通過網絡進行通信。如果用戶提供ip地址作爲命令行參數,程序將嘗試連接到該地址。如果不是,服務器將等待其他人連接。 服務器沒有問題接收客戶端發送的任何文本消息。但是,客戶端只有在發送自己的消息時才從服務器接收文本消息。我如何解決這個問題,讓客戶端立即收到消息?這是我的代碼客戶端服務器套接字編程c-linux

Server代碼:

#define MAX_CLIENTS 100 

static unsigned int cli_count = 0; 
static int uid = 10; 

typedef struct { 
    struct sockaddr_in addr;  
    int connfd;   
    int uid;    
    char name[32];   
} client_t; 

client_t *clients[MAX_CLIENTS]; 

void queue_add(client_t *cl) 
{ 
    int i; 
    for(i=0;i<MAX_CLIENTS;i++) 
    { 
     if(!clients[i]) 
     { 
      clients[i] = cl; 
      return; 
     } 
    } 
} 

void queue_delete(int uid) 
{ 
    int i; 
    for(i=0;i<MAX_CLIENTS;i++) 
    { 
     if(clients[i]) 
     { 
      if(clients[i]->uid == uid) 
      { 
       clients[i] = NULL; 
       return; 
      } 
     } 
    } 
} 
void send_message_all(char *s) 
{ 

    int i; 
    for(i=0;i<MAX_CLIENTS;i++) 
    { 
     if(clients[i]) 
     { 
      write(clients[i]->connfd, s, strlen(s)); 
     } 
    } 
} 
void *hanle_client(void *arg) 
{ 
    char buff_in[256]; 
    char buff_out[256]; 
    int rlen; 
    cli_count++; 
    client_t *cli = (client_t *)arg; 
    sprintf(buff_out, "<<JOIN, HELLO %s\r\n", cli->name); 
    send_message_all(buff_out); 

    bzero(buff_in,sizeof(buff_in)); 

    while((rlen = read(cli->connfd,buff_in,sizeof(buff_in)-1))>0) 
    { 
     sprintf(buff_out, "[%s] %s\r\n", cli->name, buff_in); 
     send_message_all(buff_out); 
    } 


    close(cli->connfd); 

    /* Delete client from queue and yeild thread */ 
    queue_delete(cli->uid); 
    free(cli); 
    cli_count--; 
    pthread_detach(pthread_self()); 

    return NULL; 
} 

int main(int argc, char *argv[]) 
{ 
    int listenfd = 0, connfd = 0, portno; 
    struct sockaddr_in serv_addr; 
    struct sockaddr_in cli_addr; 
    pthread_t tid; 
    if (argc < 2) { 
     printf("ERROR, no port provided\n"); 
     exit(1); 
    } 


    //Create socket 
    listenfd= socket(AF_INET , SOCK_STREAM , 0); 
    if (listenfd == -1) 
    { 
     printf("Could not create socket"); 
    } 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = atoi(argv[1]); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serv_addr.sin_port = htons(portno); 

    /* Bind */ 
    if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
     perror("Socket binding failed"); 
     return 1; 
    } 

    /* Listen */ 
    if(listen(listenfd, 10) < 0) 
    { 
     perror("Socket listening failed"); 
     return 1; 
    } 

    printf("<[SERVER STARTED]>\n"); 
    socklen_t clilen = sizeof(cli_addr); 
    /* Accept clients */ 
    while((connfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen))) 
    { 
     /* Client settings */ 
     client_t *cli = (client_t *)malloc(sizeof(client_t)); 
     cli->addr = cli_addr; 
     cli->connfd = connfd; 
     cli->uid = uid++; 
     sprintf(cli->name, "%d", cli->uid); 

     /* Add client to the queue and fork thread */ 
     queue_add(cli); 
     pthread_create(&tid, NULL, &hanle_client, (void*)cli); 
    } 
} 

客戶端代碼:

int main(int argc , char *argv[]) 
{ 
    int sockfd, portno ; 
    struct sockaddr_in serv_addr; 
    struct hostent *server; 
    char message[2000],server_reply[2000]; 
    if (argc <3) 
    { 
     fprintf(stderr,"usage %s hostname port\n", argv[0]); 
     exit(1); 
    } 
    portno = atoi(argv[2]); 

    //Create socket 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    if (sockfd < 0) 
    { 
     perror("ERROR opening socket"); 
     exit(1); 
    } 
    server = gethostbyname(argv[1]); 

    if (server == NULL) { 
     fprintf(stderr,"ERROR, no such host\n"); 
     exit(1); 
    } 

    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); 
    serv_addr.sin_port = htons(portno); 

    //Connect to remote server 
    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
     perror("ERROR connecting"); 
     exit(1); 
    } 

    puts("Connected\n"); 

    //keep communicating with server 
    while(1) 
    { 
     //Receive a reply from the server 
     bzero(server_reply,2000); 
     if(recv(sockfd , server_reply , 2000,0) < 0) 
     { 
      puts("recv failed"); 
      break; 
     } 
     printf("%s", server_reply); 
     server_reply[0]='\0'; 

     //Send Message to server 
     printf("Enter Message:"); 
     bzero(message,2000); 
     fgets(message, sizeof(message),stdin); 

     if(send(sockfd , message , strlen(message),0) < 0) 
     { 
      puts("Send failed"); 
      return 0; 
     } 


    } 

    close(sockfd); 
    return 0; 
} 

回答

0

我不知道如果我理解正確你的問題。但在高層次上,我注意到在調用sendall之後,您的hanleClient方法在客戶端套接字上調用close(cli->connfd)。調用close之後,您將從隊列中刪除客戶端詳細信息。這樣,被刪除的客戶端永遠不會收到任何未來的消息。你確定這是你想要的嗎?

嘗試刪除這些行和檢查,如果這是你想要的 -

close(cli->connfd); 

/* Delete client from queue and yeild thread */ 
queue_delete(cli->uid); 
free(cli); 
cli_count--; 

這樣,每當服務器接收郵件時,它會嘗試把它發送到連接到服務器的所有客戶端。

注意:您的代碼不是線程安全的,並且會導致意外的行爲,因爲您正在線程內訪問全局數據而不使用互斥鎖。