1.mysql 简介
- Linux下启动mysql
sudo service mysql start//启动mysql
mysql -U root //启动mysql;
- C++连接mysql的环境配置;
sudo apt update
sudo apt install -y libmysqlclient-dev
安装之后查看是否有mysql.h
ls /usr/include/mysql|grep mysql.h
mysql下所进行的前期准备工作:
- 进入mysql;
sudo service mysql start//启动mysql
mysql -U root //启动mysql;
- 创建数据库以及表格;
create database ChatProject;//创建数据库
use ChatProject;//切换数据库
CREATE TABLE USER(
NAME VARCHAR(20) PRIMARY KEY,
PASSWORD VARCHAR(20)
);//创建数据表;
2.关于注册以及登录功能的实现;
2.1 客户端
global.h
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#include <thread>
#include <vector>
#include <mysql/mysql.h>// 负责mysql的连接;
using namespace std;
#endif
client.h
#ifndef CLIENT_H
#define CLIENT_H
#include "global.h"
class client{
private:
int server_port;
string server_ip;
int sock;
public:
client(int port,string ip);
~client();
void run();//连接服务器,调用HandleClient函数
static void SendMsg(int conn);//发送数据
static void RecvMsg(int conn);//接收数据
void HandleClient(int conn);//用于与用户以及服务器交互来处理各种事务
};
#endif
client.cpp
#include "client.h"
client::client(int port,string ip):server_port(port),server_ip(ip){}
client::~client(){
close(sock);
}
void client::run(){//与服务器的连接
//定义sockfd
sock = socket(AF_INET,SOCK_STREAM, 0);//SOCK_STREAM代表TCP
//定义sockaddr_in
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(server_port); //服务器端口
servaddr.sin_addr.s_addr = inet_addr(server_ip.c_str()); //服务器ip
//连接服务器,成功返回0,错误返回-1
if (connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("connect");
exit(1);
}
cout<<"连接服务器成功\n";
HandleClient(sock);
return;
}
void client::HandleClient(int conn){
int choice;
string name,pass,pass1;
bool if_login=false;//记录是否登录成功
string login_name;//记录成功登录的用户名
cout<<" ------------------\n";
cout<<"| |\n";
cout<<"| 请输入你要的选项:|\n";
cout<<"| 0:退出 |\n";
cout<<"| 1:登录 |\n";
cout<<"| 2:注册 |\n";
cout<<"| |\n";
cout<<" ------------------ \n\n";
//开始处理注册、登录事件
while(1){
if(if_login)
break;
cin>>choice;
if(choice==0)
break;
//注册
else if(choice==2){
cout<<"注册的用户名:";
cin>>name;
while(1){
cout<<"密码:";
cin>>pass;
cout<<"确认密码:";
cin>>pass1;
if(pass==pass1)
break;
else
cout<<"两次密码不一致!\n\n";
}
name="name:"+name;
pass="pass:"+pass;
string str=name+pass;
send(conn,str.c_str(),str.length(),0);
cout<<"注册成功!\n";
cout<<"\n继续输入你要的选项:";
}
//登录
else if(choice==1&&!if_login){
while(1){
cout<<"用户名:";
cin>>name;
cout<<"密码:";
cin>>pass;
string str="login"+name;
str+="pass:";
str+=pass;
send(sock,str.c_str(),str.length(),0);//发送登录信息
char buffer[1000];
memset(buffer,0,sizeof(buffer));
recv(sock,buffer,sizeof(buffer),0);//接收响应
string recv_str(buffer);
if(recv_str.substr(0,2)=="ok"){
if_login=true;
login_name=name;
cout<<"登陆成功\n\n";
break;
}
else
cout<<"密码或用户名错误!\n\n";
}
}
}
//登陆成功
if(if_login){
system("clear");//清空终端d
cout<<" 欢迎回来,"<<login_name<<endl;
cout<<" -------------------------------------------\n";
cout<<"| |\n";
cout<<"| 请选择你要的选项: |\n";
cout<<"| 0:退出 |\n";
cout<<"| 1:发起单独聊天 |\n";
cout<<"| 2:发起群聊 |\n";
cout<<"| |\n";
cout<<" ------------------------------------------- \n\n";
}
}
//注意,前面不用加static!
void client::SendMsg(int conn){
char sendbuf[100];
while (1)
{
memset(sendbuf, 0, sizeof(sendbuf));
cin>>sendbuf;
int ret=send(conn, sendbuf, strlen(sendbuf),0); //发送
//输入exit或者对端关闭时结束
if(strcmp(sendbuf,"exit")==0||ret<=0)
break;
}
}
//注意,前面不用加static!
void client::RecvMsg(int conn){
//接收缓冲区
char buffer[1000];
//不断接收数据
while(1)
{
memset(buffer,0,sizeof(buffer));
int len = recv(conn, buffer, sizeof(buffer),0);
//recv返回值小于等于0,退出
if(len<=0)
break;
cout<<"收到服务器发来的信息:"<<buffer<<endl;
}
}
测试程序:
#include"client.h"
int main(){
client clnt(8023,"127.0.0.1");//初始化一个clnt窗口;
clnt.run();//运行客户端,连接服务器;
}
2.2服务端;
server.h
#ifndef SERVER_H
#define SERVER_H
#include "global.h"
class server{
private:
int server_port;//定义端口
int server_sockfd;//定义文件描述符
string server_ip;//定义IP地址
static vector<bool> sock_arr;//定义可用文件描述符
public:
server(int port,string ip);//初始化
~server();
void run();//连接
static void RecvMsg(int conn);//接收信息
static void HandleRequest(int conn,string str);//与客户端进行交互;
};
#endif
server.cpp
#include "server.h"
vector<bool> server::sock_arr(10000,false);//初始化文件描述符
server::server(int port,string ip):server_port(port),server_ip(ip){}
server::~server(){
for(int i=0;i<sock_arr.size();i++){
if(sock_arr[i])
close(i);
}
close(server_sockfd);
}
void server::run(){
//定义sockfd
server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
//定义sockaddr_in
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET;//TCP/IP协议族
server_sockaddr.sin_port = htons(server_port);//server_port;//端口号
server_sockaddr.sin_addr.s_addr = inet_addr(server_ip.c_str());//ip地址,127.0.0.1是环回地址,相当于本机ip
//bind,成功返回0,出错返回-1
if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
{
perror("bind");//输出错误原因
exit(1);//结束程序
}
//listen,成功返回0,出错返回-1
if(listen(server_sockfd,20) == -1)
{
perror("listen");//输出错误原因
exit(1);//结束程序
}
//客户端套接字
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
//成功返回非负描述字,出错返回-1
while(1){
int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
if(conn<0)
{
perror("connect");//输出错误原因
exit(1);//结束程序
}
cout<<"文件描述符为"<<conn<<"的客户端成功连接\n";
sock_arr[conn]=true;
thread t(server::RecvMsg,conn);
t.detach();
}
}
//注意,前面不用加static!
void server::RecvMsg(int conn){
//接收缓冲区
char buffer[1000];
//不断接收数据
while(1)
{
memset(buffer,0,sizeof(buffer));
int len = recv(conn, buffer, sizeof(buffer),0);
//客户端发送exit或者异常结束时,退出
if(strcmp(buffer,"exit")==0 || len<=0){
close(conn);
sock_arr[conn]=false;
break;
}
cout<<"收到套接字描述符为"<<conn<<"发来的信息:"<<buffer<<endl;
string str(buffer);
HandleRequest(conn,str);
}
}
void server::HandleRequest(int conn,string str){
char buffer[1000];
string name,pass;
bool if_login=false;//记录当前服务对象是否成功登录
string login_name;//记录当前服务对象的名字
//string target_name;//记录发送信息时目标用户的名字
//int group_num;//记录群号
//连接MYSQL数据库
MYSQL *con=mysql_init(NULL);
mysql_real_connect(con,"127.0.0.1","root","","ChatProject",0,NULL,CLIENT_MULTI_STATEMENTS);
//注册
if(str.find("name:")!=str.npos){
int p1=str.find("name:"),p2=str.find("pass:");
name=str.substr(p1+5,p2-5);
pass=str.substr(p2+5,str.length()-p2-4);
string search="INSERT INTO USER VALUES (\"";
search+=name;
search+="\",\"";
search+=pass;
search+="\");";
cout<<"sql语句:"<<search<<endl<<endl;
mysql_query(con,search.c_str());//c_str()将string 对象转换成c中的字符串样式;
}
//登录
else if(str.find("login")!=str.npos){
int p1=str.find("login"),p2=str.find("pass:");
name=str.substr(p1+5,p2-5);
pass=str.substr(p2+5,str.length()-p2-4);
string search="SELECT * FROM USER WHERE NAME=\"";
search+=name;
search+="\";";
cout<<"sql语句:"<<search<<endl;
auto search_res=mysql_query(con,search.c_str());
auto result=mysql_store_result(con);
int col=mysql_num_fields(result);//获取列数
int row=mysql_num_rows(result);//获取行数
//查询到用户名
if(search_res==0&&row!=0){
cout<<"查询成功\n";
auto info=mysql_fetch_row(result);//获取一行的信息
cout<<"查询到用户名:"<<info[0]<<" 密码:"<<info[1]<<endl;
//密码正确
if(info[1]==pass){
cout<<"登录密码正确\n\n";
string str1="ok";
if_login=true;
login_name=name;
send(conn,str1.c_str(),str1.length()+1,0);
}
//密码错误
else{
cout<<"登录密码错误\n\n";
char str1[100]="wrong";
send(conn,str1,strlen(str1),0);
}
}
//没找到用户名
else{
cout<<"查询失败\n\n";
char str1[100]="wrong";
send(conn,str1,strlen(str1),0);
}
}
}
2.3 逻辑图
客户端逻辑框图:
服务端:
2.4 执行结果
服务端:
客户端: