原帖地址: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编程