- C++MySql的使用
- 链接数据库
- 数据库操作
- C++ socket通信
- Server.h Server.cpp
- Client.h Client.cpp
- main.cpp
- Qt多线程
- MyThread.h
- MyThread.cpp
- 主线程调用程序
- 总结
最近用到了很多相关的东西,记录下来,方便下次查找
C++MySql的使用 链接数据库//链接数据库 mysql_init(&conn); if (mysql_real_connect(&conn, "127.0.0.0", "root", "paassword", "table", 3306, nullptr, CLIENT_FOUND_ROWS)) std::cout << "链接成功" << std::endl; else std::cout << "连接失败" << std::endl;数据库操作
sprintf(query,"select * from user where user_id='%s'",id); mysql_query(&conn,query);
- 配合sprintf一起使用,很舒服而且方便。
- mysql_query函数执行query语句,如果是insert或者update就直接执行完了,如果是select的话,再用其他函数获取结果。
- mysql_query函数的返回值,0代表查询成功,1是查询失败,指sql语法错误。
- 查询完之后使用mysql_store_result获取结果集。返回值是MYSQL_RES *
- mysql_num_rows获取结果集的行数
- mysql_num_fields获取结果集的列数(每一列的字段就是数据库中的列代表的字段)
MYSQL_RES * res = mysql_store_result(&conn); int n = mysql_num_rows(res),m = mysql_num_fields(res);
- 使用mysql_fetch_row获取当前记录行 返回值是MYSQL_ROW
for(int i = 0 ; i < n ; i++)
{
MYSQL_ROW row = mysql_fetch_row(res);
//row[j]获取j列字段的数据
}
- row[j]获取字段的数据(获取的全都是char*类型的,应该是)
- 查找为空的判断方法:mysql_num_rows的结果为0,代表没有查到相应的数据。
学习自 @河边小咸鱼 的博客 C++网络编程学习,大佬写的真不错
C++网络编程学习
对代码进行了修改,更加适应我自己的使用环境了?
因为用的时候我的环境是,服务端是linux,客户端是windows,所以把对应的跨平台处理代码删掉了x
#ifndef _TcpServer_hpp_ #define _TcpServer_hpp_ #include //selcet #include#include //uni std #define SOCKET int #define INVALID_SOCKET (SOCKET)(~0) #define SOCKET_ERROR (-1) #include #include #include #include using namespace std; enum{ CMD_LOGIN, CMD_LOGINRESULT, //需要的命令这在加上,为了方便数据处理 }; //数据文件头 请务必写成这样 方便数据传输 struct DataHeader{ short cmd; short data_length; }; //真正进行传输的数据 按照结构体去传 //实际上传输就是转成(char*)去传过去,然后对面再转成相应的数据,由于结构的内存是一整块的,所以传输的时候使用结构体传输。 //如果需要传输其他的数据,就按照这个格式在后面补上更多 struct LOGIN:public DataHeader{ LOGIN(){ this->cmd = CMD_LOGIN; this->data_length = sizeof(LOGIN); } char user_id[256]; char password[256]; }; struct LoginResult:public DataHeader{ LoginResult(){ this->cmd = CMD_LOGINRESULT; this->data_length = sizeof(LoginResult); } //密码不对返回0 密码对返回1 无此账号返回2 int result; }; class TcpServer { public: //构造 TcpServer(); //析构 virtual ~TcpServer(); //初始化socket 返回1为正常 int InitSocket(); //绑定IP/端口 int Bind(const char *ip, unsigned short port); //监听端口 int Listen(int n); //接受连接 int Accept(); //关闭socket void CloseSocket(); //查询是否有待处理消息 bool OnRun(); //判断是否工作中 bool IsRun(); //发送数据 //int SendData(char *_head, SOCKET _temp_socket); int SendData(DataHeader *_head, SOCKET _temp_socket); //接收数据 int RecvData(SOCKET _temp_socket); //处理请求 void cal(DataHeader *_head, SOCKET _temp_socket); private: SOCKET _sock; std::vector _clients; //储存客户端socket }; #endif
//TcpServer.cpp
#include "TcpServer.h"
TcpServer::TcpServer()
{
_sock = INVALID_SOCKET;
}
TcpServer::~TcpServer()
{
CloseSocket();
}
int TcpServer::InitSocket()
{
//创建socket
if (INVALID_SOCKET != _sock)
{
printf("关闭连接n", _sock);
CloseSocket(); //如果之前有连接 就关闭连接
}
_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _sock)
return 0; // 0为socket创建错误
return 1;
}
int TcpServer::Bind(const char *ip, unsigned short port)
{
//如果为无效套接字 则初始化
if (INVALID_SOCKET == _sock)
InitSocket();
//绑定网络端口和IP地址
sockaddr_in _myaddr = {};
_myaddr.sin_family = AF_INET; // IPV4
_myaddr.sin_port = htons(port); //端口
if (ip) // ip为空则监听所有网卡
_myaddr.sin_addr.s_addr = inet_addr(ip); // IP
else
_myaddr.sin_addr.s_addr = INADDR_ANY; // IP
if (SOCKET_ERROR ==
bind(_sock, (sockaddr *)&_myaddr, sizeof(sockaddr_in))) // socket (强制转换)sockaddr结构体 结构体大小
{
printf("绑定失败n");
return 0;
}
else
{
printf("绑定成功n绑定端口为%dn", port);
return 1;
}
}
int TcpServer::Listen(int n)
{
//如果为无效套接字 则提示
if (INVALID_SOCKET == _sock)
{
printf("请先初始化套接字并绑定IP端口n");
return 0;
}
//监听网络端口
if (SOCKET_ERROR == listen(_sock, n)) //最大连接队列
{
printf("监听失败n");
return 0;
}
else
{
printf("监听成功n");
return 1;
}
}
int TcpServer::Accept()
{
//等待接收客户端连接
sockaddr_in _clientAddr = {}; //新建sockadd结构体接收客户端数据
int _addr_len = sizeof(sockaddr_in); //获取sockadd结构体长度
SOCKET _temp_socket = INVALID_SOCKET; //声明客户端套接字
_temp_socket =
accept(_sock, (sockaddr *)&_clientAddr, (socklen_t *)&_addr_len); //自身套接字 客户端结构体 结构体大小
if (INVALID_SOCKET == _temp_socket) //接收失败
{
printf("错误,接受到无效客户端SOCKETn", _temp_socket);
return 0;
}
printf("新客户端加入nIP地址为:%s n", inet_ntoa(_clientAddr.sin_addr));
//群发通知在这
_MessageNumber * mn = new _MessageNumber;
mn->number = _clients.size();
for(int i = 0 ;i < _clients.size() ; i++)
send(_clients[i],(const char*)mn,mn->data_length,0);
//将新的客户端加入动态数组
_clients.push_back(_temp_socket);
return 1;
}
void TcpServer::CloseSocket()
{
if (INVALID_SOCKET != _sock)
{
//关闭客户端socket
for (int n = 0; n < _clients.size(); ++n)
close(_clients[n]);
//关闭socket/LINUX
close(_sock);
_sock = INVALID_SOCKET;
}
mysql_close(&conn);
}
bool TcpServer::OnRun()
{
if (IsRun())
{
//std::cout << "正在监听" << std::endl;
fd_set _fdRead; //建立集合
fd_set _fdWrite;
fd_set _fdExcept;
FD_ZERO(&_fdRead); //清空集合
FD_ZERO(&_fdWrite);
FD_ZERO(&_fdExcept);
FD_SET(_sock, &_fdRead); //放入集合
FD_SET(_sock, &_fdWrite);
FD_SET(_sock, &_fdExcept);
timeval _t = {2, 0}; // select最大响应时间
SOCKET _maxSock = _sock; //最大socket
//把连接的客户端 放入read集合
for (int n = _clients.size() - 1; n >= 0; --n)
{
FD_SET(_clients[n], &_fdRead);
if (_maxSock < _clients[n])
_maxSock = _clients[n];
}
// select函数筛选select
int _ret = select(_maxSock + 1, &_fdRead, &_fdWrite, &_fdExcept, &_t);
if (_ret < 0)
{
printf("select任务结束n");
CloseSocket();
return false;
}
if (FD_ISSET(_sock, &_fdRead)) //获取是否有新socket连接
{
FD_CLR(_sock, &_fdRead); //清理
Accept(); //连接
}
//遍历所有socket 查看是否有待处理事件
for (int n = 0; n < _clients.size(); ++n)
{
if (FD_ISSET(_clients[n], &_fdRead))
{
if (-1 == RecvData(_clients[n])) //处理请求 客户端退出的话
{
std::vector::iterator iter = _clients.begin() + n; //找到退出客户端的地址
if (iter != _clients.end()) //如果是合理值
_clients.erase(iter); //移除
_MessageNumber * mn = new _MessageNumber;
mn->number = _clients.size();
for(int i = 0 ;i < _clients.size() ; i++)
send(_clients[n],(const char*)mn,mn->data_length,0);
}
}
}
return true;
}
return false;
}
bool TcpServer::IsRun()
{
return _sock != INVALID_SOCKET;
}
int TcpServer::SendData(DataHeader *_head, SOCKET _temp_socket)
{
if (IsRun() && _head)
{
send(_temp_socket, (const char *)_head, _head->data_length, 0);
return 1;
}
return 0;
}
int TcpServer::RecvData(SOCKET _temp_socket) //处理数据
{
//缓冲区
char buffer[4096] = {};
//接收客户端发送的数据
int _buf_len = recv(_temp_socket, buffer, sizeof(DataHeader), 0);
DataHeader *_head = (DataHeader *)buffer;
if (_buf_len <= 0)
{
printf("客户端已退出n");
return -1;
}
recv(_temp_socket,buffer+sizeof(DataHeader),_head->data_length - sizeof(DataHeader),0);
cal(_head, _temp_socket);
return 0;
}
void TcpServer::cal(DataHeader *_head, SOCKET _temp_socket)
{
//在此相应数据
}
Client.h Client.cpp
//TcpClient.h #ifndef TCPCLIENT_H #define TCPCLIENT_H #define WIN32_LEAN_AND_MEAN #include#include #pragma comment(lib,"ws2_32.lib") #include #include #include #include #include #include using namespace std; enum{ CMD_LOGIN, CMD_LOGINRESULT, }; struct DataHeader{ short cmd; short data_length; }; //这些东西和服务端的定义务必保持一致 struct LOGIN:public DataHeader{ LOGIN(){ this->cmd = CMD_LOGIN; this->data_length = sizeof(LOGIN); } char user_id[256]; char password[256]; }; struct LoginResult:public DataHeader{ LoginResult(){ this->cmd = CMD_LOGINRESULT; this->data_length = sizeof(LoginResult); } int result; }; class TcpClient { public: //构造 TcpClient(); //析构 virtual ~TcpClient(); //初始化socket 返回1为正常 int InitSocket(); //连接服务器 返回1为成功 int Connect(const char *ip,unsigned short port); //关闭socket void CloseSocket(); //查询是否有待处理消息 bool OnRun(); //判断是否工作中 bool IsRun(); //发送数据 int SendData(DataHeader *_head); //接收数据 int RecvData(); //以下定义的都是我自己为了方便使用写的,定义一个DataHeader*变量让每次接收到的数据都放这里,方便我之后进行的操作 //总数据 DataHeader * res; private: SOCKET _sock; }; #endif // TCPCLIENT_H
//TcpClient.cpp #include "tcpclient.h" #includemain.cppTcpClient::TcpClient() { _sock = INVALID_SOCKET; } TcpClient::~TcpClient() { //关闭socket CloseSocket(); } int TcpClient::InitSocket() { //启动windows socket 2,x环境 WORD ver = MAKEWORd(2,2); WSADATA dat; if(0 != WSAStartup(ver,&dat)) return -1;//环境错误 //创建socket if(INVALID_SOCKET != _sock) { printf(" 关闭连接n",_sock); CloseSocket();//如果之前有连接 就关闭连接 } _sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(INVALID_SOCKET == _sock) return 0; //socket创建失败 return 1; } int TcpClient::Connect(const char * ip,unsigned short port) { //如果为无效套接字 则初始化 if(INVALID_SOCKET == _sock) InitSocket(); //连接服务器 sockaddr_in _sin = {}; _sin.sin_family = AF_INET;//IPV4 _sin.sin_port = htons(port);//端口号 _sin.sin_addr.S_un.S_addr = inet_addr(ip);//IP if(SOCKET_ERROR == connect(_sock,(sockaddr*)&_sin,sizeof(sockaddr_in))) return 0;//连接失败 return 1;//连接成功 } void TcpClient::CloseSocket() { if(INVALID_SOCKET != _sock) { //关闭socket closesocket(_sock); //清除windows socket 环境 WSACleanup(); _sock = INVALID_SOCKET; } } bool TcpClient::OnRun() { if(IsRun())//如果有连接则监听事件 { fd_set _fdRead;//建立集合 FD_ZERO(&_fdRead);//清空集合 FD_SET(_sock,&_fdRead);//放入集合 timeval _t = {1,0};//select最大响应时间 //新建seclect int _ret = select(_sock+1,&_fdRead,NULL,NULL,&_t); if(_ret<0) { printf("seclect任务结束n"); return false; } if(FD_ISSET(_sock,&_fdRead))//获取是否有可读socket { FD_CLR(_sock,&_fdRead);//清理计数器 if(-1 == RecvData()) { CloseSocket(); return false; } } return true; } return false; } bool TcpClient::IsRun() { return _sock != INVALID_SOCKET; } int TcpClient::SendData(DataHeader *_head) { if(IsRun() && _head) { send(_sock,(const char*)_head, _head->data_length,0); return 1; } return 0; } int TcpClient::RecvData()//处理数据 { //缓冲区 char buffer[4096] = {}; //接收客户端发送的数据 int _buf_len = recv(_sock,buffer,sizeof(DataHeader),0); DataHeader * _head = (DataHeader *)buffer; if(_buf_len<=0) { printf("与服务器断开连接,任务结束n"); return -1; } recv(_sock,buffer+sizeof(DataHeader),_head->data_length-sizeof(DataHeader),0); res = _head; return 0; }
//服务端的 main函数 #include "TcpServer.h" #includeusing namespace std; int main() { //建立tcp对象 TcpServer *tcp1 = new TcpServer(); //建立一个socket tcp1->InitSocket(); //绑定端口和IP tcp1->Bind(nullptr, 8888); //监听 tcp1->Listen(5); //循环 while (tcp1->IsRun()) tcp1->OnRun(); //关闭 tcp1->CloseSocket(); return 0; }
//客户端启动方法
TcpClient* tcp = new TcpClient();
tcp->Connect("47.97.105.213",8888);
//最好加上条件语句判断时候连接上,Connect函数成功连接返回1,失败返回0,详见函数实现
Qt多线程
学了一个比较好用的,自己写一个类,让他继承QObject类,然后在里面写信号和槽函数。
最后在主线程里面使用moveToThread开新的线程
代码实现
#ifndef MYTHREAD_H #define MYTHREAD_H #include "tcpclient.h" #includeMyThread.cppclass MyThread : public QObject { Q_OBJECT public: explicit MyThread(QObject *parent = nullptr); public slots: void dowork(); signals: void newMessage(); }; #endif // MYTHREAD_H
#include "mythread.h" #include主线程调用程序MyThread::MyThread(QObject *parent) : QObject{parent} { qDebug()<<"启动准备干活!!!!!!!!!"; } void MyThread::dowork() { while(true) { qDebug()<<"干活了"; emit newMessage() Sleep(1000); } }
//头文件中写
QThread * qth;
//cpp文件写
//构造函数中
MyThread *th = new MyThread(tcp);
qth = new QThread(this);
th->moveToThread(qth);
//线程释放
connect(qth, &QThread::finished, qth, &QThread::deleteLater);
//点击按钮启动子线程中的函数
connect(ui->sendBtn, &QPushButton::clicked, th, &MyThread::dowork);
connect(th, &MyThread::newMessage, [=]() {
//这里写你要在子线程法术newMessage信号之后你要进行的操作
});
//线程启动
qth->start();
//析构函数中
//线程退出等待
qth->quit();
qth->wait();
总结
确实学到了很多东西,应该说会用了很多东西,很多深层的都不知道,不过会用了。



