基于socket的聊天系统设计.doc_第1页
基于socket的聊天系统设计.doc_第2页
基于socket的聊天系统设计.doc_第3页
基于socket的聊天系统设计.doc_第4页
基于socket的聊天系统设计.doc_第5页
免费预览已结束,剩余21页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

网络程序设计课程设计基于socket的聊天系统设计摘要:本设计通过研究讨论,设计了基于socket编程的网络聊天系统,并且通过验证与测试,证明了系统的可用性、易用性、完善性。关键词:socket、server、client、聊天系统引言:socket通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过套接字向网络发出请求或者应答网络请求。一、开发原理服务器:使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。 客户端:使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。二、实现目标根据客户机提出各种请求,服务器能够根据不同请求,发送不同的响应,最终实现服务器端与客户机端的聊天功能。三、设计实现过程(一)/*chat.h* 基于socket的聊天客户机和服务器的头文件* Copyright by Subo, All Right Reserved*设计思路:* 客户机提出各种请求,服务器根据不同请求,发送不同的响应.*关键问题:* 客户机和服务器之间协议制订*/#include / for sockaddr_in#include / for socket#include / for socket#include / for printf#include / for exit#include / for bzero/*服务器端口定义*/#define CHAT_SERVER_PORT (6666)/*报文类型定义*/#define NO_COMMAND (100)/客户端发送报文类型#define REGISTER (1)#define LOGIN (2)#define GET_USER_LIST (3)#define TALK_TO (4)#define EXIT (5)#define CHANGE (6)#define GET_MESSAGE (7)/服务器端发送报文类型#define SUCCEED (0)#define FAIL (-1)#define TRANSFER (80)/*报文格式定义*/#define COMMAND_SIZE (sizeof(char)#define OPTION_SIZE (16)#define ID_SIZE (OPTION_SIZE)#define PASSWORD_SIZE (OPTION_SIZE)#define MESSAGE_SIZE (1024)typedef struct chat_package signed char type; char fromID_SIZE +1; char passwordPASSWORD_SIZE +1; char optionOPTION_SIZE +1; char toID_SIZE + 1; char messageMESSAGE_SIZE +1;chat_package;#define BUFFER_SIZE (sizeof(chat_package)/*选项分类:* 用户列表 */#define USER_LIST USER_LIST(二)/*一个基于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_IDUSER_ID_SIZE; char passwordPASSWORD_SIZE; int client_socket; /client_socket=NOT_LOGIN,表示没有用户登录, /client_socket=NOT_IN_USE,表示没有用户注册, user;/多线程共享user_tablestatic user user_tableUSER_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_MAXMESSAGE_SIZE) printf(USER_ID_SIZE*USER_AMOUNT_MAXMESSAGE_SIZEn); exit(1); int i=0; for(i=0;iUSER_AMOUNT_MAX;i+) user_tablei.client_socket = NOT_IN_USE; bzero(user_tablei.user_ID,OPTION_SIZE); bzero(user_tablei.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;iUSER_AMOUNT_MAX;i+) if( (strcmp(user_tablei.user_ID,user_ID)=0) &(strcmp(user_tablei.password,password)=0) ) user_tablei.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 NOT_LOGIN) memcpy(user_list_buffer, user_tablei.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;iUSER_AMOUNT_MAX;i+) if(strcmp(user_tablei.user_ID,user_ID)=0) pthread_mutex_unlock(&user_table_mutex); return FAIL; for(i=0;iUSER_AMOUNT_MAX;i+) if(NOT_IN_USE = user_tablei.client_socket) user_tablei.client_socket = NOT_LOGIN; memcpy(user_tablei.user_ID,user_ID,USER_ID_SIZE); memcpy(user_tablei.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=0) socket = user_tablei.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;iUSER_AMOUNT_MAX;i+) if(user_tablei.client_socket = client_socket) user_tablei.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;iUSER_AMOUNT_MAX;i+) if(strcmp(user_tablei.user_ID,user_ID)=0) pthread_mutex_unlock(&user_table_mutex); return FAIL; for(i=0;iUSER_AMOUNT_MAX;i+) if(client_socket = user_tablei.client_socket) memcpy(user_tablei.user_ID,user_ID,USER_ID_SIZE); memcpy(user_tablei.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 from; char * password = (chat_package *)receive_buffer)-password; char * receiver = (chat_package *)receive_buffer)-to; printf(Request %d from clientn,(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 clientn,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 : %sn,strerror(errno); close(server_socket); pthread_attr_destroy(&child_thread_attr); pthread_mutex_destroy(&user_table_mutex); pthread_exit (NULL); return 0;(三)/* 基于socket的聊天客户机* Copyright by Subo, All Right Reserved*设计思路:* 客户机提出各种请求,服务器根据不同请求,发送不同的响应.*关键问题:* 客户机和服务器之间协议制订*/#include chat.h#include / for fork#include / for signal#include / for wait#include static char user_IDBUFFER_SIZE; /一个很大的缓冲区,实际ID_SIZE内有效static char passwordBUFFER_SIZE; /一个很大的缓冲区,实际PASSWORD_SIZEE内有效static int client_socket;/*函数名称: connect_to_server*正常返回值: 连接到服务器的socket*函数执行失败: 连接失败返回值为 -1,向控制台输出错误信息*依赖自定义数据结构: 无*/int connect_to_server(char * server_IP_addr) /设置一个socket地址结构client_addr,代表客户机internet地址, 端口 struct sockaddr_in client_addr; bzero(&client_addr,sizeof(client_addr); /把一段内存区的内容全部设置为0 client_addr.sin_family = AF_INET; /internet协议族 client_addr.sin_addr.s_addr = htons(INADDR_ANY);/INADDR_ANY表示自动获取本机地址 client_addr.sin_port = htons(0); /0表示让系统自动分配一个空闲端口 /创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket client_socket = socket(AF_INET,SOCK_STREAM,0); if( client_socket 0) printf(Create Socket Failed!n); return FAIL; /把客户机的socket和客户机的socket地址结构联系起来 if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr) printf(Client Bind Port Failed!n); return FAIL; /设置一个socket地址结构server_addr,代表服务器的internet地址, 端口 struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr); server_addr.sin_family = AF_INET; if(inet_aton(server_IP_addr,&server_addr.sin_addr) = 0) /服务器的IP地址来自程序的参数 printf(Server IP Address Error!n); return FAIL; server_addr.sin_port = htons(CHAT_SERVER_PORT); socklen_t server_addr_length = sizeof(server_addr); /向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接 if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) 0) printf(Can Not Connect To %s!n,server_IP_addr); return FAIL; return SUCCEED;/*函数名称: send_request_to_server*正常返回值: 发送到服务器的报文的字节数*函数执行失败: 发送失败返回值为 -1*参数说明: 当不使用option时, option应当是NULL* 当不使用message时, message应当是NULL*依赖自定义数据结构: chat_package -chat.h*/void send_request_to_server(signed char request, char * option, char * to, char * message) static chat_package buffer; bzero(char*)&buffer,BUFFER_SIZE); buffer.type = request; memcpy(buffer.from, user_ID, ID_S

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论