posts - 0,  comments - 0,  trackbacks - 0
原帖地址:http://hi.baidu.com/dlpucat/blog/item/5a4de306e53d857802088196.html

编译方式:
gcc -pthread -o chat_server chat_server.c
  1 /************************************************************
  2 *    基于socket的聊天服务器端
  3 *    Copyright by Subo, All Right Reserved
  4 *设计思路:
  5 *    客户机提出各种请求,服务器根据不同请求,发送不同的响应.
  6 *   服务器端采用多线程,为每个连接的客户建立一个服务线程.
  7 *关键问题:
  8 *    客户机和服务器之间协议制订
  9 *   多线程访问同一个用户列表的互斥问题
 10 *************************************************************/
 11 #include <pthread.h>
 12 #include <sys/errno.h>   
 13 #include "chat.h"
 14 
 15 #define LENGTH_OF_LISTEN_QUEUE    (20)
 16 #define USER_AMOUNT_MAX    (50)
 17 
 18 #define NOT_LOGIN    (-1)
 19 #define NOT_IN_USE    (NOT_LOGIN -1)
 20 #define USER_ID_SIZE (ID_SIZE)
 21 typedef struct user{
 22     char user_ID[USER_ID_SIZE];
 23     char password[PASSWORD_SIZE];
 24     int client_socket;
 25     //client_socket==NOT_LOGIN,表示没有用户登录,
 26     //client_socket==NOT_IN_USE,表示没有用户注册,               
 27 }user;
 28 //多线程共享user_table
 29 static user user_table[USER_AMOUNT_MAX];
 30 //访问user_table时要使用的信号量
 31 pthread_mutex_t user_table_mutex;
 32 
 33 /************************************************************
 34 *函数名称: init_user_table
 35 *函数执行失败:   当一个报文不能容纳全部用户名称列表时,给出错误提示信息,结束程序
 36 *依赖自定义数据结构:     struct user -- 本文件
 37 *依赖全局变量:          user_table -- 本文件
 38 *************************************************************/
 39 int init_user_table()
 40 {
 41     if(USER_ID_SIZE*USER_AMOUNT_MAX>MESSAGE_SIZE)
 42     {
 43         printf("USER_ID_SIZE*USER_AMOUNT_MAX>MESSAGE_SIZE\n");
 44         exit(1);
 45     }   
 46     int i=0;
 47     for(i=0;i<USER_AMOUNT_MAX;i++)
 48     {
 49         user_table[i].client_socket = NOT_IN_USE;
 50         bzero(user_table[i].user_ID,OPTION_SIZE);
 51         bzero(user_table[i].password,OPTION_SIZE);
 52     }
 53 }
 54 /************************************************************
 55 *函数名称: login
 56 *正常返回值: 登录成功为SUCCEED,登录失败为FAIL
 57 *参数说明: client_socket是服务器同用户正在进行通信的socket
 58 *依赖自定义数据结构:    struct user -- 本文件
 59 *依赖全局变量:         user_table -- 本文件
 60 *                    user_table_mutex -- 本文件
 61 *************************************************************/
 62 int login(char * user_ID, char * password, int client_socket)
 63 {
 64     pthread_mutex_lock(&user_table_mutex);
 65     int i=0;
 66     for(i=0;i<USER_AMOUNT_MAX;i++)
 67     {
 68         if( (strcmp(user_table[i].user_ID,user_ID)==0)
 69             &&(strcmp(user_table[i].password,password)==0) )
 70         {
 71             user_table[i].client_socket = client_socket;
 72             pthread_mutex_unlock(&user_table_mutex);
 73             return SUCCEED;
 74         }
 75     }
 76     pthread_mutex_unlock(&user_table_mutex);
 77     return FAIL;
 78 }
 79 /************************************************************
 80 *函数名称: get_active_user_list
 81 *正常返回值: SUCCEED
 82 *参数说明:   在函数返回数据放置在字符数组user_list_buffer中,
 83 *           在user_list_buffer中,每个用户名称占据USER_ID_SIZE + 1大小.
 84 *           要求user_list_buffer中的数据必须初始化为全'\0'
 85 *依赖自定义数据结构:    struct user -- 本文件
 86 *依赖全局变量:         user_table -- 本文件
 87 *                    user_table_mutex -- 本文件
 88 *************************************************************/
 89 int get_active_user_list(char * user_list_buffer)
 90 {
 91     pthread_mutex_lock(&user_table_mutex);
 92     int i=0;
 93     for(i=0;i<USER_AMOUNT_MAX;i++)
 94     {
 95         if(user_table[i].client_socket > NOT_LOGIN)
 96         {
 97             memcpy(user_list_buffer, user_table[i].user_ID, USER_ID_SIZE);
 98             user_list_buffer += USER_ID_SIZE + 1;
 99         }
100     }   
101     pthread_mutex_unlock(&user_table_mutex);
102     return SUCCEED;
103 }
104 /************************************************************
105 *函数名称: user_register
106 *正常返回值: 注册成功SUCCEED,注册失败FAIL
107 *函数执行失败: 注册重复的user_ID,注册失败.
108 *             如果user_table中没有处于空闲的记录,注册失败.
109 *参数说明: client_socket是服务器同用户正在进行通信的socket
110 *依赖自定义数据结构:    struct user -- 本文件
111 *依赖全局变量:         user_table -- 本文件
112 *                    user_table_mutex -- 本文件
113 *************************************************************/
114 int user_register(char * user_ID, char * password, int client_socket)
115 {
116     pthread_mutex_lock(&user_table_mutex);
117     int i=0;
118     for(i=0;i<USER_AMOUNT_MAX;i++)
119     {
120         if(strcmp(user_table[i].user_ID,user_ID)==0)
121         {
122             pthread_mutex_unlock(&user_table_mutex);
123             return FAIL;
124         }
125     }
126     for(i=0;i<USER_AMOUNT_MAX;i++)
127     {
128         if(NOT_IN_USE == user_table[i].client_socket)
129         {
130             user_table[i].client_socket = NOT_LOGIN;
131             memcpy(user_table[i].user_ID,user_ID,USER_ID_SIZE);
132             memcpy(user_table[i].password,password,PASSWORD_SIZE);
133             pthread_mutex_unlock(&user_table_mutex);
134             return SUCCEED;
135         }
136     }
137     pthread_mutex_unlock(&user_table_mutex);
138     return FAIL;
139 }
140 /************************************************************
141 *函数名称: look_up_socket
142 *正常返回值: 服务器与目的用户通信的socket,
143 *函数执行失败: 没有找到服务器与目的用户通信的socket,返回值为FAIL
144 *参数说明: receiver是目的用户的ID
145 *依赖自定义数据结构:    struct user -- 本文件
146 *依赖全局变量:         user_table -- 本文件
147 *                    user_table_mutex -- 本文件
148 *************************************************************/
149 int look_up_socket(char * receiver)
150 {
151     pthread_mutex_lock(&user_table_mutex);
152     int socket=0;
153     int i=0;
154     for(i=0;i<USER_AMOUNT_MAX;i++)
155     {
156         if(strcmp(user_table[i].user_ID,receiver)==0)
157         {
158             if(user_table[i].client_socket>=0)
159             {
160                 socket = user_table[i].client_socket;
161                 pthread_mutex_unlock(&user_table_mutex);
162                 return socket;
163             }
164         }
165     }
166     pthread_mutex_unlock(&user_table_mutex);
167     return FAIL;
168 }
169 /************************************************************
170 *函数名称: deactive_user
171 *功能说明: 用于用户登出服务器时,把服务器与用户通信的socket设置为NOT_LOGIN
172 *正常返回值: SUCCEED
173 *函数执行失败: 没有找到服务器与用户通信的socket,返回值为FAIL
174 *参数说明: client_socket是服务器与用户通信的socket
175 *依赖自定义数据结构:    struct user -- 本文件
176 *依赖全局变量:         user_table -- 本文件
177 *                    user_table_mutex -- 本文件
178 *************************************************************/
179 int deactive_user(int client_socket)
180 {
181     pthread_mutex_lock(&user_table_mutex);
182     int i=0;
183     for(i=0;i<USER_AMOUNT_MAX;i++)
184     {
185         if(user_table[i].client_socket == client_socket)
186         {
187             user_table[i].client_socket=NOT_LOGIN;
188             pthread_mutex_unlock(&user_table_mutex);
189             return SUCCEED;
190         }
191     }
192     pthread_mutex_unlock(&user_table_mutex);
193     return FAIL;
194 }
195 /************************************************************
196 *函数名称: user_change_register
197 *正常返回值: 注册成功SUCCEED,注册失败FAIL
198 *函数执行失败: 注册重复的user_ID,注册失败.
199 *函数功能的其他说明: 不改变当前用户的登录状态
200 *参数说明: client_socket是服务器同用户正在进行通信的socket
201 *依赖自定义数据结构:    struct user -- 本文件
202 *依赖全局变量:         user_table -- 本文件
203 *                    user_table_mutex -- 本文件
204 *************************************************************/
205 int user_change_register(char * user_ID, char * password, int client_socket)
206 {
207     pthread_mutex_lock(&user_table_mutex);
208     int i=0;
209     for(i=0;i<USER_AMOUNT_MAX;i++)
210     {
211         if(strcmp(user_table[i].user_ID,user_ID)==0)
212         {
213             pthread_mutex_unlock(&user_table_mutex);
214             return FAIL;
215         }
216     }
217     for(i=0;i<USER_AMOUNT_MAX;i++)
218     {
219         if(client_socket == user_table[i].client_socket)
220         {
221             memcpy(user_table[i].user_ID,user_ID,USER_ID_SIZE);
222             memcpy(user_table[i].password,password,PASSWORD_SIZE);
223             pthread_mutex_unlock(&user_table_mutex);
224             return SUCCEED;
225         }
226     }
227     pthread_mutex_unlock(&user_table_mutex);
228     return FAIL;
229 }
230 /************************************************************
231 *函数名称: init_server_socket
232 *功能说明: 初始化服务器用于监听的的socket
233 *正常返回值: 已经初始化的服务器用于监听的的socket
234 *函数执行失败: 输出错误信息,退出程序
235 *************************************************************/
236 int init_server_socket()
237 {
238     struct sockaddr_in server_addr;
239     bzero(&server_addr,sizeof(server_addr));
240     server_addr.sin_family = AF_INET;
241     server_addr.sin_addr.s_addr = htons(INADDR_ANY);
242     server_addr.sin_port = htons(CHAT_SERVER_PORT);
243 
244     int server_socket = socket(AF_INET,SOCK_STREAM,0);
245     if( server_socket < 0)
246     {
247         printf("Create Socket Failed!");
248         exit(1);
249     }
250    
251     if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
252     {
253         printf("Server Bind Port : %d Failed!", CHAT_SERVER_PORT);
254         exit(1);
255     }
256 
257     if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
258     {
259         printf("Server Listen Failed!");
260         exit(1);
261     }
262     return server_socket;
263 }
264 /************************************************************
265 *函数名称: process_request
266 *功能说明: 根据接收到的报文的内容,进行响应的服务.
267 *          服务类型包括:注册,登录,获取已登录用户列表,向用户发送信息,退出,修改注册信息
268 *正常返回值: 服务器对用户发回的响应类型
269 *函数执行失败: 没有检测和处理
270 *参数说明: client_socket是服务器与用户通信的socket
271 *         receive_buffer为服务器收到的报文的内容
272 *依赖自定义数据结构:    chat_package -- chat.h
273 *************************************************************/
274 int process_request(int client_socket, char * receive_buffer)
275 {
276     chat_package send_buffer;
277     bzero((char*)&send_buffer,BUFFER_SIZE);
278     char * user_ID = ((chat_package *)receive_buffer)->from;
279     char * password = ((chat_package *)receive_buffer)->password;
280     char * receiver = ((chat_package *)receive_buffer)->to;
281     printf("Request %d from client\n",((chat_package *)receive_buffer)->type);
282     switch(((chat_package *)receive_buffer)->type)
283     {
284     case REGISTER:
285         send_buffer.type = user_register(user_ID, password, client_socket);
286         break;
287     case LOGIN:
288         send_buffer.type = login(user_ID, password, client_socket);
289         break;
290     case GET_USER_LIST:
291         memcpy(send_buffer.option, USER_LIST, OPTION_SIZE);
292         send_buffer.type = get_active_user_list(send_buffer.message);
293         break;
294     case TALK_TO:
295         send_buffer.type = SUCCEED;
296         send(client_socket, (chat_package *)&send_buffer,BUFFER_SIZE,0);
297         client_socket = look_up_socket(receiver);
298         send_buffer.type = TRANSFER;
299         memcpy(send_buffer.from, ((chat_package *)receive_buffer)->from, MESSAGE_SIZE);
300         memcpy(send_buffer.message, ((chat_package *)receive_buffer)->message, MESSAGE_SIZE);
301         break;
302     case EXIT:
303         deactive_user(client_socket);
304         return send_buffer.type;   
305         break;
306     case CHANGE:
307         send_buffer.type = user_change_register(user_ID, password, client_socket);
308     }
309     printf("Answer %d to client\n",send_buffer.type);
310     send(client_socket, (chat_package *)&send_buffer,BUFFER_SIZE,0);
311     return send_buffer.type;   
312 }
313 /************************************************************
314 *函数名称: talk_to_client
315 *功能说明: 对单独的一个用户的各种请求进行服务,当用户的请求为EXIT时,结束本线程
316 *函数执行失败: 通信失败时,显示错误信息,结束本线程
317 *依赖自定义数据结构:    chat_package -- chat.h
318 *************************************************************/
319 void * talk_to_client(void * new_server_socket_to_client)
320 {
321     int new_server_socket = (int)new_server_socket_to_client;
322     int request = NO_COMMAND;
323     while(request!=EXIT)
324     {
325         chat_package buffer;
326         bzero((char*)&buffer,BUFFER_SIZE);
327         int length = recv(new_server_socket,(char*)&buffer,BUFFER_SIZE,0);
328         if (length < 0)
329         {
330             printf("Server Recieve Data Failed!\n");
331             close(new_server_socket);
332             pthread_exit(NULL);
333         }
334         if (length==0)
335         {
336             close(new_server_socket);
337             pthread_exit(NULL);
338         }      
339         request = process_request(new_server_socket, (char*)&buffer);
340     }
341     close(new_server_socket);
342     pthread_exit(NULL);      
343 }
344 
345 int main(int argc, char **argv)
346 {
347     init_user_table();
348     pthread_mutex_init(&user_table_mutex, NULL);
349     int server_socket = init_server_socket();
350 
351     pthread_t child_thread;
352     pthread_attr_t child_thread_attr;
353     pthread_attr_init(&child_thread_attr);
354     pthread_attr_setdetachstate(&child_thread_attr,PTHREAD_CREATE_DETACHED);
355     while (1)
356     {
357         struct sockaddr_in client_addr;
358         socklen_t length = sizeof(client_addr);
359         int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
360         if ( new_server_socket < 0)
361         {
362             printf("Server Accept Failed!\n");
363             break;
364         }
365         if( pthread_create(&child_thread,&child_thread_attr,talk_to_client, (void *)new_server_socket) < 0 )
366             printf("pthread_create Failed : %s\n",strerror(errno));
367     }
368     close(server_socket);
369     pthread_attr_destroy(&child_thread_attr);
370     pthread_mutex_destroy(&user_table_mutex);
371     pthread_exit (NULL);
372     return 0;
373 }

posted on 2009-04-01 23:34 季节 阅读(1310) 评论(0)  编辑 收藏 引用 所属分类: Linux编程

<2026年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿

文章分类

文章档案

搜索

  •  

最新评论