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