Qt:Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_29542611/article/details/83778389

Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)

前言

感觉Winsock网络编程的api其实和Linux下网络编程的api非常像,其实和其他编程语言的网络编程都差不太多。博主用Qt实现的,当然不想用黑窗口呗,有界面可以看到,由于GUI编程的话 一般UI进程不能阻塞,肯定需要多线来实现,在等待用户连接的时候accept,和客户端通信 等待消息的时候recv这些都是阻塞的 都需要在后台进程中。博主使用的是Qt5.9.7

界面效果

先看下效果再说
在这里插入图片描述
在这里插入图片描述

Winsock面向连接的接口

Winsock初始化和释放

WSAStartup、WSACleanup

服务端:

socket() -> bind() -> listen() -> accept() -> send() / recv() -> closesocket()

客户端:

socket() -> connect() -> send() / recv() -> closesocket()

这些函数都在msdn上有,这里就不过多的阐述

代码展示

服务端 将与客户度建立连接的 过程放到单独的线程中进行处理了,这个线程 做的事就是等待客户端连接,客户端连接后 单独再开一个线程专门与客户度进行通信,这样就不会导致界面无响应了。这里线程和线程间的通信是使用的Qt中的信号槽机制。

处理客户端连接请求代码

void SocketThread::run()
{
        sockaddr_in clientAddr;
        int size = sizeof(clientAddr);
        while(!isInterruptionRequested()){
            //每次接受新客户端将之前的地址信息清0
            memset(&clientAddr,0,sizeof(clientAddr));
            //等待新客户端连接 阻塞函数,结束线程 使用requestInterruption打断线程并没有用,只能使用terminate 终止线程
            SOCKET client = ::accept(mListen,(sockaddr*)&clientAddr,&size);
            char* clientIp = inet_ntoa(clientAddr.sin_addr);
            int clientPort = ntohs(clientAddr.sin_port);
            QTime time = QTime::currentTime();
            QString str = time.toString("hh:mm:ss");
            QString msg = QString("%1 [%2:%3] connect success").arg(str).arg(clientIp).arg(clientPort);
            //新客户端连接,通知 UI 更新界面
            emit isMsg(msg);
            //开启新线程和客户端进行通信
            MsgThread* msgThread = new MsgThread(client,clientAddr,parent);
            msgThread->start();

            connect(msgThread,&MsgThread::isMsg,this,[=](QString msg){
                //转发消息给 UI进程,UI进行界面更新
                emit isMsg(msg);
            });
            connect(this,&SocketThread::isClose,this,[=](){
                msgThread->terminate();
                msgThread->quit();
                delete msgThread;
            });
        }
}

服务端和客户端通信的代码

void MsgThread::run(){
        //inet_addr点分十进制转网络ip地址 ,inet_ntoa网络转点分十进制
        char* clientIp = inet_ntoa(mAddr.sin_addr);
        int clientPort = ntohs(mAddr.sin_port);
        while(true){
            memset(resp,0,1024);
            char buf[1024] = {0};
            //阻塞等待 接受信息
            int ret = recv(mClient,buf,1024,0);
            QTime time = QTime::currentTime();
            QString str = time.toString("hh:mm:ss");
            if(ret == 0){//连接断开
                emit isMsg(QString("%1 [%2:%3] is closed!!!").arg(str).arg(clientIp).arg(clientPort));
                break;
            }
            QString msg = QString("%1 [%2:%3]:%4").arg(str).arg(clientIp).arg(clientPort).arg(buf);
            //接受到消息,通知UI 界面更新
            emit isMsg(msg);

            //给用户进行响应消息,小写变大写
            strcpy(resp,QString(buf).toUpper().toUtf8().data());
            qDebug() << "给客户端发送消息:" << resp;
            send(mClient,resp,strlen(resp)+1,0);
        }
}

完整代码

完整项目代码可以点这里进行下载,或者github下载最新代码

猜你喜欢

转载自blog.csdn.net/qq_29542611/article/details/83778389