基于winsock的局域网聊天室实现
? ? ? ?最初實現是由于課題要求運用WinSock來實現SOCKET通信,就去了解了一下了一下winsock的官方文檔:微軟Winsock文檔
? ? ? ?WINSock2最初設計目的便是向Windows添加IPv4通信的支持,其工作原理就是在原有的Socket編程上進一步適應于Windows的開發與使用,其具體實現步驟如下:
但在這里要實現一個多人的聊天室,故就要引入多線程的開發,在服務端Server要為每一位進入的Client開辟一個獨立線程,而客戶端Client要求收發也要獨立進行,于是就為send和recv過程均開辟一個線程,于是就對上述流程圖進行了一下改進:
? ?這里的服務端要實現廣播的功能就要在主線程內保存每一位在線客戶端的套接字描述符和addr信息,于是就想引入map來建立映射:
/**將接入客戶端的sock描述符與addr建立匹配存入client_map*/map<SOCKET, struct sockaddr_in> client_map;Mutex.lock();client_map[client] = addrClient;count_online++;cout << "新用戶進入:" << temp << ":" << addrClient.sin_port << " 此時在線人數:" << count_online << endl;Mutex.unlock();? 此處的sockaddr_in結構體是引進winsock2.h庫里的定義,具體屬性可以查詢文檔,這里有引入互斥鎖,就是由于每個線程都對Client_map共享資源涉及讀寫操作,造成了讀寫者沖突的問題,當時也沒咋考慮,結果在子線程迭代器遍歷糾錯了半天~,很重要呀!!廣播的大概實現思路如下圖:
在子線程中的實現廣播操作就比較簡單了:
//將聊天信息廣播給每一個客戶端iter = client_map.begin();Mutex.lock();while (temp_iter != 0){char msg[BUFFER_SIZE];memset(msg, 0, sizeof(msg));cout << "發送的port:" << iter->second.sin_port << endl;sprintf_s(msg, "%s,[%s:%d] :%s\n", szDateTime, temp,temp_addr.sin_port, buf);re_s = send(iter->first, msg, strlen(msg), 0);}iter++;}Mutex.unlock();服務端的大概思路就是這樣,至于Bind(),listen(),accpet()過程就不細說了,注意這里由于這里是多客戶端的通信,故Accept()過程就要在循環內不斷輪序處理等待建立鏈接對列。
在開發客戶端時,由于要涉及到UI開發,就打算用c++的QT來實現,沒想到在QT上做多線程可真麻煩呀!!(主要是我太菜了),由于子線程不能對UI進行操作,在recv線程中,當收到消息時,利用信號槽方式通知UI線程刷新TextBrowser,整了我好長時間,,,
recv線程函數(有些累贅的代碼我就給刪了)
//recv線程函數 int MainWindow::recv_thread() {int re = 0;while (1){memset(buf, 0, sizeof(buf));re = recv(client, buf, sizeof(buf), 0);data = "";if (re == SOCKET_ERROR){recv_data = "fail to recv";}else{recv_data = QString::fromUtf8(buf);}data = recv_data;emit emitsendRecvdata();}}開辟新線程并建立信號槽鏈接
QObject::connect(this,SIGNAL(emitsendRecvdata()),this,SLOT(refrach_text()));std::thread t1(MainWindow::recv_thread,this);t1.detach();槽函數來刷=刷新頁面
void MainWindow::refrach_text() {ui->textBrowser->append(data); }至此主題思路就是這樣,但還有很多BUG,比如服務端如何確定長連接的客戶端是否在線,參照了一下其他博客發現可以靠心跳檢測來實現,但我懶得弄了:)
還有一個問題就是字符亂碼的問題,初始設計只能發生英文字符,中文字符會發生亂碼,找了下原因發現是由于QString 與?char * 造成的,解決方法是:在QString轉char是先轉成std::string過渡量;char轉QString可是用QString再帶的fromutf_8函數,親測有效。
?
參考博客:
http://www.cnblogs.com/snaildev/p/7724867.html?心跳包實現思路
總結
以上是生活随笔為你收集整理的基于winsock的局域网聊天室实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 价值7k美刀的Flickr网站漏洞是怎么
- 下一篇: Excel VBA操作网页 显示滚动进度