2015-11-09 174 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--; 

这样,每当服务器接收邮件时,它会尝试把它发送到连接到服务器的所有客户端。

注意:您的代码不是线程安全的,并且会导致意外的行为,因为您正在线程内访问全局数据而不使用互斥锁。