Tcp服务端,实现了多线程,多客户端,互斥,链表,高并发,接收数据,按文件夹分类写入到文件中,是一个用于调试接收打印log,debug等数据的小型tcp服务器。
总体界面

界面Widget,关键逻辑代码
TcpSerWidget::TcpSerWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::TcpSerWidget)
{
//设置相关ui界面
ui->setupUi(this);
//初始化界面关联和触发
Init();
m_TcpSerFlg=0;
m_pTcpserver = new MyTcpServer;
//关联客户端收到的数据,刷新到界面
connect(m_pTcpserver,&MyTcpServer::SendToWidget,this,&TcpSerWidget::ClientInfoSlots);
}
void TcpSerWidget::Init(){
//IplineEdit,监听端口
//只输入整数
//QRegExp regx("[a-zA-Z0-9]+$");
QRegExp regx("[0-9]+$");
QValidator *validator = new QRegExpValidator(regx, ui->IplineEdit );
ui->IplineEdit->setValidator(validator);
//默认显示
ui->IplineEdit->setPlaceholderText("端口");
//plainTextEdit,发送数据窗口
//文本改变触发函数
connect(ui->plainTextEdit,SIGNAL(textChanged()),this,SLOT(plainTextEdit_send_textChanged()));
ui->plainTextEdit->setPlaceholderText("输入需要发送的数据(最大256字节)");
//pushButton,监听端口
//触发函数
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(SerListen_pushButton_clicked()));
//pushButton_2,发送数据按钮
//触发函数
connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(pushButton_send_clicked()));
//ui->textEdit->setFontPointSize(13);
}
//获取本地地址和设置的端口,启动服务器监听
void TcpSerWidget::SerListen_pushButton_clicked(){
//ui->MesglineEdit->setText(QString(socket->readAll()));
QString port_qstr=ui->IplineEdit->text();
quint16 port=port_qstr.toUShort();
if(port<30000||port>50000){
port=PORT;
}
qDebug("SerListen_pushButton_clicked,port:%s,%d\n",port_qstr.toStdString().c_str(),port);
if(m_TcpSerFlg!=1){
//启动日志监听服务
//监听任何IPv4地址
m_pTcpserver->listen(QHostAddress::AnyIPv4,port);
//m_pTcpserver->start();
//
//QHostAddress address=QHostAddress("192.168.0.173");
//m_pTcpserver->listen(address,port);
m_TcpSerFlg=1;
char ser_info[128];
memset(ser_info,0,sizeof(ser_info));
bool listen_state=m_pTcpserver->isListening();
QHostAddress SerAddr=m_pTcpserver->serverAddress();
if(listen_state){
snprintf(ser_info,sizeof(ser_info),"Listening(%s:%d)...",SerAddr.toString().toStdString().c_str(),port);
}else{
snprintf(ser_info,sizeof(ser_info),"Start Listening(%s:%d)->fail",SerAddr.toString().toStdString().c_str(),port);
}
qDebug("TcpServer,ser_info:%s\n",ser_info);
QString state=QString(QLatin1String(ser_info));
SetSerStatus(state);
}
}
//发送数据
void TcpSerWidget::pushButton_send_clicked(){
QString text=ui->plainTextEdit->toPlainText();
qDebug("触发发送数据:%s",text.toStdString().c_str());
m_pTcpserver->SendClientData(text);
}
tcp服务端逻辑代码
MyTcpServer::MyTcpServer(QObject * parent) : QTcpServer(parent){
//启动客户端发送数据监听线程
m_thr_sendClient = new MyThread(MyTcpServer::runCb,this);
m_thr_sendClient->start();
}
void MyTcpServer::incomingConnection(qintptr socketDescriptor){
qDebug() << "TcpServer incomingConnection";
//QThreadPool::globalInstance()->start(new Mythread(handle));
QMutexLocker locker(&m_ClientList_mutex);
//创建tcp客户端类,启动收发
ClienTcpThread *t = new ClienTcpThread(socketDescriptor);
t->start();
connect(t,&ClienTcpThread::SendToSerWidget,this,&MyTcpServer::ClientIpSlots);
//添加到客户端管理链表
m_ClientList.push_back(t);
}
void MyTcpServer::ClientIpSlots(QByteArray baIp)
{
qDebug("MyTcpServer ClientIpInfo:%s\n",baIp.data());
//发送到界面数据刷新
emit SendToWidget(baIp);
}
void MyTcpServer::SendClientData(QString data){
QMutexLocker locker(&m_SendClientData_list_mutex);
m_SendClientData_list.push_back(data);
}
//每个客户端发送数据线程,有需要发送数据,则送给客户端发送链表中,去等待发送
void MyTcpServer::runCb2(){
qDebug("hello mytcpserver runCb2");
qint32 seccnt=0;
QList<ClienTcpThread *>::const_iterator it_client;
ClienTcpThread * pcli=Q_NULLPTR;
QList<QString>::const_iterator it_send;
QString send_string;
while (true) {
QThread::msleep(10);
//qDebug("mytcpserver run %d",seccnt++);
if(!m_ClientList.isEmpty()&&!m_SendClientData_list.isEmpty()){
if(m_SendClientData_list_mutex.tryLock()&&m_ClientList_mutex.tryLock()){
qDebug("mytcpserver run client:%d,data:%d",m_ClientList.size(),m_SendClientData_list.size());
it_send = m_SendClientData_list.constBegin();
for(;it_send!=m_SendClientData_list.constEnd();it_send++){
send_string = *it_send;
it_client=m_ClientList.constBegin();
for(;it_client!=m_ClientList.constEnd();it_client++){
pcli=*it_client;
pcli->SendData(send_string);
}
m_SendClientData_list.pop_front();
}
m_ClientList_mutex.unlock();
m_SendClientData_list_mutex.unlock();
}
}
}
}
子客户端逻辑代码
ClienTcpThread::ClienTcpThread(qintptr s)
{
m_socketDescriptor=s;
m_bfileopen=false;
}
void ClienTcpThread::run(){
//char* preadbuf=new char[1024];
//qint64 readLen=0;
//创建QTcpSocket
m_socket = new QTcpSocket();
if(!m_socket->setSocketDescriptor(m_socketDescriptor)) {
qDebug() << "tcpSocket setSocketDescriptor(m_socketDescriptor) failed";
delete m_socket;
m_socket=NULL;
return;
}
//创建分类文件夹和文件
QFileInfo info("./QFile.exe");
QString absolutePath = info.absolutePath();
QString DbgDirPrx("dvr_");
QString dirName = absolutePath+"/"+DbgDirPrx+QDateTime::currentDateTime().toString("yyyy_MM_dd");
QDir dir(dirName);
if(!dir.exists())
{
dir.mkdir(dirName);
qDebug()<<dirName<<" 文件夹创建成功";
}
char path[128]={0};
snprintf(path,sizeof(path),"%s/%s_%s.log",dirName.toStdString().c_str(),m_socket->peerAddress().toString().toStdString().c_str(),QDateTime::currentDateTime().toString("hhmmss").toStdString().c_str());
//关联文件名字
m_file.setFileName(path);
bool b_open = m_file.open(QIODevice::WriteOnly|QIODevice::Text);
if(b_open){
m_bfileopen=true;
}
qDebug("open file(%d):%s\n",b_open,path);
char IPbuf[128]={0};
snprintf(IPbuf,sizeof(IPbuf),"IP[%s:%d]",m_socket->peerAddress().toString().toStdString().c_str(),m_socket->peerPort());
QByteArray baIP(IPbuf);
emit SendToSerWidget(baIP);
//m_tcpSocket->peerAddress().toString().toStdString().c_str(),m_tcpSocket->peerPort()
char heartbuf[128]={0};
//snprintf(heartbuf,sizeof(heartbuf),"heart->%s",IPbuf);
snprintf(heartbuf,sizeof(heartbuf),"heart");
qDebug("%s\n",IPbuf);
//connect(m_socket,&QTcpSocket::readyRead,this,&ClienTcpThread::RcvData);
// m_socket->waitForReadyRead(1024);
qint64 curSec = QDateTime::currentDateTime().toTime_t();
qint64 lastSendSec=curSec;
qint64 readLen=0;
const qint64 maxlen=1024*1024;
char preadbuf[maxlen];
while(m_socket->state()==QAbstractSocket::ConnectedState)
{
curSec = QDateTime::currentDateTime().toTime_t();
//读数据
if (m_socket->waitForReadyRead(1000)){
memset(preadbuf,0,maxlen);
readLen=m_socket->read(preadbuf,maxlen); //接收数据
//cout << stu1.ar << " " << stu1.b << endl;
//qDebug("Rcv[%s][%lld]:%s\n",IPbuf,readLen,preadbuf);
qDebug("Rcv[%s][%lld/%lld]\n",IPbuf,readLen,maxlen);
if (m_bfileopen)
{
qDebug("RcvData,write[%lld]\n",readLen);
m_file.write(preadbuf,readLen);
m_file.flush();
}
}
//发数据
if(abs(curSec-lastSendSec)>5){
qDebug("[%lld,%s]->heart\n",curSec,IPbuf);
m_socket->write(heartbuf);
lastSendSec=curSec;
}else{
if(m_SendData_list_mutex.tryLock()){
if(!m_SendData_list.isEmpty()){
qDebug("[%lld,%s]->sendlist:%d\n",curSec,IPbuf,m_SendData_list.size());
QList<QString>::const_iterator it=m_SendData_list.constBegin();
QString send_string;
for(;it!=m_SendData_list.constEnd();it++){
send_string=*it;
qDebug("[%lld,%s]->send:%s\n",curSec,IPbuf,send_string.toStdString().c_str());
m_socket->write(send_string.toLatin1());//按asccii码转QByteArray
}
m_SendData_list.clear();
}
m_SendData_list_mutex.unlock();
}
}
QThread::msleep(100);
}
if(m_bfileopen){
m_file.close();
m_bfileopen=false;
}
//delete preadbuf;
qDebug("[%s]->end\n",IPbuf);
if(Q_NULLPTR !=m_socket){
m_socket->close();
delete m_socket;
m_socket=NULL;
}
}
//添加发送数据到发送链表
qint8 ClienTcpThread::SendData(QString data){
QMutexLocker locker(&m_SendData_list_mutex);
m_SendData_list.push_back(data);
qDebug("send data:%s",data.toStdString().c_str());
return 0;
}
主mian
QApplication a(argc, argv);
//重置qDebug打印函数到文件中
SetDebugPathFile();
qInstallMessageHandler(customMessageHandler);
//MyTcpServer * pTcpServer= new MyTcpServer;
//监听任何IPv4地址
//pTcpServer->listen(QHostAddress::AnyIPv4,PORT);
TcpSerWidget w;
w.show();
演示,使用程序链接资源下载
https://download.youkuaiyun.com/download/wutu_csdn_blog/87129453

该博客介绍了一个使用Qt开发的TCP服务器,具备多线程处理多个客户端连接的能力,实现了互斥机制、高并发处理及接收到的数据按文件夹分类存储。关键代码包括服务端逻辑、子客户端逻辑和主程序。
532

被折叠的 条评论
为什么被折叠?



