Socket网络编程--聊天程序(7)

  接上一小节,本来是计划这一节用来讲数据库的增删改查,但是在实现的过程中,出现了一点小问题,也不是技术的问题,就是在字符界面上比较不好操作。比如要注册一个帐号,就需要弄个字符界面提示,然后输入数字表示选择,在依次输入信息。(这一点,用C写过什么管理系统就知道,很是麻烦。)考虑到本程序讲的是网络编程,就不弄增删改查了,就判断一个用户名密码是否正确就行了。

  首先是安装mysql和创建数据库,所用到的命令如下:

1 su root  //使用root用户
2 yum install mysql-devel*
3 yum install mysql-server*
4 service mysqld start

  创建一个users数据库和一个client表

1 $mysql -u root
2 mysql> create database users;
3 mysql> use users;    //切换到users数据库中
4 mysql> create table clients(id int,username varchar(32),password varchar(32) ); //创建一个叫test的表
5 mysql> show create table clients;  //显示刚才创建的表信息
6 mysql> select * from clients;   //查询client表中数据
7 mysql> quit

  1.插入数据

 1 #include <stdio.h>
 2 #include <mysql.h>
 3 #include <stdlib.h>
 4
 5 #define HOST "localhost"
 6 #define USERNAME "root"
 7 #define PASSWORD ""
 8 #define DATABASE "users"
 9
10 int main(int argc,char *argv[])
11 {
12     MYSQL conn;
13     int res;
14     char *sql="insert into clients values(‘1‘,‘user1‘,‘123456‘);";
15     mysql_init(&conn);
16
17     if(mysql_real_connect(&conn,HOST,USERNAME,PASSWORD,DATABASE,0,NULL,CLIENT_FOUND_ROWS))
18     {
19         printf("Connect Success!\n");
20         res=mysql_query(&conn,sql);
21         if(res)
22         {
23             printf("Insert Error!\n");
24         }
25         else
26         {
27             printf("Insert Success!\n");
28         }
29     }
30     else
31     {
32         printf("Connect Failed!\n");
33         exit(-1);
34     }
35     return 0;
36 }

  2.删除数据

 1 #include <stdio.h>
 2 #include <mysql.h>
 3 #include <stdlib.h>
 4
 5 #define HOST "localhost"
 6 #define USERNAME "root"
 7 #define PASSWORD ""
 8 #define DATABASE "users"
 9
10 int main(int argc,char *argv[])
11 {
12     MYSQL conn;
13     int res;
14     char *sql="delete from clients where username=\"user1\";";
15
16     mysql_init(&conn);
17
18     if(mysql_real_connect(&conn,HOST,USERNAME,PASSWORD,DATABASE,0,NULL,CLIENT_FOUND_ROWS))
19     {
20         printf("Connect Success!\n");
21         res=mysql_query(&conn,sql);
22         if(res)
23         {
24             printf("Delete Error!\n");
25         }
26         else
27         {
28             printf("Delete Success!\n");
29         }
30     }
31     else
32     {
33         printf("Connect Failed!\n");
34         exit(-1);
35     }
36     return 0;
37 }

  3.修改数据

 1 #include <stdio.h>
 2 #include <mysql.h>
 3 #include <stdlib.h>
 4
 5 #define HOST "localhost"
 6 #define USERNAME "root"
 7 #define PASSWORD ""
 8 #define DATABASE "users"
 9
10 int main(int argc,char *argv[])
11 {
12     MYSQL conn;
13     int res;
14     char *sql="update clients set username=\"user2\" where username=\"user1\";";
15     mysql_init(&conn);
16
17     if(mysql_real_connect(&conn,HOST,USERNAME,PASSWORD,DATABASE,0,NULL,CLIENT_FOUND_ROWS))
18     {
19         printf("Connect Success!\n");
20         res=mysql_query(&conn,sql);
21         if(res)
22         {
23             printf("Update Error!\n");
24         }
25         else
26         {
27             printf("Update Success!\n");
28         }
29     }
30     else
31     {
32         printf("Connect Failed!\n");
33         exit(-1);
34     }
35     return 0;
36 }

  4.查询数据

 1 #include <stdio.h>
 2 #include <mysql.h>
 3 #include <stdlib.h>
 4
 5 #define HOST "localhost"
 6 #define USERNAME "root"
 7 #define PASSWORD ""
 8 #define DATABASE "users"
 9
10 int main(int argc,char *argv[])
11 {
12     MYSQL conn;
13     MYSQL_RES *res_ptr;//指向查询结果的指针
14     MYSQL_FIELD *field;//字段结构体指针
15     MYSQL_ROW result_row;//按行返回的查询信息
16
17     int res;
18     int i,j;
19     int row,column;//查询返回的行数和列数
20     char *sql="select * from clients;";
21     mysql_init(&conn);
22
23
24     if(mysql_real_connect(&conn,HOST,USERNAME,PASSWORD,DATABASE,0,NULL,CLIENT_FOUND_ROWS))
25     {
26         printf("Connect Success!\n");
27         res=mysql_query(&conn,sql);
28         //res=0表示查询成功
29         if(res)
30         {
31             printf("Select Error!\n");
32         }
33         else
34         {
35             printf("Select Success!\n");
36             //将查询的结果给res_ptr
37             res_ptr=mysql_store_result(&conn);
38             //如果结果不为空,就可以输出了
39             if(res_ptr)//可以用这个的真假来判断用户名密码是否正确
40             {
41                 //有结果了
42                 column=mysql_num_fields(res_ptr);//获取列数
43                 row=mysql_num_rows(res_ptr)+1;//加1是因为第一行是字段名
44                 printf("查询到的数据有 %d 行\n",row);
45
46                 //输出结果的字段名
47                 for(i=0;field=mysql_fetch_field(res_ptr);i++)
48                 {
49                     printf("%s\t",field->name);
50                 }
51                 printf("\n");
52                 //按行输出结果
53                 for(i=1;i<row;i++)
54                 {
55                     result_row=mysql_fetch_row(res_ptr);
56                     for(j=0;j<column;j++)
57                     {
58                         printf("%s\t",result_row[j]);
59                     }
60                     printf("\n");
61                 }
62             }
63             else
64             {
65                 //没有结果
66                 printf("没有查询到匹配的数据。");
67             }
68         }
69     }
70     else
71     {
72         printf("Connect Failed!\n");
73         exit(-1);
74     }
75     mysql_close(&conn);
76     return 0;
77 }

  对应的makefile

1 main:
2         gcc insert.c `mysql_config --cflags --libs` -o insert
3         gcc delete.c `mysql_config --cflags --libs` -o delete
4         gcc update.c `mysql_config --cflags --libs` -o update
5         gcc select.c `mysql_config --cflags --libs` -o select

  由于本次的重点不是数据库的操作,所以就简单的给出常用的基本方法,在我们的聊天程序中只加入查询用户密码的功能,其他的如注册用户什么的就不写了,应该没有什么难度,就是有点烦。

  加入数据库连接后的聊天程序

  client.c 不变

  server.c 修改如下

  ...
 17 #include <mysql.h>//用于mysql连接
 18
  ...  37
 38 void print_time(char * ch,time_t *now)
 39 {
 40     struct tm*stm;
 41     stm=localtime(now);//立即获取当前时间
 42     sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec);
 43 }
 44
 45 int mysql_check_login(struct user su)
 46 {
 47     MYSQL conn;
 48     MYSQL_RES *res_ptr;
 49     int res;
 50     int row;
 51     char sql[256]={0};
 52     strcpy(sql,"select * from clients where username=\"");
 53     strcat(sql,su.name);
 54     strcat(sql,"\" and password=\"");
 55     strcat(sql,su.pwd);
 56     strcat(sql,"\";");
 57     printf("查询的sql:%s\n",sql);
 58
 59     mysql_init(&conn);
 60     if(mysql_real_connect(&conn,"localhost","root","","users",0,NULL,CLIENT_FOUND_ROWS))
 61     {
 62         res=mysql_query(&conn,sql);
 63         if(res)
 64         {
 65             perror("Select SQL Error!\n");
 66             exit(-1);
 67         }
 68         else
 69         {
 70             res_ptr=mysql_store_result(&conn);
 71             if(res_ptr)
 72             {
 73                 row=mysql_num_rows(res_ptr);
 74                 if(row==0)
 75                     return 0;
 76                 return 1;//1表示验证成功
 77             }
 78             else
 79             {
 80                 return 0;//0表示验证失败
 81             }
 82         }
 83     }
 84     else
 85     {
 86         perror("Database Connect Failed!");
 87         exit(-1);
 88     }
 89     mysql_close(&conn);
 90     return 0;
 91 }
 92
 93 int main(int argc,char *argv[])
 94 {
    ...110     struct timeval timeout;
111     struct user use;
112     time_t now; struct tm *timenow;
113
    ...
168     while(1)
169     {
       ...
174         switch(select(max_servfd+1,&servfd,NULL,NULL,&timeout))
175         {
176             case -1:
177                 perror("select error");
178                 break;
179             case 0:
180                 break;
181             default:
182                 //printf("has datas to offer accept\n");
183                 if(FD_ISSET(sockfd,&servfd))//sockfd 有数据表示可以进行accept
184                 {
                       ...200                     printf("客户端发来的用户名是:%s,密码:%s\n",use.name,use.pwd);
201                     memset(recvBuf,0,sizeof(recvBuf));
202                     if(mysql_check_login(use))
203                     {
204                         printf("验证成功!\n");
205                         strcpy(sendBuf,"yes");
206                     }
207                     else
208                     {
209                         printf("验证失败!\n");
210                         strcpy(sendBuf,"no");
211                     }
212                     if((sendSize=send(clientfd,sendBuf,MAX_DATA_SIZE,0))==-1)
213                     {
214                         perror("fail to receive datas");
215                     }
              ...221                 }
222                 break;
223         }
224         //FD_COPY(recvfd,servfd);
225         for(i=0;i<MAX_CON_NO;i++)//最大队列进行判断,优化的话,可以使用链表
226         {
        ...231         }
232
233         switch(select(max_recvfd+1,&recvfd,NULL,NULL,&timeout))
234         {
        ...288         }
289     }
290     return 0;
291 }

  本次就增加了一个mysql_check_login这个函数用于用户名和密码的判断。也没有加入太多的功能。只要有个大概思路就可以了,剩下的注册和修改基本相似,就不加入到程序中了。

  接下来还是老规矩,上一张运行时的截图

  数据库中的用户名是user1,密码是123456。看,完成了验证了。顿时感觉好极了。

  本文地址: http://www.cnblogs.com/wunaozai/p/3876134.html

Socket网络编程--聊天程序(7)

时间: 2024-10-29 19:09:49

Socket网络编程--聊天程序(7)的相关文章

Socket网络编程--聊天程序(6)

这一小节将增加一个用户的结构体,用于保存用户的用户名和密码,然后发给服务器,然后在服务器进行判断验证.这里就有一个问题,以前讲的就是发送字符串是使用char类型进行传输,然后在服务器进行用同样是字符串进行接收.然而作为一个结构体是不是也可以呢?如果有看send或recv的函数定义就知道第二个参数是void *类型,也就是说这两个函数对传入的类型其实是不做要求的,只是要你传输个地址,然后后面接一个大小就可以了.就是要send在这个地址取值,去大小为size个,然后传输.学过TCP/IP就知道,我们

Socket网络编程--聊天程序(9)

这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也即二进制文件发送例如图片)和单点登陆(就是多加一个数组fd_L[],用来记录是否已经登陆过了.),这些问题就不讨论了. 支持多服务器实现负载问题的聊天程序 今天才知道原来我们一直使用的select来处理IO多路复用的这个函数最多只能有1024个连接,因为内部实现里面的数组就是只有1024,多了不行.

Socket网络编程--聊天程序(8)

上一节已经完成了对用户的身份验证了,既然有了验证,那么接下来就能对不同的客户端进行区分了,所以这一节讲实现私聊功能.就是通过服务器对客户端的数据进行转发到特定的用户上, 实现私聊功能的聊天程序 实现的技术细节是:对客户端发送的数据增加一个标识头,由于我们处理的是纯文本,所以为了讲解的方便就把标识头加到聊天信息的前面,然后在服务器中判断.如果是要在做成产品的话,因为要考虑传送纯文本,图片,文件,特定的结构体等等其他非纯文本信息,那么我们可以对一次聊天信息,发送两次数据,第一次用TCP发送一个结构体

Socket网络编程--聊天程序(5)

上一小节我们讲了使用select来避免使用多进程的资源浪费问题.上次只是实现了从多个客户端发送数据给服务器端,接下来就要实现从服务器端发送数据给各个服务器. 使用select多路转换处理聊天程序2 client.c 使用上一节用的那个,在那个基础上修改下面几句 66 //send-recv 一些返回指没有判断,具体可以看server.c 67 if((pid=fork())<0) 68 { 69 perror("fork error\n"); 70 } 71 else if(pi

Socket网络编程--聊天程序(3)

上一小节,已经讲到可以每个人多说话,而且还没有限制,简单的来说,我们已经完成了聊天的功能了,那么接下来我们要实现什么功能呢?一个聊天程序至少应该支持一对多的通讯吧,接下来就实现多个客户端往服务器发送数据,和服务器向多个客户端发送数据. 多对一,单向,各个客户端都可以向服务器发送数据 close函数 #include <unistd.h> int close(int sockfd); //用于关闭所打开的Socket套接字 返回值:如果为0表示成功,-1表示失败 处理的办法是每一个客户端连接到服

Socket网络编程--聊天程序(4)

上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理.对于多用户连接时,服务器会受不了的,而且还很消耗资源.据说有个select函数可以用,好像还很NB的样子. 使用select多路转换处理聊天程序 下面摘取APUE 14.5小结 I/O多路转接 当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中循环中使用阻塞I/O: while((n = read(STDIN_FILENO, buf, BUFFSIZ))>0) if(writ

Socket网络编程--聊天程序(2)

上一节简单如何通过Socket创建一个连接,然后进行通信.只是每个人只能说一句话.而且还是必须说完才会接收到信息,总之是很不方便的事情.所以这一小节我们将对上一次的程序进行修改,修改成每个人可以多说话,主要是通过Linux下多进程fork实现的. 一对一,server和client是每个人都可以多说几句话 由于控制台度数据的函数fgets是阻塞函数,要每个人都可以多说话,这里我使用的是读取和发送都在不同的进程里面,使之互相没有影响. fork函数 #include <unistd.h> pid

Socket网络编程--小小网盘程序(1)

这个系列是准备讲基于Linux Socket进行文件传输.简单的文件传输就是客户端可以上传文件,可以从服务器端下载文件.就这么两个功能如果再加上身份验证,就成了FTP服务器了,如果对用户的操作再加上一些功能(如分享),就可以作为一个最简单的网盘了.想想是不是有点小激动啊. 我这一小节就不讲那么高级的东西,就先了解文件怎么传输,我们以前的聊天程序传输数据都是一次发送就完成本次的发送,因为一个sendBuf是足够的.但是对于二进制文件来说,文件的大小就不一定了,有可能很大,所以我们的Buf是不知道要

Socket网络编程--小小网盘程序(4)

在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 client.cpp增加下面这个函数以实现文件的下载. 1 int file_pull(struct Addr addr,struct User user,char *filenames) 2 { 3 struct sockaddr_in servAddr; 4 struct hostent *host;