客户端服务器套接字编程c-linux

时间:2015-11-09 06:30:44

标签: c linux sockets client-server

我正在编写一个使用TCP通过网络进行通信的聊天室程序。如果用户提供ip地址作为命令行参数,程序将尝试连接到该地址。如果没有,服务器将等待其他人连接。 服务器接收客户端发送的任何文本消息都没有问题。但是,客户端仅在发送自己的消息时才从服务器接收文本消息。我如何解决这个问题,以便客户端立即收到消息?这是我的代码

服务器代码:

#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;
}

1 个答案:

答案 0 :(得分:0)

我不确定我是否正确理解了您的问题。但在较高级别,我注意到在调用close(cli->connfd)后,您的sendall方法在客户端套接字上调用close(cli->connfd); /* Delete client from queue and yeild thread */ queue_delete(cli->uid); free(cli); cli_count--; 。在调用close之后,您将从队列中删除客户端详细信息。这样,被删除的客户端将永远不会收到任何未来的消息。你确定这是你想要的吗?

尝试删除这些行并检查这是否是您想要的 -

{{1}}

这样,只要服务器收到消息,它就会尝试将其发送给连接到服务器的所有客户端。

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