基于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;
}