Qt:Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊(多執行緒)
阿新 • • 發佈:2018-12-08
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下載最新程式碼。