• 基于linux的聊天功能设计与实现


    目 录
    摘 要 i
    Abstract ii
    1 绪论 1
    1.1 研究背景及意义 1
    1.2 研究现状 1
    1.3 研究内容 2
    1.4 论文组织结构 2
    2 开发平台和相关技术简介 3
    2.1 嵌入式系统定义 3
    2.2 嵌入式Linux的主要特征 3
    2.3 QT的发展及编程机制 3
    2.4 TCP/IP协议简介 5
    2.5 Socket套接字简介 6
    2.6 C++语言简介 8
    3 可行性研究和需求分析 10
    3.1 可行性研究 10
    3.1.1 经济可行性分析 10
    3.1.2 技术可行性分析 10
    3.1.2 法律可行性分析 10
    3.2 需求分析 10
    3.2.1 用户需求 11
    3.2.2 功能需求 11
    3.2.3 性能需求 12
    4 系统的总体设计 13
    4.1 体系结构设计 13
    4.2 功能模块设计 13
    4.2.1 客户端功能模块的设计 14
    4.2.2 服务器端功能模块的划分 15
    4.2.3 数据库设计 15
    5 系统的详细设计及编码实现 16
    5.1 客户端实现 16
    5.1.1 连接服务器模块 17
    5.1.2 登陆模块 18
    5.1.3 注册模块 20
    5.1.4 私聊模块 22
    5.1.5 群聊模块 24
    5.1.6 设置字体模块 25
    5.2 服务器端实现 29
    5.2.1 服务器中数据库模块 29
    5.2.2 服务器模块实现 32
    6 系统使用简介和功能测试 35
    6.1 聊天系统使用介绍 35
    6.2 服务端编译 35
    6.3 客户端的编译 35
    6.4 系统启动测试 35
    6.4.1 服务端启动测试 36
    6.4.2 客户端启动测试 36
    6.4.3 性能测试 38
    结论 39
    参考文献 40
    致 谢 41
    外文原文 42
    中文翻译 53
    3.2 需求分析
    需求分析是软件开发的基础和前提,也是最终目标软件验收的标准,它可以避免或者尽早的剔除早期的错误。需求分析比较详细地对用户的需求进行了分析,更加精准、细致的回答了目标系统必须做什么。通常我们在进行软件开发的过程中,往往由于需求分析的不足,而最终导致项目的失败。据统计,超过60%的失败项目都是由于项目需求不明确或错误造成的,由此可见,需求分析是软件工程中的一个重要环节,是关乎软件项目开发成败的重要因素。现在的软件项目中返工开销几乎占了总开发的一般么人导致返工的主要原因是需求分析不明确。从而引发了想怒开发中的一些列更改。这些更改可能导致浪费大量的资源、软件项目无法按时完成等严重问题。所以,需求分析是软件设计和实现的基础,是软件项目卖相成功的重中之重。通过对问题及其环境的理解与分析,为问题设计的信息、功能及行为建立模型,将用户需求精确化、完全化,整个活动构成软件开发生命周期的需求分析阶段。
    3.2.1 用户需求
    互联网的普及,聊天工具已经成为人们日常的生活不可或缺的一部分。当今时代,即使通讯软件迅速发展,其聚集了娱乐资讯、社交、出行及聊天等强大的功能和拥有炫丽的图形界面,但同时软件的也体积也十分庞大,因此,用户希望研发一款软件不会拥有许多附加功能,软件体积较小。因此开发本系统也变得十分必需。根据用户对聊天功能的需求,主要可以概括为以下几点:
    1、操作简单方便,界面简洁。
    2、能够注册用户。
    3、拥有熟悉的聊天界面。
    4、能够进行私聊。
    5、能够进行群聊。
    6、运行稳定,安全可靠。
    3.2.2 功能需求
    根据对用户需求的分析和对产品的定位,该聊天系统要实现主要功能如下:
    1、启动服务端,可以在服务器的终端看到用户的相关信息。
    2、客户端可通过设置IP及端口号连接服务器。
    3、登陆界面有注册新用户的功能,实现用户注册。
    4、用户登陆时会自动核实用户名和密码是否匹配,不匹配会产生提示信息。
    5、登陆后进入界面,可以看到所有在线的用户。
    6、用户退出后会立即刷新在线用户列表。
    7、可以通过相关操作实现与在线用户进行私聊。
    8、实现与所有在线用户的群聊。
    9、聊天时可以更改字体颜色、大小及设置字体是否加粗、是否倾斜、是否加下划线。
    基于linux的聊天功能设计与实现的用例图如图3-1所示。
    在这里插入图片描述

    图3-1 聊天系统用例图
    3.2.3 性能需求
    首先要求程序运行稳定可靠,可以应付各种由于系统问题产生的错误,比如连接失败等,要求提前设想到类似的尽可能多的可能发生的事件,做出相应的应对措施,并向用户显示相应的提示信息。
    同时作为嵌入式平台下的应用软件,要求程序对所运行至系统的硬件要求尽可能低,运行时内存占用尽可能小,响应速度要尽可能快。并且不发生内存泄露之类影响系统运行的错误事件。并且要求易于维护及扩展。所以采取模块化封装。程序要有良好的容错性,当用户进行非法操作时或者系统本身出问题是要能以最好的方式退出程序,避免程序假死现象。

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "mysql.h"
    using namespace std;
    
    int sockfd;
    MYSQL *conn_ptr;
    vector<int> fdVector;
    vector<int>idVector;
    
    void* do_service(void *arg)
    {
    	int fd=(int)arg;
    	char buff[1024] = {0};
        	char msg[1024];
     
        	int res = -1;
        	while(1){
            	memset(buff,0,sizeof(buff));
           		memset(msg,0,sizeof(msg));
    
            	res = read(fd,buff,sizeof(buff));
            	if(res < 0){
    
            	}else if(res == 0){
    
            	}else{
    			char *delim=":";
    			char *delim2="#";
               	 	//1.查看登录信息是否正确
                		if(strstr(buff,"#Login:") != NULL){//协议#Login:username:passwd
    			strtok(buff,delim);
    			char* id=strtok(NULL,delim);
    			char *passwd=strtok(NULL,delim);
    			memset(msg,0,sizeof(msg));
    			int rel_id=atoi(id);
    			if((res=check(conn_ptr,rel_id,passwd))>0)
    			{	idVector.push_back(rel_id);
    				fdVector.push_back(fd);
    				sprintf(msg,"@@@@check:Ok####");
    				if(write(fd,msg,strlen(msg))!=strlen(msg))
    					fprintf(stderr,"write check:ok error!");
    				if(updateState(conn_ptr,rel_id,1)<0)
    					fprintf(stderr,"update state fail!");
    				printf("########################################\n");
    				
    				printf("%s(%d) login success!\n",query(conn_ptr,rel_id),rel_id);
    				vector<int>::iterator iter = fdVector.begin();
    				for(iter; iter != fdVector.end(); ++iter)
    				{
    					if(*iter!=fd)
    					{
    						memset(msg,0,sizeof(msg));					
    						sprintf(msg,"@@@@onlineList:%s####",queryList(conn_ptr));
    						if(write(*iter,msg,strlen(msg))!=strlen(msg))
    							fprintf(stderr,"update online list error when login!\n");
    					}
    				}
    			
    			}else
    			{
    				sprintf(msg,"@@@@check:NO####");
    				if(write(fd,msg,strlen(msg))!=strlen(msg))
    					fprintf(stderr,"write check:No error!");
    			printf("########################################\n");
    			printf("%s(%d) login failed!\n",query(conn_ptr,rel_id),rel_id);
    			}//end if-else
    			}//end 1.
    			else if(strstr(buff,"#Submit:")!=NULL)//2.注册新用户,协议#Submit:nickName:password:age:birthday:state(0)
    			{
    				memset(msg,0,sizeof(msg));
    				strtok(buff,delim);
    				char *username=strtok(NULL,delim);
    				char *passwd=strtok(NULL,delim);
    				char *age=strtok(NULL,delim);
    				char *birthday=strtok(NULL,delim);
    				sprintf(msg,"%s|%s|%s|%s|%d",username,passwd,age,birthday,0);
        				if((res=insert(conn_ptr,msg))>0)
    				{
    					memset(msg,0,sizeof(msg));
    					sprintf(msg,"@@@@id:%d####",res);
    					if(write(fd,msg,strlen(msg))!=strlen(msg))
    						fprintf(stderr,"write error!\n");
    				printf("%s用户注册成功\n",username);
    				}//end if
    			}//end 2
    			else if(strstr(buff,"#GetList:")!=NULL)//3.获得在线用户列表信息
    			{
    				memset(msg,0,sizeof(msg));					
    				sprintf(msg,"@@@@onlineList:%s####",queryList(conn_ptr));
    				if(write(fd,msg,strlen(msg))!=strlen(msg))
    				fprintf(stderr,"write error!\n");
    				printf("在线用户列表:%s\n",queryList(conn_ptr));
    			}//end 3
    			else if(strstr(buff,"#Chat:"))//4.发送聊天信息
    			{
    				memset(msg,0,sizeof(msg));
    				strtok(buff,delim);
    				int id=atoi(strtok(NULL,delim));
    				char *nickName=query(conn_ptr,id);
    				strcpy(msg,strtok(NULL,delim2));
    				printf("%s(%d) 发送消息:%s\n",nickName,id,msg);
    				char temp[1024]={'\0'};
    				memset(temp,0,sizeof(temp));
                            	sprintf(temp,"@@@@Chat:%s(%d):%s####",nickName,id,msg);
                            	strcpy(msg,temp);
    				vector<int>::iterator iter = fdVector.begin();
    				for(iter; iter != fdVector.end(); ++iter)
    				{		
                            		if(write(*iter,msg,strlen(msg))!=strlen(msg))
    						fprintf(stderr,"chat conten send fail!\n");;
    				}
    				
    			}//end 4
    			else if(strstr(buff,"#Private:"))//5.私聊,协议#Private:sendId:recvId:msg:isbold:isItalic:isUnderline:font:size:r:g:b#
    			{
    				memset(msg,0,sizeof(msg));
    				strtok(buff,delim);
    				int sendId=atoi(strtok(NULL,delim));
    				int recvId=atoi(strtok(NULL,delim));
    				char temp[1024];
    				memset(temp,0,sizeof(temp));
    				strcpy(temp,strtok(NULL,delim2));
    				printf("%d 向 %d 发送消息:%s\n",sendId,recvId,temp);
    				sprintf(msg,"@@@@Chat:%s(%d):%s####",query(conn_ptr,sendId),sendId,temp);
    				int i;
    				for(i=0;i<idVector.size();i++)		
    				{
    					if(idVector.at(i)==recvId)
    						break;
    				}
    	
                            	if(write(fdVector.at(i),msg,strlen(msg))!=strlen(msg))
    					fprintf(stderr,"chat conten send fail!\n");;
    				if(write(fd,msg,strlen(msg))!=strlen(msg))
    					fprintf(stderr,"chat conten send fail!\n");;
    				
    			}
    			else if(strstr(buff,"#Close:"))//6.关闭聊天窗口,该用户state=0;
                    	{
    				memset(msg,0,sizeof(msg));
    				strtok(buff,delim);
    				int id=atoi(strtok(NULL,delim));
    				if((res=updateState(conn_ptr,id,0))>0)
    				{
    					memset(msg,0,sizeof(msg));
    					sprintf(msg,"@@@@close:%d####",id);
    					if(write(fd,msg,strlen(msg))!=strlen(msg))
    						fprintf(stderr,"write error!\n");
    					printf("%s 退出系统\n",query(conn_ptr,id));
    					printf("########################################\n");
    					vector<int>::iterator iter = fdVector.begin();
    					vector<int>::iterator iterTemp;
    					for(iter; iter != fdVector.end(); ++iter)
    					{
    						if(*iter==fd)
    						{
    						iterTemp=iter;
    						//fdVector.erase(iter);
    						continue;
    						}
    						
    						memset(msg,0,sizeof(msg));					
    						sprintf(msg,"@@@@onlineList:%s####",queryList(conn_ptr));
    						if(write(*iter,msg,strlen(msg))!=strlen(msg))
    							fprintf(stderr,"write error:%s!\n",msg);
    						
    					}
    					//~~~~~~~~~~~~~~~~~~~~~~~~~~
    					fdVector.erase(iterTemp);
    				}//end if
    				
    			}//else 6
               	}//end else
    	}//end while
    	
        return (void*)0;
    }
    
    //信号处理函数
    void sig_handler(int signo)
    {
    	if(signo==SIGINT)
    	{
    		close(sockfd);
    		mysql_close(conn_ptr);
    		printf("service will be closed....\n");
    		exit(1);
    	}
    }
    
    int main(int argc,char* argv[])
    {
        /*
        if(argc<2)
        {
            fprintf(stderr,"usage: %s port\n",argv[0]);
        }*/
        /* 1. 创建数据库并连接*/
        conn_ptr=(MYSQL*)malloc(sizeof(MYSQL));
        mysql_init(conn_ptr);
        if (!conn_ptr)
        {
            fprintf(stderr,"mysql_init failed\n");
            return EXIT_FAILURE;
        }
        //连接到mysql服务器,参数为:handle,host,user,password,database,port,socket,client_flag
        conn_ptr = mysql_real_connect(conn_ptr,"localhost","root",\
                                  "mysql","test",0,NULL,0);
        if (!conn_ptr)
        {
            fprintf(stderr,"Connection failed\n");
        }else
        {
            printf("MySql connect correct\n");
        }
      /*  create_table(conn_ptr);
       char data[]="group|group|22|1993-09-11|0";
        insert(conn_ptr,data);
       /query(conn_ptr,1612975487);
        check(conn_ptr,"group","group");*/
    
    	fdVector.clear();
    	idVector.clear();
    
        /*2. 创建socket建立网络连接*/
        //信号处理
            if(signal(SIGINT,sig_handler)==SIG_ERR)
    	{
    		fprintf(stderr,"signal:%s\n",strerror(errno));
    		exit(1);
    	}
    	if(signal(SIGPIPE,SIG_IGN)==SIG_ERR)
    	{
    			fprintf(stderr,"ignor sigpipe");
    			exit(1);
    	}
            //初始化服务器地址
            sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(sockfd<0)
            {
                fprintf(stderr,"socket wrong");
            }
            struct sockaddr_in addr;
            memset(&addr,0,sizeof(addr));
            addr.sin_family=AF_INET;
            addr.sin_port=htons(8080);
         //   addr.sin_port=htons(atoi(argv[1]));
            addr.sin_addr.s_addr=INADDR_ANY;
            int ret;
            //绑定
            if((ret=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)))<0)
            {
                fprintf(stderr,"bind :%s\n",strerror(errno));
                exit(1);
            }
            //监听
            if((ret=listen(sockfd,10))<0)
            {
                fprintf(stderr,"listen:%s\n",strerror(errno));
                exit(1);
            }
            //设置线程分离属性
            pthread_attr_t attr;
            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);	
    
            while(1)
            {
                struct sockaddr_in clientaddr;
                memset(&clientaddr,0,sizeof(clientaddr));
                socklen_t len=sizeof(clientaddr);
                int fd=accept(sockfd,(struct sockaddr*)&clientaddr,&len);
                if(fd<0)
                {
    			fprintf(stderr,"accept:%s\n",strerror(errno));
    			continue;
                }
                //创建新线程
                pthread_t pth2;
                int err;
    	    //fdVector.push_back(fd);
                if((err=pthread_create(&pth2,&attr,do_service,(void*)fd))<0)
                {
    			fprintf(stderr,"pthread_creat:%s\n",strerror(err));
    			continue;
                }
    
            }
    
        pthread_attr_destroy(&attr);
        mysql_close(conn_ptr);
        close(sockfd);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    kotlin 之几个常见的内联函数(二)
    WebGL 的 Hello World
    [附源码]java毕业设计期刊在线投稿平台
    基础SSM框架搭建
    LeetCode150. 逆波兰表达式求值
    c语言练习46:模拟实现strncpy
    实力认证!Coremail连续9次入围安全牛《中国网络安全行业全景图》
    MyBatis 关于查询语句上配置的详细内容
    单片机毕业设计-基于单片机的运动手环
    react-严格模式
  • 原文地址:https://blog.csdn.net/newlw/article/details/128114368