
- 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<SOCKET> _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绑定端口为%d\n", 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("错误,接受到无效客户端SOCKET\n" , _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<SOCKET>::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"
#include
TcpClient::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.cpp
//服务端的 main函数
#include "TcpServer.h"
#include
using 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"
#include
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
public slots:
void dowork();
signals:
void newMessage();
};
#endif // MYTHREAD_H
MyThread.cpp
#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();
总结
确实学到了很多东西,应该说会用了很多东西,很多深层的都不知道,不过会用了。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)