简易聊天室四 注册用户

来源:互联网 发布:ubuntu连接wifi命令 编辑:程序博客网 时间:2024/05/11 16:37

  简易聊天室四  注册用户

断断续续几天的功夫,终于把注册用户的功能加好了,真的是好就没有写程序了,这几天把数据库的知识又好好的复习了一下,想着是赶紧给大家带来这篇博客,自己在学习过程中遇到的东西,也希望和大家分享一下。
在前几章的博客中,我们搭建好了TCP/IP框架,分析了线程和界面,今天开始,我们就要开始往程序中写功能了。就像QQ一样,一切的功能伊始,首先得注册一个用户,对于用户注册信息的存储和维护,对后面的其他功能,都起到了至关重要的作用。
一.sqlite3数据库
SQLite,是一款轻型的数据库,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。我们使用它的最新版——sqlite3。
在使用sqlite3之前,先让我们看看应该如何安装:

1.去sqlite主页http://www.sqlite.org/.跳转到下载也http://www.sqlite.org/download.html。源码下载sqlite-amalgamation-3.7.3.tar.gz

2.进入下载目录,解压文件tar -zxvf sqlite-amalgamation-3.7.3.tar.gz. 解压后生成sqlite-3.7.3目录. cd 进入sqlite-3.7.3。

3./configure

make

sudo make install

安装完成。

sqlite3给我提供了很多的接口函数供我们使用,使我们在程序中可以很方便的创建,插入,查询,删除数据库,下面是几个常见的功能,我把代码贴出来:

#include <stdio.h>#include <sqlite3.h>#include <unistd.h>#include <stdlib.h>#include <string.h>int callback(void *arg,int n,char**result,char**name){int i = 0;for(i = 0 ; i < n ; i++){if(strcmp(name[i],"id") == 0  ){printf("%s\n",result[i]);}}return 0;}int main(){sqlite3 *db;char *errmsg;sqlite3_open("newdb.db",&db);//创建/打开数据库/**/char sql[128];char name[10] = {0};memset(sql, '\0', 128);  sprintf(sql, "%s%s%s", "create table ", "test_tb","(id INTEGER PRIMARY KEY, data TEXT);"); //创建表格sqlite3_exec(db, sql, NULL, NULL, &errmsg);printf("%s\n",errmsg);/**/memset(sql, '\0', 128);  sprintf(sql,"%s%s%s","insert into ","test_tb(id,data)","values(19,'shijie')");   //插入一组数据sqlite3_exec(db, sql, NULL, NULL, NULL);        sprintf(sql,"%s%s%s","insert into ","test_tb(id,data)","values(22,'shichengcheng')");   //插入一组数据sqlite3_exec(db, sql, NULL, NULL, NULL);sprintf(sql,"%s%s%s","insert into ","test_tb(id,data)","values(24,'songtao')");   //插入一组数据sqlite3_exec(db, sql, NULL, NULL, NULL);/**/memset(sql, '\0', 128);  sprintf(sql,"update test_tb set id=22,data='fyb'where id=21");   //索引修改一组数据sqlite3_exec(db, sql, NULL, NULL, NULL);/**/memset(sql, '\0', 128);  sprintf(sql,"delete from test_tb where id=19");   //索引删除一组数据sqlite3_exec(db, sql, NULL, NULL, NULL);/**/    //sqlite3_exec(db, "drop table test_tb", NULL, NULL, NULL);  //删除数据表  /**/char ** azResult;  //sqlite3_get_table()解析数据库int nrow = 0;int ncolumn = 0;sqlite3_get_table(db ,"select * from test_tb" , &azResult , &nrow , &ncolumn , &errmsg);printf("nrow = %d, ncolumn = %d\n",nrow,ncolumn);printf("msg = %s\n",errmsg);printf("%s|%s\n",*(azResult+0),*(azResult+1));printf("%s|%s\n",*(azResult+2),*(azResult+3));printf("%s|%s\n",*(azResult+4),*(azResult+5));printf("%s|%s\n",*(azResult+6),*(azResult+7));sqlite3_free_table( azResult );printf("\n\n\n");/**/sqlite3_exec(db, "select * from test_tb",callback, NULL, NULL);sqlite3_close(db);return 0;}
对于最后一个遍历数据库
sqlite3_exec(db, "select * from test_tb",callback, NULL, NULL);
等于就是我们下达“select * from test_tb”命令,使之遍历数据库,然后我们传入一个回调函数,在它遍历数据库的过程,我们乘机寻找我们需要找的东西,在这里面,有一点一定要牢记,callback函数一定要加return 0;否则,遍历不会成功,读者可以复制程序后删除语句后试试。
数据库其他的东西,就是通过sqlite语句调用sqlite3_exec函数执行函数的传入数(据库指针,sqlite语句,回调函数(也可以null),回调函数实参,错误信息输出)。大家可以通过程序,多加训练。

二.枚举enum{};

枚举enum介绍

在这里,博主主要想给大家传达一个思想,对于一个大型程序,难免会有很多的分支选择程序,判断执行。最典型的就是switch case;很多童鞋一开始写程序,满篇程序都是幻数,如果-1,执行什么,如果是3,执行什么,这样子写程序,不仅调理不清,而且给其他人甚至自己日后读取程序都加大难度。

 enum {LOG,REG}; //登录 注册 enum {OK,NO};   
三.信息包用同一个结构体

这个是方便我们开发程序,我们在进行通讯的时候,会发送不同类型的数据,发送id,发送name,发送聊天内容,有的时候发送数据还不止一种,所以,使用一个统一的数据库,很大程度上可以使我们少去烦恼我们怎么打包发送。

myhead.h

#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <unistd.h>#include <pthread.h>#include <sqlite3.h>#include <time.h> enum {LOG,REG};enum {OK,NO};typedef struct chat_b           //目前只需要这些,以后会逐一增加{int action;char regName[10];char regPassword[30];long logId;char logPassword[30];int ack;}chat_t;


下面是各主程序

客户端:

welcome.c

#include "myhead.h"void welcome(void){system("clear");printf("\n\n\n\n\n\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t    简易聊天室  \t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\n\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t  A:  Log  \t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t  B:  Reg  \t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t\t\t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t  C:  Exi  \t\t\t\t\033[0m\n");printf("\t\t\t\t\t\033[47;34m\t\t\t \t\t\t\t\t\033[0m\n");}int Log(int clientfd,chat_t *client_struct);int reg(int clientfd,chat_t *client_struct);void welcome_menu(int clientfd,chat_t *client_struct){char welc_choice[10];wel:memset(welc_choice,0,sizeof(welc_choice));welcome();printf("请输入您的选择:");scanf("%s",welc_choice);if(strcmp("Log",welc_choice) == 0){//printf("in Log\n");Log(clientfd,client_struct);}else if(strcmp("Reg",welc_choice) == 0){//printf("in Reg\n");reg(clientfd,client_struct);}else if(strcmp("Exi",welc_choice) == 0){//printf("in Exi\n");exit(0);}else{//printf("error\n");printf("输入无效指令(Log,Reg,Exi)\n");goto wel;sleep(2);}sleep(2);goto wel;}int Log(int clientfd,chat_t *client_struct){//write(clientfd,"Log",3);client_struct->action = LOG;write(clientfd,client_struct,sizeof(chat_t));}int reg(int clientfd,chat_t *client_struct){//write(clientfd,"reg",3);char stmPassword[30];srand((unsigned) time(NULL));reg:client_struct->action = REG;printf("请输入您的昵称:\n");scanf("%s",client_struct->regName);if(strcmp("admin",client_struct->regName) == 0){printf("管理员无法被注册\n");memset(client_struct,0,sizeof(chat_t));goto reg;}printf("请输入您的密码:\n");scanf("%s",client_struct->regPassword);printf("请确认您的密码:\n");scanf("%s",stmPassword);if(strcmp(stmPassword,client_struct->regPassword) == 0){client_struct->logId = rand() % 100000;write(clientfd,client_struct,sizeof(chat_t));read(clientfd,client_struct,sizeof(chat_t));if(client_struct->ack == OK){}else{printf("昵称已存在!\n");memset(client_struct,0,sizeof(chat_t));goto reg;}printf("请记住您的ID:%d\n",client_struct->logId);sleep(4);}else{memset(client_struct,0,sizeof(chat_t));memset(stmPassword,0,sizeof(stmPassword));goto reg;}}

main.c

#include "./myhead.h"#define PORT 8900extern void welcome(void);extern void welcome_menu(int client_fd,chat_t *client_struct);int main(char argc, char **argv){int clientfd = socket(AF_INET,SOCK_STREAM,0);chat_t client_struct = {0};if(clientfd < 0){fprintf(stderr,"socketfd failed");}struct sockaddr_in server_addr;memset(&server_addr,0,sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;        server_addr.sin_port = htons(8900);        server_addr.sin_addr.s_addr = htons(INADDR_ANY);if(-1 ==connect(clientfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))){printf("connect failed!\n");close(clientfd);return -1;}welcome_menu(clientfd,&client_struct);//while(1);close(clientfd);return 0;}

服务器

client_thread.c

#include "../client/myhead.h"int Log(int client_fd,chat_t *chat_struct);int reg(int client_fd,chat_t *chat_struct);sqlite3 *db;chat_t *client_struct;int callback_reg(void *arg,int n,char**result,char**name); void *client_thread(void *arg){int client_fd = *(int *)arg;//取出accept_fd,用于信息的传输chat_t chat;client_struct = &chat;  // 如果没有这句,client_struct 是野指针//char rev_buf[20] = {0};int i = 0;//printf("%d\n",client_fd);//while(i--)//{//read(client_fd,rev_buf,20);//printf("%s\n",rev_buf);//memset(rev_buf,0,20);//}sqlite3_open("client_db",&db);sqlite3_exec(db, "create table client_tb (id INTEGER PRIMARY KEY, name TEXT,passward TEXT,online INTEGER);", NULL, NULL, NULL);while(1){memset(client_struct,0,sizeof(chat_t));read(client_fd,client_struct,sizeof(chat_t)); // read(client_fd,client_struct,sizeof(client_struct)); 指针和指针内容printf("%s\n%s\n",client_struct->regName,client_struct->regPassword);printf("%d,i=%d,fd=%d\n",client_struct->action,i++,client_fd);switch(client_struct->action){case LOG:Log(client_fd,client_struct);break;case REG:reg(client_fd,client_struct);break;default:break;}}}int Log(int client_fd,chat_t *chat_struct){//printf("Log\n");}int reg(int client_fd,chat_t *chat_struct){//printf("Reg\n");char sql[100] = {0};chat_struct->ack = OK;sqlite3_exec(db,"select * from client_tb",callback_reg,chat_struct,NULL);write(client_fd,chat_struct,sizeof(chat_t));if(chat_struct->ack == NO){return 0;}sprintf(sql,"insert into client_tb(id, name,passward,online)values(%d,'%s','%s',0)",chat_struct->logId,chat_struct->regName,chat_struct->regPassword);sqlite3_exec(db,sql,NULL,NULL,NULL);}int callback_reg(void *arg,int n,char**result,char**name){chat_t *p =  (chat_t*)arg;int i = 0;for(i = 0 ; i < n ; i++){if(strcmp(name[i],"name") == 0  ){if(strcmp(p->regName,result[i]) == 0){p->ack = NO;}}}return 0;}

main.c


#include "../client/myhead.h"extern void*client_thread(void*arg);int main(char argc,char **argv){int sockfd = socket(AF_INET,SOCK_STREAM,0); //AF_INET=IPV4; SOCK_STREAM 流传输if(sockfd < 0){fprintf(stderr,"server socket failed!\n"); //stderr 标准错误输出return -1;}struct sockaddr_in server_addr;memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8900);server_addr.sin_addr.s_addr = htons(INADDR_ANY);bzero(&(server_addr.sin_zero),0);if(bind(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) < 0){fprintf(stderr,"bind failed!\n");return -1;}if(listen(sockfd,7) < 0){perror("listen failed!");return -1;}struct sockaddr_in client_addr;int accept_fd;char buff[5] = {0};pthread_t  client_fd;socklen_t client_len = sizeof(struct sockaddr);while(1){accept_fd = accept(sockfd,(struct sockaddr *)&client_addr,&client_len);int *p;*p = accept_fd;pthread_create(&client_fd,NULL,client_thread,(void *)p);pthread_detach(client_fd);}close(sockfd);return 0;}

在写程序的时候,我遇到了两个问题,卡了我一些时间一个是野指针,一个是指针和指针内容

   
0 0
原创粉丝点击