【局域网聊天客户端篇】基于socket与Qt

前言

暑假把linux下的高级编程和网络编程学习了一遍,学习很重要,但是也得有个练手的地方,所以必须做做项目来认识下自己所学习的知识。

能够找到小伙伴一起做项目也是一件很快乐的事情的,很幸运的有两个小伙伴一起做这个项目,而我正好负责整个客户端模块,她两负责编写服务器的模块。

开始吧:

项目具体描述:做一个可以实现单个服务器响应多客户端私聊和群聊的聊天工具。具体功能越丰富越好。

下面我以我们做项目的形式来讲讲我们的项目的实现。

项目策划

虽然只是私底下做项目,但是我们还是做了个小小的项目时间和项目实现上的规划,相当于一个实现的计划。

几个问题

这个项目有几个核心的东西必须讨论清楚:

(1)用户信息存储的数据库表

(2)自己定制的信息协议

自己定制协议,这样可以很大程度上放开很多东西,有了自己的协议我可以把所有的东西都变成一条消息,比如在实现私聊,群聊,离线消息,加好友等,都可以设置为一条请求消息和一条对应的回复消息的协议直接进行消息的打包,传输和解析操作。

下面看看外面自己定制的协议:

 1 #ifndef AGREEMENT
 2 #define AGREEMENT
 3
 4 /*
 5 注册:101+用户名长度+用户名+密码长度+密码+密保问题+密保答案长度+密保答案
 6 登录:102+用户名长度+用户名+密码长度+密码
 7 改密:103+用户名长度+用户名+密保问题+密保答案长度+密保答案+密码长度+新密码
 8 退出:104+用户名长度+用户名
 9 加入群聊:105+用户名长度+用户名
10 回复:
11 111+回复类型+消息长度+消息 1:成功,2:用户名重复失败
12 112+回复类型+消息长度+消息 1:成功 2:失败(用户名,密码)
13 113+回复类型+消息长度+消息 1:成功 2:失败(用户名,密保)
14
15
16 201+发送者用户名长度+发送者用户名+接受者用户名长度+接受者用户名+消息长度+消息
17 202+发送者用户名长度+发送者用户名+消息长度+消息
18 203+被禁言用户名长度+被禁言用户名+禁言时间消息(一个字节)
19 204+被删除用户名长度+被删除用户名
20 205+指定用户名长度+指定用户名
21 206+发送者用户名长度+发送者用户名+接受者用户名长度+接受者用户名+消息长度+消息
22 207+发送者用户名长度+发送者用户名+接受者用户名长度+接受者用户名+文件消息长度+文件消息
23 208+用户数量+用户名长度+用户名
24 */
25 //枚举:
26 /*消息类型*/
27 enum{REGISTER,LOGIN,CHPASSWD,QUIT,JOIN,PMSG,QMSG,GAGMSG,DELMSG,SETMSG,LATEMSG,FILEMSG,USERLIST,REG_ACK,LOG_ACK,CHPW_ACK};
28
29 /*101解析*/
30 enum{REG_TYPE,REG_USERLEN,REG_USER,REG_PWLEN,REG_PW,REG_QUE,REG_ANSLEN,REG_ANS};
31 /*102解析*/
32 enum{LOG_TYPE,LOG_USERLEN,LOG_USER,LOG_PWLEN,LOG_PW};
33 /*103解析*/
34 enum{CHPW_TYPE,CHPW_USERLEN,CHPW_USER,CHPW_QUE,CHPW_ANSLEN,CHPW_ANS,CHPW_PWLEN,CHPW_PW};
35 /*104解析*/
36 enum{QUIT_TYPE,QUIT_USERLEN,QUIT_USER};
37 /*105解析*/
38 enum{JOIN_TYPE,JOIN_USERLEN,JOIN_USER};
39
40 /*201解析*/
41 enum{PRI_TYPE,PRI_FROMLEN,PRI_FROM,PRI_TOLEN,PRI_TO,PRI_MSGLEN,PRI_MSG};
42 /*202解析*/
43 enum{QM_TYPE,QM_FROMLEN,QM_FROM,QM_MSGLEN,QM_MSG};
44 /*203解析*/
45 enum{GAG_TYPE,GAG_USERLEN,GAG_USER,GAG_TIME};
46 /*204解析*/
47 enum{DEL_TYPE,DEL_USERLEN,DEL_USER};
48 /*205解析*/
49 enum{SET_TYPE,SET_USERLEN,SET_USER};
50 /*206解析*/
51 enum{LATE_TYPE,LATE_FROMLEN,LATE_FROM,LATE_TOLEN,LATE_TO,LATE_MSGLEN,LATE_MSG};
52 /*207解析*/
53 enum{FILE_TYPE,FILE_FROMLEN,FILE_FROM,FILE_TOLEN,FILE_TO,FILE_MSGLEN,FILE_MSG};
54 /*208解析*/
55 enum{USERL_TYPE,USERL_USERLEN,USERL_USER};
56
57 /*111解析*/
58 enum{REG_ACK_TYPE,REG_ACK_REPLY,REG_ACK_MSGLEN,REG_ACK_MSG};
59 /*112解析*/
60 enum{LOG_ACK_TYPE,LOG_ACK_REPLY,LOG_ACK_MSGLEN,LOG_ACK_MSG};
61 /*113解析*/
62 enum{CHPW_ACK_TYPE,CHPW_ACK_REPLY,CHPW_ACK_MSGLEN,CHPW_ACK_MSG};
63
64 #include <QString>
65 #include <QCryptographicHash>
66
67 QString md5(QString str);
68
69 #endif // AGREEMENT

agreement.h

其中enum(枚举)的定义主要是为了后面的消息解析的连续性。

并且看的出我们的协议是分为两个大组的,最重要的是可扩展性很强,你可以随时的加上一些协议,删除一些协议。灵活性是比较强的。

数据库我们采用的是sqlite本地数据库,数据库表主要是必须定下来防止后续的改动,不能轻易改动。

做项目必须让头脑时刻清醒着,比较好的是在之前建立项目的框架图:

这是我们第一次讨论的框架图,并讨论了几个重要的问题

总的来说,框架很简单,主要就是服务器跟数据库的对话,还有客户端跟服务器的对话,服务器本身可以作为一个管理员的身份。

我主要负责客户端的编写,客户端就是一些信息的解析和发送,并且这次做的是界面的客户端,所以主要还是客户端的界面上的功能的实现。而作为客户端的框架也需要提前想好,这里的主要原因是我用的是Qt界面编程,使用信号与槽的机制进行界面类之间的通信,这里主要的关键在于你的socket只有一个,因为你只能连接一次服务器,就不断开的,所以你的socket在类之间不好传递,所以你就需要在一个界面类中发送所有的socket消息。具体看下下面的一张图界面关系:

通信层的socket在”登陆后的主界面“上,接受的数据包都在这里。

刚开始的时候我把登录界面作为主界面,后来发现这是错误的,因为私聊界面和群聊界面是依托在登陆后的界面上,也就是说如果我以登录界面为socket通信层,那么私聊界面离登录界面有两层的距离,这样通信起来会极大的不方便。

所以写代码前的考虑显得很重要,我因为这个问题整个项目的修改了两次,这在项目中是大忌,因为那个时候你会觉得崩溃的感觉。

下面是我的解析包的代码:

  1 void MyTcpSocket::readyReadSlot()
  2 {
  3     qDebug()<<"have data";
  4     /*read first byte to get msgType*/
  5     while(this->bytesAvailable() > 0)
  6     {
  7         unsigned char oneByte;
  8         if(this->bytesAvailable()>=1 && currType == -1)
  9         {
 10             this->read((char*)&oneByte,1);
 11             qDebug()<<"onebyte:"<<oneByte;
 12
 13             switch(oneByte)
 14             {
 15                 case 111:
 16                     msgType = REG_ACK;
 17                     currType = REG_ACK_TYPE;
 18                     break;
 19                 case 112:
 20                     msgType = LOG_ACK;
 21                     currType = LOG_ACK_TYPE;
 22                     break;
 23                 case 113:
 24                     msgType = CHPW_ACK;
 25                     currType = CHPW_ACK_TYPE;
 26                     break;
 27                 case 201:
 28                     msgType = PMSG;
 29                     currType = PRI_TYPE;
 30                     break;
 31                 case 202:
 32                     msgType = QMSG;
 33                     currType = QM_TYPE;
 34                     break;
 35                 case 203:
 36                     msgType = GAGMSG;
 37                     currType = GAG_TYPE;
 38                     break;
 39                 case 204:
 40                     msgType = DELMSG;
 41                     currType = DEL_TYPE;
 42                     break;
 43                 case 205:
 44                     msgType =  SETMSG;
 45                     currType = SET_TYPE;
 46                     break;
 47                 case 208:
 48                     msgType = USERLIST;
 49                     currType = USERL_TYPE;
 50                     break;
 51                 case 209:
 52                     msgType = BROAD;
 53                     currType = BROAD_TYPE;
 54                     break;
 55
 56
 57                 default:
 58                     qDebug()<<"UNKNOW msgType";
 59                     break;
 60             }
 61
 62         }
 63
 64         /*read next data*/
 65         unsigned char ackType,msgLen;
 66         QByteArray msg;
 67         switch(msgType)
 68         {
 69             case REG_ACK:
 70             {
 71
 72                 if(this->bytesAvailable()>=1 && currType==REG_ACK_TYPE)
 73                 {
 74                     this->read((char*)&ackType,1);
 75                     currType = REG_ACK_REPLY;
 76                     qDebug()<<"ackType"<<ackType;
 77                 }
 78                 if(this->bytesAvailable()>=1 && currType==REG_ACK_REPLY)
 79                 {
 80                     this->read((char*)&msgLen,1);
 81                     currType = REG_ACK_MSGLEN;
 82                     qDebug()<<"msgLen:"<<msgLen;
 83                 }
 84                 if(this->bytesAvailable()>=msgLen && currType==REG_ACK_MSGLEN)
 85                 {
 86                     msg.resize(msgLen);
 87                     this->read(msg.data(),msg.size());
 88                     currType = -1;
 89                     msgType = -1;
 90                     qDebug()<<"msg:"<<QString(msg);
 91                     emit registerAckSignal(ackType,msg);
 92                     qDebug()<<"send register signal";
 93                     ackType = -1;
 94                     msg.clear();
 95                 }
 96                 break;
 97             }
 98             case LOG_ACK:
 99             {
100
101                 if(this->bytesAvailable()>=1 && currType==LOG_ACK_TYPE)
102                 {
103                     this->read((char*)&ackType,1);
104                     currType = LOG_ACK_REPLY;
105                     qDebug()<<"ackType"<<ackType;
106                 }
107                 if(this->bytesAvailable()>=1 && currType==LOG_ACK_REPLY)
108                 {
109                     this->read((char*)&msgLen,1);
110                     currType = LOG_ACK_MSGLEN;
111                     qDebug()<<"msgLen:"<<msgLen;
112                 }
113                 if(this->bytesAvailable()>=msgLen && currType==LOG_ACK_MSGLEN)
114                 {
115                     msg.resize(msgLen);
116                     this->read(msg.data(),msg.size());
117                     currType = -1;
118                     msgType  = -1;
119                     qDebug()<<"msg:"<<QString(msg);
120                     qDebug()<<"login send signal";
121                     emit loginAckSignal(ackType,msg);
122
123                     ackType = -1;
124                     msg.clear();
125                 }
126
127                 break;
128             }
129             case CHPW_ACK:
130             {
131
132                 if(this->bytesAvailable()>=1 && currType==CHPW_ACK_TYPE)
133                 {
134                     this->read((char*)&ackType,1);
135                     currType = CHPW_ACK_REPLY;
136                     qDebug()<<"ackType"<<ackType;
137                 }
138                 if(this->bytesAvailable()>=1 && currType==CHPW_ACK_REPLY)
139                 {
140                     this->read((char*)&msgLen,1);
141                     currType = CHPW_ACK_MSGLEN;
142                     qDebug()<<"msgLen:"<<msgLen;
143                 }
144                 if(this->bytesAvailable()>=msgLen && currType==CHPW_ACK_MSGLEN)
145                 {
146                     msg.resize(msgLen);
147                     this->read(msg.data(),msg.size());
148                     currType = -1;
149                     msgType = -1;
150                     qDebug()<<"msg:"<<QString(msg);
151                     emit chpasswdAckSignal(ackType,msg);
152                     qDebug()<<"chpasswd signal send";
153                     ackType = -1;
154                     msg.clear();
155                 }
156
157                 break;
158             }
159             /*204read del msg*/
160             case DELMSG:
161             {
162                 char userLen;
163                 QByteArray user;
164                 if(this->bytesAvailable()>=1 && currType == DEL_TYPE)
165                 {
166                     this->read((char*)&userLen,1);
167                     currType = DEL_USERLEN;
168                     qDebug()<<"userLen:"<<userLen;
169                 }
170                 if(this->bytesAvailable()>=userLen && currType == DEL_USERLEN)
171                 {
172                     user.resize(userLen);
173                     this->read(user.data(),user.size());
174                     currType = -1;
175                     msgType = -1;
176                     //QMessageBox::information(this,"del","you have been deleted,beacause you a choubi!!!");
177                     qDebug()<<"user:"<<user;
178                     exit(0);
179                 }
180                 break;
181             }
182             case SETMSG:
183             {
184                 QString user;
185                 unsigned char userLen;
186                 if(this->bytesAvailable()>=1 && currType == SET_TYPE)
187                 {
188                     this->read((char*)&userLen,1);
189                     currType = SET_USERLEN;
190                 }
191                 if(this->bytesAvailable()>=userLen && currType == SET_USERLEN)
192                 {
193                     QByteArray ba;
194                     ba.resize(userLen);
195                     this->read(ba.data(),ba.size());
196                     currType = -1;
197                     msgType = -1;
198
199                     user = QString(ba);
200
201                     emit setAdminSignal(user);
202                 }
203                 break;
204             }
205
206
207             /*208read users list*/
208             case USERLIST:
209             {
210                 unsigned char actType,userLen;
211                 QByteArray user;
212                 if(this->bytesAvailable()>=1 && currType == USERL_TYPE)
213                 {
214                     this->read((char*)&actType,1);
215                     currType = USERL_ACT;
216                     qDebug()<<"actType:"<<actType;
217                 }
218                 if(this->bytesAvailable()>=1 && currType == USERL_ACT)
219                 {
220                     this->read((char*)&userLen,1);
221                     currType = USERL_USERLEN;
222                     qDebug()<<"userLen:"<<userLen;
223                 }
224                 if(this->bytesAvailable()>=userLen && currType == USERL_USERLEN)
225                 {
226                     user.resize(userLen);
227                     this->read(user.data(),user.size());
228                     currType = -1;
229                     msgType = -1;
230                     qDebug()<<"user:"<<QString(user);
231                     //emit signal to add user in listWidget
232                     emit addUserSignal(actType,QString(user));
233                 }
234                 break;
235             }
236             case PMSG:
237             {
238                 QString send,rec,time,msg;
239                 unsigned char sendLen,recLen,msgLen;
240                 if(this->bytesAvailable()>=1 && currType == PRI_TYPE)
241                 {
242                     this->read((char*)&sendLen,1);
243                     currType = PRI_FROMLEN;
244                     qDebug()<<"sendLen:"<<sendLen;
245                 }
246                 if(this->bytesAvailable()>=sendLen && currType == PRI_FROMLEN)
247                 {
248                     QByteArray ba;
249                     ba.resize(sendLen);
250                     this->read(ba.data(),ba.size());
251                     send = QString(ba);
252                     currType = PRI_FROM;
253                     qDebug()<<"send:"<<send;
254                 }
255                 if(this->bytesAvailable()>=1 && currType == PRI_FROM)
256                 {
257                     this->read((char*)&recLen,1);
258                     currType = PRI_TOLEN;
259                     qDebug()<<"recLen:"<<recLen;
260                 }
261                 if(this->bytesAvailable()>=recLen && currType == PRI_TOLEN)
262                 {
263                     QByteArray ba1;
264                     ba1.resize(recLen);
265                     this->read(ba1.data(),ba1.size());
266                     rec = QString(ba1);
267                     currType = PRI_TO;
268                     qDebug()<<"rec:"<<rec;
269                 }
270                 if(this->bytesAvailable()>=1 && currType == PRI_TO)
271                 {
272                     this->read((char*)&msgLen,1);
273                     currType = PRI_MSGLEN;
274                     qDebug()<<"msgLen:"<<msgLen;
275                 }
276                 if(this->bytesAvailable()>=msgLen && currType == PRI_MSGLEN)
277                 {
278                     QByteArray ba2;
279                     ba2.resize(msgLen);
280                     this->read(ba2.data(),ba2.size());
281                     time = QString(ba2).mid(0,18);
282                     msg = QString(ba2).mid(19);
283                     qDebug()<<"time:"<<time<<"msg:"<<msg;
284
285                     currType = -1;
286                     msgType = -1;
287
288                     emit priChatMsgSignal(send,send+" "+time+"\n"+msg);
289                 }
290                 break;
291             }
292             case QMSG:
293             {
294                 QString from,time,msg;
295                 unsigned char fromLen,msgLen;
296                 if(this->bytesAvailable()>=1 && currType == QM_TYPE)
297                 {
298                     this->read((char*)&fromLen,1);
299                     currType = QM_FROMLEN;
300                     qDebug()<<"fromLen:"<<fromLen;
301                 }
302                 if(this->bytesAvailable()>=fromLen && currType == QM_FROMLEN)
303                 {
304                     QByteArray ba;
305                     ba.resize(fromLen);
306                     this->read(ba.data(),ba.size());
307                     from = QString(ba);
308                     currType = QM_FROM;
309                     qDebug()<<"from:"<<from;
310                 }
311                 if(this->bytesAvailable()>=1 && currType == QM_FROM)
312                 {
313                     this->read((char*)&msgLen,1);
314                     currType = QM_MSGLEN;
315                     qDebug()<<"msgLen"<<msgLen;
316                 }
317                 if(this->bytesAvailable()>=msgLen && currType == QM_MSGLEN)
318                 {
319                     QByteArray ba;
320                     ba.resize(msgLen);
321                     this->read(ba.data(),ba.size());
322                     time = QString(ba).mid(0,18);
323                     msg = QString(ba).mid(19);
324                     currType = -1;
325                     msgType = -1;
326
327                     qDebug()<<"msg:"<<time<<" "<<msg;
328                     emit groupChatMsgSignal(from+" "+time+"\n"+msg);
329                 }
330                 break;
331             }
332             case BROAD:
333             {
334                 QString msg;
335                 unsigned char msgLen;
336                 if(this->bytesAvailable()>=1 && currType == BROAD_TYPE)
337                 {
338                     this->read((char*)&msgLen,1);
339                     currType = BROAD_MSGLEN;
340                     qDebug()<<"msgLen:"<<msgLen;
341                 }
342                 if(this->bytesAvailable()>=msgLen && currType == BROAD_MSGLEN)
343                 {
344                     QByteArray ba;
345                     ba.resize(msgLen);
346                     this->read(ba.data(),ba.size());
347                     currType = -1;
348                     msgType = -1;
349                     msg = QString(ba);
350                     emit broadMsgSignal(msg);
351                 }
352                 break;
353             }
354             case GAGMSG:
355             {
356                 QString user;
357                 unsigned char userLen;
358                 char time;
359                 if(this->bytesAvailable()>=1 && currType == GAG_TYPE)
360                 {
361                     this->read((char*)&userLen,1);
362                     currType = GAG_USERLEN;
363                     qDebug()<<"userLen:"<<userLen;
364                 }
365                 if(this->bytesAvailable()>=userLen && currType == GAG_USERLEN)
366                 {
367                     QByteArray ba;
368                     ba.resize(userLen);
369                     this->read(ba.data(),ba.size());
370                     currType = GAG_USER;
371                     user = QString(ba);
372                     qDebug()<<"user:"<<user;
373                 }
374                 if(this->bytesAvailable()>=1 && currType == GAG_USER)
375                 {
376                     this->read((char*)&time,1);
377                     currType = -1;
378                     msgType = -1;
379                     qDebug()<<"time:"<<time;
380                     emit gagMsgSignal(user,time);
381                 }
382                 break;
383             }
384
385
386             default:
387             qDebug()<<"UNKNOW msgType2";
388             break;
389         }//switch
390     }//while
391 }//readData

基本上是一个模式的解析,这里用上了之前定于的枚举解析,很方便的防止包不完整的情况的发生

总结

我们用了四天做完了这个项目,做完后的感觉是,一些基础的知识很重要,这个项目的基础知识你必须手到擒来。在写代码前一定要把很多东西考虑清楚,想清楚之后去写代码就只是做码农的工作了,只是客户端的逻辑复杂一点点。在协议,框架等东西都很确定的情况下,你就不会晕,而是给自己一个模块一个模块的去写出来,所以,框架才是最重要的。

时间: 2024-10-12 11:52:09

【局域网聊天客户端篇】基于socket与Qt的相关文章

Mina airQQ聊天 客户端篇(三)

开发工具 (FlashBuilder4.7) 程序类型(Adobe Air) Flex Air做的桌面程序,效果还挺好看的,最主要是Socket这一块,它也是异步的,并且在Flex中的事件机制比较强大(个人认为) 有改一些样式,重新看看新的效果吧: 大致的实现方式: 在WindowedApplication中包含登陆窗口和主界面,用Flex中的状态来切换,聊天窗口时Window组件,好友列表用树菜单 实现好友分组,好友上线时改成在线图标,收到消息时头像抖动,聊天显示实现图文混排,系统托盘,其它貌

聊天程序(基于Socket、Thread)

聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现了服务端跟多个客户端之间的聊天,可以群发消息,选择ip发消息,客户端向服务端发送文件. (例子为WinForm应用程序) Socket,端口,Tcp,UDP. 概念 1.Socket还被称作"套接字",应用程序通常通过套接字向网络发送请求或者应答网络请求.根据连接启动的方式以及本地套接字要

C#基于Socket的CS模式的完整例子

基于Socket服务器端实现本例主要是建立多客户端与服务器之间的数据传输,首先设计服务器.打开VS2008,在D:\C#\ch17目录下建立名为SocketServer的Windows应用程序.打开工程,往当前窗体中添加控件,如表17-6所示.表17-6  添加控件列表 控    件 Name Text ListBox lbInfo Label label Button button1 启动服务器 设计好的界面如图17-2所示. 接下来开始运用前面的知识设计服务器,主要分为以下步骤.(1)首先是

Qt学习心得之网络编程简单的局域网聊天服务端建立

学而不思则罔,思而不学则殆.学习和思考是相辅相成的,通过这几天对网络编程的学习,收获颇丰.接下来我将利用Qt做的一个以TcpIp协议为传输方式的简单的局域网聊天服务端与大家分享下: 首先谈谈我个人对Tcp协议的理解:Tcp就是网上购物,买家和买家之间的物品传递,快递公司的扮演.快递公司将卖家所要寄出的物品进行包装,给予独特的号码,并从卖家获取目的地地址,得知这些明确信息后准确将物品送到买家,买家签收后,卖家通过快递单号查询到买家签收的消息. 其次是这个简单局域网聊天服务器的创建思路.如下图是思路

基于EPOLL模型的局域网聊天室和Echo服务器

一.EPOLL的优点 在Linux中,select/poll/epoll是I/O多路复用的三种方式,epoll是Linux系统上独有的高效率I/O多路复用方式,区别于select/poll.先说select/poll的缺点,以体现epoll的优点. select: (1)可监听的socket受到限制,在32位的系统中,默认最大值为1024. (2)采用轮询方式,当要监听的sock数量很大时,效率低. (3)随着要监听socket数据的增加,要维护一个存放大量fd的数据结构,系统开销太大. pol

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating-a-wpf-chat-client-server-application/ 注意:本教程是相当广泛的,如果你是在短请也看到我们的东西 开始和 如何在几分钟内创建一个客户端服务器应用程序教程. 注2:本例中包括,明显延长进一步证明功能,在包中包含的示例 包下载. 在我们开始之前确保您已经安装了Vis

基于Socket的Android聊天室

1        基于Socket的Android聊天室 Socket通信是网络通信中最常用的技术之一,通过Socket建立的可靠连接,可以让多个终端与服务器保持通信,最典型的应用是建立一个多人聊天程序.本实例使用ServerSocket建立聊天服务器.将服务器端所有的通讯线程保存到一个集合当中,当有用户发来数据,则转发给所有用户,实现聊天室效果.Android端通过使用Socket建立客户端链接,并且在AsyncTask中执行网络读写的任务,将用户输入的内容发送到服务器,并接收服务器发来的数据

QT实现局域网聊天工具

三年多以前刚学习QT写的一个局域网聊天工具小项目. 由于是初学QT时写的,代码比较简略,也没时间好好整理项目,仅供大家参考相关TCP以及UDP的连接与传输功能   以及相关控件的基本使用方法. 需要源码学习的留下邮箱~ 1. 客户端程序函数说明 //连接服务器: tcpSocket = new QTcpSocket(this); tcpSocket->connectToHost(serverIP,8000); //断开服务器: tcpSocket->disconnectFromHost();

Qt局域网聊天

原文地址 https://blog.csdn.net/tsvico/article/details/94721560 本次设计是一个简易的局域网聊天,功能设计主要分为群聊和私聊两部分,每部分都支持基础聊天以及文件传输功能,私聊页面相较于主页面支持更多功能,例如表情发送.窗口抖动,语音聊天等.参考了<Qt及Qt Quick开发实战精解>中第5章群聊实例,在群聊的基础设计了私聊这部分内容以及其他一些功能.下面介绍下整体的设计以及实现. 本文档将依据启动次序来写 设计时这里用的是主机的ip地址,可使