C++相关学习记录

C++相关学习记录,第1张

C++相关学习记录
  • 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++ socket通信

学习自 @河边小咸鱼 的博客 C++网络编程学习,大佬写的真不错
C++网络编程学习

对代码进行了修改,更加适应我自己的使用环境了?
因为用的时候我的环境是,服务端是linux,客户端是windows,所以把对应的跨平台处理代码删掉了x

Server.h Server.cpp
#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开新的线程
代码实现

MyThread.h

#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();

总结

确实学到了很多东西,应该说会用了很多东西,很多深层的都不知道,不过会用了

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/921041.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-16
下一篇2022-05-16

发表评论

登录后才能评论

评论列表(0条)

    保存