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()){//每次接受新客户端将之前的地址信息清0memset(&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下载最新代码。