基于socket的Linux上的网络聊天程序--多线程的服务器

编译方式:
gcc -pthread -o chat_server chat_server.c

#include <pthread.h>
#include <sys/errno.h>   
#include "chat.h"

#define LENGTH_OF_LISTEN_QUEUE    (20)
#define USER_AMOUNT_MAX    (50)

#define NOT_LOGIN    (-1)
#define NOT_IN_USE    (NOT_LOGIN -1)
#define USER_ID_SIZE (ID_SIZE)
typedef struct user{
    char user_ID[USER_ID_SIZE];
    char password[PASSWORD_SIZE];
    int client_socket;
    //client_socket==NOT_LOGIN,表示没有用户登录,
    //client_socket==NOT_IN_USE,表示没有用户注册,               
}user;
//多线程共享user_table
static user user_table[USER_AMOUNT_MAX];
//访问user_table时要使用的信号量
pthread_mutex_t user_table_mutex;


int init_user_table()
{
    if(USER_ID_SIZE*USER_AMOUNT_MAX>MESSAGE_SIZE)
    {
        printf("USER_ID_SIZE*USER_AMOUNT_MAX>MESSAGE_SIZE\n");
        exit(1);
    }   
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        user_table[i].client_socket = NOT_IN_USE;
        bzero(user_table[i].user_ID,OPTION_SIZE);
        bzero(user_table[i].password,OPTION_SIZE);
    }
}

int login(char * user_ID, char * password, int client_socket)
{
    pthread_mutex_lock(&user_table_mutex);
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if( (strcmp(user_table[i].user_ID,user_ID)==0)
            &&(strcmp(user_table[i].password,password)==0) )
        {
            user_table[i].client_socket = client_socket;
            pthread_mutex_unlock(&user_table_mutex);
            return SUCCEED;
        }
    }
    pthread_mutex_unlock(&user_table_mutex);
    return FAIL;
}

int get_active_user_list(char * user_list_buffer)
{
    pthread_mutex_lock(&user_table_mutex);
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(user_table[i].client_socket > NOT_LOGIN)
        {
            memcpy(user_list_buffer, user_table[i].user_ID, USER_ID_SIZE);
            user_list_buffer += USER_ID_SIZE + 1;
        }
    }   
    pthread_mutex_unlock(&user_table_mutex);
    return SUCCEED;
}

int user_register(char * user_ID, char * password, int client_socket)
{
    pthread_mutex_lock(&user_table_mutex);
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(strcmp(user_table[i].user_ID,user_ID)==0)
        {
            pthread_mutex_unlock(&user_table_mutex);
            return FAIL;
        }
    }
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(NOT_IN_USE == user_table[i].client_socket)
        {
            user_table[i].client_socket = NOT_LOGIN;
            memcpy(user_table[i].user_ID,user_ID,USER_ID_SIZE);
            memcpy(user_table[i].password,password,PASSWORD_SIZE);
            pthread_mutex_unlock(&user_table_mutex);
            return SUCCEED;
        }
    }
    pthread_mutex_unlock(&user_table_mutex);
    return FAIL;
}

int look_up_socket(char * receiver)
{
    pthread_mutex_lock(&user_table_mutex);
    int socket=0;
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(strcmp(user_table[i].user_ID,receiver)==0)
        {
            if(user_table[i].client_socket>=0)
            {
                socket = user_table[i].client_socket;
                pthread_mutex_unlock(&user_table_mutex);
                return socket;
            }
        }
    }
    pthread_mutex_unlock(&user_table_mutex);
    return FAIL;
}

int deactive_user(int client_socket)
{
    pthread_mutex_lock(&user_table_mutex);
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(user_table[i].client_socket == client_socket)
        {
            user_table[i].client_socket=NOT_LOGIN;
            pthread_mutex_unlock(&user_table_mutex);
            return SUCCEED;
        }
    }
    pthread_mutex_unlock(&user_table_mutex);
    return FAIL;
}

int user_change_register(char * user_ID, char * password, int client_socket)
{
    pthread_mutex_lock(&user_table_mutex);
    int i=0;
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(strcmp(user_table[i].user_ID,user_ID)==0)
        {
            pthread_mutex_unlock(&user_table_mutex);
            return FAIL;
        }
    }
    for(i=0;i<USER_AMOUNT_MAX;i++)
    {
        if(client_socket == user_table[i].client_socket)
        {
            memcpy(user_table[i].user_ID,user_ID,USER_ID_SIZE);
            memcpy(user_table[i].password,password,PASSWORD_SIZE);
            pthread_mutex_unlock(&user_table_mutex);
            return SUCCEED;
        }
    }
    pthread_mutex_unlock(&user_table_mutex);
    return FAIL;
}

int init_server_socket()
{
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(CHAT_SERVER_PORT);

    int server_socket = socket(AF_INET,SOCK_STREAM,0);
    if( server_socket < 0)
    {
        printf("Create Socket Failed!");
        exit(1);
    }
   
    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
    {
        printf("Server Bind Port : %d Failed!", CHAT_SERVER_PORT);
        exit(1);
    }

    if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
    {
        printf("Server Listen Failed!");
        exit(1);
    }
    return server_socket;
}

int process_request(int client_socket, char * receive_buffer)
{
    chat_package send_buffer;
    bzero((char*)&send_buffer,BUFFER_SIZE);
    char * user_ID = ((chat_package *)receive_buffer)->from;
    char * password = ((chat_package *)receive_buffer)->password;
    char * receiver = ((chat_package *)receive_buffer)->to;
    printf("Request %d from client\n",((chat_package *)receive_buffer)->type);
    switch(((chat_package *)receive_buffer)->type)
    {
    case REGISTER:
        send_buffer.type = user_register(user_ID, password, client_socket);
        break;
    case LOGIN:
        send_buffer.type = login(user_ID, password, client_socket);
        break;
    case GET_USER_LIST:
        memcpy(send_buffer.option, USER_LIST, OPTION_SIZE);
        send_buffer.type = get_active_user_list(send_buffer.message);
        break;
    case TALK_TO:
        send_buffer.type = SUCCEED;
        send(client_socket, (chat_package *)&send_buffer,BUFFER_SIZE,0);
        client_socket = look_up_socket(receiver);
        send_buffer.type = TRANSFER;
        memcpy(send_buffer.from, ((chat_package *)receive_buffer)->from, MESSAGE_SIZE);
        memcpy(send_buffer.message, ((chat_package *)receive_buffer)->message, MESSAGE_SIZE);
        break;
    case EXIT:
        deactive_user(client_socket);
        return send_buffer.type;   
        break;
    case CHANGE:
        send_buffer.type = user_change_register(user_ID, password, client_socket);
    }
    printf("Answer %d to client\n",send_buffer.type);
    send(client_socket, (chat_package *)&send_buffer,BUFFER_SIZE,0);
    return send_buffer.type;   
}

void * talk_to_client(void * new_server_socket_to_client)
{
    int new_server_socket = (int)new_server_socket_to_client;
    int request = NO_COMMAND;
    while(request!=EXIT)
    {
        chat_package buffer;
        bzero((char*)&buffer,BUFFER_SIZE);
        int length = recv(new_server_socket,(char*)&buffer,BUFFER_SIZE,0);
        if (length < 0)
        {
            printf("Server Recieve Data Failed!\n");
            close(new_server_socket);
            pthread_exit(NULL);
        }
        if (length==0)
        {
            close(new_server_socket);
            pthread_exit(NULL);
        }      
        request = process_request(new_server_socket, (char*)&buffer);
    }
    close(new_server_socket);
    pthread_exit(NULL);      
}

int main(int argc, char **argv)
{
    init_user_table();
    pthread_mutex_init(&user_table_mutex, NULL);
    int server_socket = init_server_socket();

    pthread_t child_thread;
    pthread_attr_t child_thread_attr;
    pthread_attr_init(&child_thread_attr);
    pthread_attr_setdetachstate(&child_thread_attr,PTHREAD_CREATE_DETACHED);
    while (1)
    {
        struct sockaddr_in client_addr;
        socklen_t length = sizeof(client_addr);
        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
        if ( new_server_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }
        if( pthread_create(&child_thread,&child_thread_attr,talk_to_client, (void *)new_server_socket) < 0 )
            printf("pthread_create Failed : %s\n",strerror(errno));
    }
    close(server_socket);
    pthread_attr_destroy(&child_thread_attr);
    pthread_mutex_destroy(&user_table_mutex);
    pthread_exit (NULL);
    return 0;
}

posted @ 2010-12-17 14:33  flyxiang  阅读(742)  评论(0编辑  收藏  举报