日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于Qt的简易聊天室设计

發(fā)布時(shí)間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Qt的简易聊天室设计 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

服務(wù)器端實(shí)現(xiàn):

第一步:封裝自己的tcp通信類
//tcpserver.h #ifndef TCPSOCKETSERVER_H #define TCPSOCKETSERVER_H#include <string> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stdbool.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ #include <arpa/inet.h>/*in_addr_t inet_addr(const char *cp);*/ /*uint16_t htons(uint16_t hostshort);*/ /*int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);*/ /*ssize_t recv(int sockfd, void *buf, size_t len, int flags);*/class CTcpSocket{ public:CTcpSocket(int port); ~CTcpSocket(); int createSocket(); /*創(chuàng)建套接字*/int getAccpet(); /*接收客戶端請(qǐng)求并創(chuàng)建一個(gè)用于通信的套接字*/std::string socketRecv(int clientSocketfd); /*接收數(shù)據(jù)*/bool socketSend(int clientSocketfd,std::string strSend); /*發(fā)送數(shù)據(jù)*/void closeCliSocket(int clientfd);void closeScvSocket();private:int m_nPort; int m_nServerfd;struct sockaddr_in m_sock_addr,m_client_addr;socklen_t m_addrlen;char *m_pRcvbuf;char *m_pSendbuf; };#endif //tcpserver.cpp #include "tcpserver.h"#define BUF_SIZE 1024CTcpSocket::CTcpSocket(int port) {m_nPort = port;m_pSendbuf = new char[BUF_SIZE];if(!m_pSendbuf){fprintf(stderr,"mem alloc failure!\n");}m_pRcvbuf = new char[BUF_SIZE];if(!m_pRcvbuf){fprintf(stderr,"mem alloc failure!\n");} }CTcpSocket::~CTcpSocket() { if (m_pSendbuf){delete[] m_pSendbuf;m_pSendbuf = NULL;}if (m_pRcvbuf){delete[] m_pRcvbuf;m_pRcvbuf = NULL;} }int CTcpSocket::createSocket() {//step 1 create socketm_nServerfd = socket(AF_INET, SOCK_STREAM, 0);if (m_nServerfd < 0){perror("socket()");return -1;}int nZero = 1;int ret = setsockopt(m_nServerfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&nZero, sizeof(int));if (ret < 0){perror("setsocket()");return -2;}//step 2 bind socketm_sock_addr.sin_family = AF_INET;m_sock_addr.sin_port = htons(m_nPort);//sock_addr.sin_addr.s_addr = inet_addr("192.168.155.6");m_sock_addr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANYret = bind(m_nServerfd, (struct sockaddr *)&m_sock_addr, sizeof(m_sock_addr));if (ret < 0){perror("bind()");return -3;}//step 3 start listenret = listen(m_nServerfd, 5); //Up to 11 device connections are allowedif (ret < 0){perror("listen()");return -4;}return m_nServerfd; }int CTcpSocket::getAccpet() {//step 4 receive client request and create a new socketint nRetClientfd = accept(m_nServerfd, (struct sockaddr *)&m_client_addr, &m_addrlen);if (nRetClientfd < 0){perror("accept()");return -1;}return nRetClientfd; }std::string CTcpSocket::socketRecv(int clientSocketfd) {//step 4 read data bufmemset(m_pRcvbuf, 0, BUF_SIZE);int ret = recv(clientSocketfd, m_pRcvbuf, BUF_SIZE, 0);if (ret < 0){perror("recv()");return "recv error";}if (ret == 0){close(clientSocketfd);return "client exit";}std::string retstr = std::string(m_pRcvbuf, ret);return retstr; }bool CTcpSocket::socketSend(int clientSocketfd,std::string strSend) {memset(m_pSendbuf, '\0', BUF_SIZE);strcpy(m_pSendbuf, strSend.c_str());int ret = send(clientSocketfd, m_pSendbuf, BUF_SIZE, 0);if (ret < 0){perror("send()");return false;}return true; }void CTcpSocket::closeScvSocket() {close(m_nServerfd); }void CTcpSocket::closeCliSocket(int clientfd) {close(clientfd); }
第二步:main.cpp邏輯處理
#include "tcpserver.h" #include <iostream> #include <string> #include <map> #include <vector> #include <iterator> #include <pthread.h> #include <unistd.h> #include <ctime>struct chatroom {std::string room;std::string user; };std::map<int, struct chatroom> mapClientfd; //用于保存客戶端套接字 CTcpSocket tcpsocket(8889);void *thread_start(void *arg); bool deleteRoom(int clientfd); std::vector<std::string> mysplite(const std::string &strSrc, const std::string &strSep); bool addUser(std::string strRoomNo, std::string strUser, int clientfd); void sendUserInfo(int clientfd, struct chatroom mychatroom); std::string getSysDate(); void sendMsgtoAllcli(int clientfd, std::string strSend);int main() {pthread_t tid;tcpsocket.createSocket();while (1){int clientfd = tcpsocket.getAccpet();if (clientfd < 0){std::cout << "server accept exeception!" << std::endl;exit(-1);}printf("clientfd:%d",clientfd);int nRet = pthread_create(&tid, NULL, thread_start, (void *)&clientfd);if (nRet != 0){perror("pthreadd_create()");exit(-2);}pthread_detach(tid);}return 0; }//線程并發(fā) void *thread_start(void *arg) {int clientfd = *((int *)arg);while (1){std::string strRet = tcpsocket.socketRecv(clientfd);if (strRet == "client exit"){//先保存要?jiǎng)h除的房間號(hào)和用戶名struct chatroom mychatroom = mapClientfd[clientfd];//刪除鍵為clientfd的元素deleteRoom(clientfd);sendUserInfo(clientfd,mychatroom);tcpsocket.closeCliSocket(clientfd);return NULL;}std::cout << "服務(wù)器收到:" << strRet << std::endl;//命令解析 判斷前面幾個(gè)字符std::cout << "(0,7):" << strRet.substr(0,7) << std::endl; if(strRet.substr(0,7) == "useradd"){//獲得房間號(hào)std::string strRoomNo = mysplite(strRet.substr(7,strRet.length())," ")[0];//獲得用戶昵稱std::string strUser = mysplite(strRet.substr(7,strRet.length())," ")[1];//添加用戶addUser(strRoomNo,strUser,clientfd);}else if (strRet.substr(0,7) == "dispsvr"){//獲取系統(tǒng)時(shí)間std::string strDate = getSysDate();//拼裝數(shù)據(jù)std::string strSend = strRet.substr(0, 7); //dispsvrstrSend += strDate;strSend += "@";strSend += mapClientfd[clientfd].user;strSend += ":";strSend += strRet.substr(7, strRet.length());std::cout << strSend << std::endl;//群發(fā)sendMsgtoAllcli(clientfd, strSend);}} }//刪除map指定元素 bool deleteRoom(int clientfd) {bool bRet = false;for (std::map<int, struct chatroom>::iterator iter = mapClientfd.begin(); iter != mapClientfd.end(); iter++){if (iter->first == clientfd){std::cout << "刪除房間:" << iter->second.room << "用戶:" << iter->second.user << std::endl;mapClientfd.erase(iter);bRet = true;}}return bRet; }//添加好友 bool addUser(std::string strRoomNo, std::string strUser, int clientfd) {//判斷是否已有該用戶bool flag = true;for (std::map<int, struct chatroom>::iterator iter = mapClientfd.begin(); iter != mapClientfd.end(); iter++){//房間中用戶已存在if (strRoomNo == iter->second.room && strUser == iter->second.user){flag = false;}}if (flag) //該昵稱可以在該房間使用{struct chatroom myroom;myroom.room = strRoomNo;myroom.user = strUser;//添加用戶mapClientfd[clientfd] = myroom;sendUserInfo(clientfd,myroom);}else{bool bRet = tcpsocket.socketSend(clientfd, "existed");if (bRet == false){std::cout << "send data failure! 165" << std::endl;}}return true; }//轉(zhuǎn)發(fā)當(dāng)前用戶 void sendUserInfo(int clientfd, struct chatroom mychatroom) {//封裝即將發(fā)送給客戶端的數(shù)據(jù)std::string strSend = "curroom";for (std::map<int, struct chatroom>::iterator iter = mapClientfd.begin(); iter != mapClientfd.end(); iter++){if(iter->second.room == mychatroom.room){strSend += iter->second.user;strSend += " ";}}//將當(dāng)前所有用戶廣播for (std::map<int, struct chatroom>::iterator iter = mapClientfd.begin(); iter != mapClientfd.end(); iter++){//轉(zhuǎn)發(fā)到同組房間if(iter->second.room == mychatroom.room){//發(fā)送數(shù)據(jù)bool bRet = tcpsocket.socketSend(iter->first, strSend);if (bRet == false){std::cout << "send data failure! 151" << std::endl;}else{std::cout << strSend << "轉(zhuǎn)發(fā)到:" << iter->first << "成功" << std::endl;} }} }//自定義字符串分割函數(shù) std::vector<std::string> mysplite(const std::string &strSrc, const std::string &strSep) {using namespace std;vector<string> vecResult;int offset = 0;int index = 0;while (index != std::string::npos){index = strSrc.find(strSep, offset);string strTemp = strSrc.substr(offset, index - offset);vecResult.push_back(strTemp);offset = index + strSep.length();}return vecResult; }//獲取系統(tǒng)時(shí)間 std::string getSysDate() {//獲取系統(tǒng)時(shí)間time_t timep;struct tm *p;time(&timep);p = gmtime(&timep);int year = p->tm_year + 1990;int month = p->tm_mon + 1;int day = p->tm_mday;int hour = p->tm_hour + 8;int minute = p->tm_min;int second = p->tm_sec;char charDate[256] = {'\0'};sprintf(charDate,"%d-%d-%d %d:%d:%d",year,month,day,hour,minute,second);return charDate; }void sendMsgtoAllcli(int clientfd, std::string strSend) {for (std::map<int, struct chatroom>::iterator iter = mapClientfd.begin(); iter != mapClientfd.end(); iter++){//轉(zhuǎn)發(fā)到同組房間if(iter->second.room == mapClientfd[clientfd].room){//發(fā)送數(shù)據(jù)bool bRet = tcpsocket.socketSend(iter->first, strSend);if (bRet == false){std::cout << "send data failure! 248" << std::endl;}else{std::cout << strSend << "轉(zhuǎn)發(fā)到:" << iter->first << "成功" << std::endl;} }} }
第三步:makefile文件
//makefile文件 CC = g++ MV = mv CP = cp RM = rmLIBTHREAD = -lpthread CFLAGS = -g BIN = ../binall: $(BIN)/server$(BIN)/server:tcpserver.o main.o$(CC) -o $@ $^ $(LIBTHREAD) .SUFFIXES:.cpp .o .cpp.o:$(CC) $(CFLAGS) -c $*.cpp -o $*.o -Wall.PHONY:clean clean:rm -rf *.o $(BIN)/server

Qt客戶端實(shí)現(xiàn)

#include "chatwidget.h" #include "ui_chatwidget.h"ChatWidget::ChatWidget(QWidget *parent) :QWidget(parent),ui(new Ui::ChatWidget) {ui->setupUi(this);ui->textEdit_ALL->setStyleSheet("QTextEdit { background: #cc9966 }");ui->textEdit_SEND->setStyleSheet("QTextEdit { background: #cccccc }");ui->textEdit_RECV->setStyleSheet("QTextEdit { background: #cccccc }");ui->textEdit_SEND->installEventFilter(this);//設(shè)置完后自動(dòng)調(diào)用其eventFilter函數(shù)//設(shè)置焦點(diǎn)setFocustoEnd();tcpsocket = new QTcpSocket(this);//接收數(shù)據(jù)connect(tcpsocket,&QTcpSocket::readyRead,[=](){QString strRecv = tcpsocket->readAll().data();qDebug() << strRecv;if(!strRecv.isEmpty()){if(strRecv.mid(0,7) == "curroom"){//只獲取昵稱ui->textEdit_ALL->clear();QStringList strList = strRecv.mid(7,strRecv.length()).split(" ");for(int i=0; i<strList.size(); i++){QString strMsg = QString("%1%2%3").arg("<font color=\"#FFFFFF\">").arg(strList[i]).arg("</font>");ui->textEdit_ALL->append(strMsg);}}else if(strRecv.mid(0,7) == "dispsvr"){QString strMsg = QString("%1%2%3").arg("<font color=\"#111111\">").arg(strRecv.mid(7,strRecv.length())).arg("</font>");ui->textEdit_RECV->append(strMsg);}else{QMessageBox::warning(this,"溫馨提示","昵稱已被使用,請(qǐng)更換");}QApplication::alert(this);}}); }ChatWidget::~ChatWidget() {delete ui;delete tcpsocket; }//退出 void ChatWidget::on_pushButton_EXIT_clicked() {this->close(); }//清空 void ChatWidget::on_pushButton_CLEAR_clicked() {ui->textEdit_SEND->clear();setFocustoEnd(); }//發(fā)送 void ChatWidget::on_pushButtonSEND_clicked() {//獲取用戶輸入的信息QString strData = "dispsvr";strData += ui->textEdit_SEND->toPlainText();if(strData.mid(0,7) == "dispsvr" && strData.length() > 7){tcpsocket->write(strData.toUtf8());tcpsocket->waitForBytesWritten();this->tcpsocket->flush();ui->textEdit_SEND->clear();setFocustoEnd();} }//回車(chē)鍵發(fā)送 bool ChatWidget::eventFilter(QObject *target, QEvent *event) {if(target == ui->textEdit_SEND){if(event->type() == QEvent::KeyPress)//回車(chē)鍵{QKeyEvent *k = static_cast<QKeyEvent *>(event);if(k->key() == Qt::Key_Return){//獲取用戶輸入的信息QString strData = "dispsvr";strData += ui->textEdit_SEND->toPlainText();//發(fā)送消息tcpsocket->write(strData.toUtf8());tcpsocket->waitForBytesWritten();this->tcpsocket->flush();if(strData.mid(0,7) == "dispsvr" && strData.length() > 7){ui->textEdit_SEND->clear();setFocustoEnd();}return true;}}}return QWidget::eventFilter(target,event); }//登錄 void ChatWidget::on_pushButton_login_clicked() {//連接到服務(wù)器QString ip = ui->lineEdit_IP->text();quint16 port = ui->lineEdit_PORT->text().toUShort();tcpsocket->connectToHost(QHostAddress(ip),port);//發(fā)送房間號(hào)+昵稱QString room = "useradd";room += ui->lineEdit_ROOM->text();room += " ";room += ui->lineEdit->text();tcpsocket->write(room.toUtf8());setFocustoEnd(); }void ChatWidget::setFocustoEnd() {//設(shè)置自動(dòng)換行ui->textEdit_SEND->setFocus();// 光標(biāo)移動(dòng)到最后, 并設(shè)置擁有焦點(diǎn)QTextCursor textcusor = ui->textEdit_SEND->textCursor();textcusor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);ui->textEdit_SEND->setTextCursor(textcusor);ui->textEdit_SEND->setFocus(Qt::MouseFocusReason); }void ChatWidget::on_pushButtot_CLEAR_clicked() {ui->textEdit_RECV->clear();ui->textEdit_SEND->clear(); }

運(yùn)行步驟

一、服務(wù)器端程序放到Linux系統(tǒng)下使用make編譯
二、將編譯生成的目標(biāo)文件放到阿里服務(wù)器下執(zhí)行:nohup ./server &
三、運(yùn)行客戶端,修改房間號(hào)和昵稱登錄。

總結(jié)

以上是生活随笔為你收集整理的基于Qt的简易聊天室设计的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。