文档库 最新最全的文档下载
当前位置:文档库 › 一个基于socket的Linux上的网络聊天程序--多线程的服务器程序

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

一个基于socket的Linux上的网络聊天程序--多线程的服务器程序
2007-11-04 13:35编译方式:
gcc -pthread -o chat_server chat_server.c
/************************************************************
* 基于socket的聊天服务器端
* Copyright by Subo, All Right Reserved
*设计思路:
* 客户机提出各种请求,服务器根据不同请求,发送不同的响应.
* 服务器端采用多线程,为每个连接的客户建立一个服务线程.
*关键问题:
* 客户机和服务器之间协议制订
* 多线程访问同一个用户列表的互斥问题
*************************************************************/
#include
#include
#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;

/************************************************************
*函数名称: init_user_table
*函数执行失败: 当一个报文不能容纳全部用户名称列表时,给出错误提示信息,结束程序
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
*************************************************************/
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_table[i].client_socket = NOT_IN_USE;
bzero(user_table[i].user_ID,OPTION_SIZE);
bzero(user_table[i].password,OPTION_SIZE);
}
}
/************************************************************
*函数名称: login
*正常返回值: 登录成功为SUCCEED,登录失败为FAIL
*参数说明: client_socket是服务器同用户正在进行通信的socket
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
*************************************************************/
int login(char * user_ID, char * password, int client_socket)
{
pthread_mutex_lock(&user_table_mutex);
int i=0;
for(i=0;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;
}
/************************************************************
*函数名称: get_active_user_list
*正常返回值: SUCCEED
*参数说明: 在函数返回数据放置在字符数组user_list_buffer中,
* 在user_list_buffer中,每个用户名称占据USER_ID_SIZE + 1大小.
* 要求user_list_buffer中的数据必须初始化为全'\0'
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
*************************************************************/
int get_active_user_list(char * user_list_buffer)
{
pthread_mutex_lock(&user_table_mutex);
int i=0;
for(i=0;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;
}
/************************************************************
*函数名称: user_register
*正常返回值: 注册成功SUCCEED,注册失败FAIL
*函数执行失败: 注册重复的user_ID,注册失败.
* 如果user_table中没有处于空闲的记录,注册失败.
*参数说明: client_socket是服务器同用户正在进行通信的socket
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
*************************************************************/
int user_register(char * user_ID, char * password, int client_socket)
{
pthread_mutex_lock(&user_table_mutex);
int i=0;
for(i=0;i{
if(strcmp(user_table[i].user_ID,user_ID)==0)
{
pthread_mutex_unlock(&user_table_mutex);
return FAIL;
}
}
for(i=0;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;
}
/************************************************************
*函数名称: look_up_socket
*正常返回值: 服务器与目的用户通信的socket,
*函数执行失败: 没有找到服务器与目的用户通信的socket,返回值为FAIL
*参数说明: receiver是目的用户的ID
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
***********************************

**************************/
int look_up_socket(char * receiver)
{
pthread_mutex_lock(&user_table_mutex);
int socket=0;
int i=0;
for(i=0;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;
}
/************************************************************
*函数名称: deactive_user
*功能说明: 用于用户登出服务器时,把服务器与用户通信的socket设置为NOT_LOGIN
*正常返回值: SUCCEED
*函数执行失败: 没有找到服务器与用户通信的socket,返回值为FAIL
*参数说明: client_socket是服务器与用户通信的socket
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
*************************************************************/
int deactive_user(int client_socket)
{
pthread_mutex_lock(&user_table_mutex);
int i=0;
for(i=0;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;
}
/************************************************************
*函数名称: user_change_register
*正常返回值: 注册成功SUCCEED,注册失败FAIL
*函数执行失败: 注册重复的user_ID,注册失败.
*函数功能的其他说明: 不改变当前用户的登录状态
*参数说明: client_socket是服务器同用户正在进行通信的socket
*依赖自定义数据结构: struct user -- 本文件
*依赖全局变量: user_table -- 本文件
* user_table_mutex -- 本文件
*************************************************************/
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{
if(strcmp(user_table[i].user_ID,user_ID)==0)
{
pthread_mutex_unlock(&user_table_mutex);
return FAIL;
}
}
for(i=0;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;
}
/******************************************************

******
*函数名称: init_server_socket
*功能说明: 初始化服务器用于监听的的socket
*正常返回值: 已经初始化的服务器用于监听的的socket
*函数执行失败: 输出错误信息,退出程序
*************************************************************/
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;
}
/************************************************************
*函数名称: process_request
*功能说明: 根据接收到的报文的内容,进行响应的服务.
* 服务类型包括:注册,登录,获取已登录用户列表,向用户发送信息,退出,修改注册信息
*正常返回值: 服务器对用户发回的响应类型
*函数执行失败: 没有检测和处理
*参数说明: client_socket是服务器与用户通信的socket
* receive_buffer为服务器收到的报文的内容
*依赖自定义数据结构: chat_package -- chat.h
*************************************************************/
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;
}
/************************************************************
*函数名称: talk_to_client
*功能说明: 对单独的一个用户的各种请求进行服务,当用户的请求为EXIT时,结束本线程
*函数执行失败: 通信失败时,显示错误信息,结束本线程
*依赖自定义数据结构: chat_package -- chat.h
*************************************************************/
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;


相关文档
相关文档 最新文档