分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
转自:http://blog.csdn.net/demowolf/archive/2010/05/17/5598879.aspx
折腾了很久TCP IP通信机制。
以前虽然看过bsd tcp/ip的so called 基础通信代码。什么bind, listen ,accept , receive, write, read,但是一直没真正理解。
这次由于公司需求,我狠狠地读了代码,并且搬出QT老本行,开始了QT For windows的编程。
这个大体构架是做一个聊天室软件。
每个client都可以给服务器TCP发消息,服务器通过TCP给各个客户端转发消息。
服务器端代码:
Server.cpp 继承 QTcpServer 主要用来listen to some port , 侦听到端口后, 继承重写了incomingConnection函数,来new 如下的一个
代码
tcpClientSocket.cpp 这个继承QTcpSocket ,用来 server.cpp里被 New 出来,接受各种请求
它重写了函数dataReceived , 即各种客户端发来的请求数据,(注意,这个不是第一步的connect状态,这个是业务逻辑上得请求,比如我给
server发送了“你好” ) 。
这一步处理好后,便开始给各个客户端分发同样的消息“你好” 。使用方法,很简单,QTcpSocket的write方法即可。
这里的细节重点是,在server.cpp里,每个new出来的TcpClientSocket的指针,我放到一个QLIST< TcpClientSocket * >模板里。这样,只要
你不删去这个节点,这个TCP链接就一直存在,嘿嘿,神奇吧。
刚开始我看QT自带example ,fortuneclient and threaded fortune server;我试图着在example的基础上修改代码,一步步达到目的。结果
发现他的业务逻辑,总是write后就自动disconnected, 我以为不disconnected,就能长链接,结果总是出错。
我一直纳闷,这是为什么呢?我用了个List保存了socket的descriptor,以为留着套接字的描述符,就可以下次再调出来用用。实际呢,必须
创建链路的时刻,就保存指针。TCP链接,指针在,链路在。指针亡,链路亡。
这也验证了我的想法,所谓一个真正的通信链路SOCKET的创建,是这样执行下去的。在APP层,我们调用了connect,实际OS对网卡发送了连接
对方的信号,这个电子,一路走过去,直到accept , 这一个链路创建了,在网卡开辟了区域了,在系统OS也开辟了内存,两方都为此一直保持
着这段数据的存在,指针即维系一个网络TCP链路的关键。
这就意味着,客户端无需写什么侦听代码来接受服务器端的消息,直接保持那个链路,消息自然就可以发过来,触发dataReceived信号。
写完代码后,我测试了一下,3个客户端同时链接TCP服务器端的5566端口,全部成功。
曾经很纠结我的所谓端口只能被一个占用。看来,理论远不如实际来的直接。
最后,我还是贴个代码吧。我知道,当一个人寻找各类消息的时候,代码总是最先看得,谁喜欢看人家博客唠叨半天,不讲大道理啊!
服务器端:
- chatserver.h
- *********************
- #ifndef CHATSERVER_H
- #define CHATSERVER_H
- #include <QTcpServer>
- #include <QStringList>
- #include "tcpclientsocket.h"
- class ChatServer : public QTcpServer
- {
- Q_OBJECT
- public:
- ChatServer(QObject *parent = 0,int port=0);
- void PushMessage();
- QList<TcpClientSocket*> tcpClientSocketList;
- signals:
- void updateServer(QString,int);
- public slots:
- void updateClients(QString,int);
- void slotDisconnected(int);
- protected:
- void incomingConnection(int socketDescriptor);
- private:
- QStringList fortunes;
- int onlineDescriptor;
- };
- #endif // CHATSERVER_H
- *********************
- chatserver.cpp
- *********************
- #include "chatserver.h"
- #include "chatthread.h"
- #include <stdlib.h>
- ChatServer::ChatServer(QObject *parent,int port)
- : QTcpServer(parent)
- {
- fortunes << tr("Searching for people...")
- << tr("You've find a people. Try say hello!")
- << tr("You've disconnected.");
- listen(QHostAddress::Any,port);
- }
- void ChatServer::incomingConnection(int socketDescriptor)
- {
- TcpClientSocket *tcpClientSocket=new TcpClientSocket(this);
- connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));
- connect(tcpClientSocket,SIGNAL(disconnect(int)),this,SLOT(slotDisconnected(int)));
- tcpClientSocket->setSocketDescriptor(socketDescriptor);
- tcpClientSocketList.append(tcpClientSocket);
- /*
- onlineDescriptor=socketDescriptor;
- QString fortune = fortunes.at(qrand() % fortunes.size());
- // QString fortune = fortunes.at(0);
- ChatThread *thread = new ChatThread(socketDescriptor, fortune, this);
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
- */
- }
- void ChatServer::updateClients(QString msg, int length)
- {
- // emit updateServer(msg,length);
- for(int i=0;i<tcpClientSocketList.count();i++)
- {
- QTcpSocket *item=tcpClientSocketList.at(i);
- if(item->write(msg.toLatin1(),length)!=length)
- {
- continue;
- }
- }
- }
- void ChatServer::slotDisconnected(int descriptor)
- {
- for (int i=0;i<tcpClientSocketList.count();i++)
- {
- QTcpSocket *item=tcpClientSocketList.at(i);
- if(item->socketDescriptor()==descriptor)
- {
- tcpClientSocketList.removeAt(i);
- return;
- }
- }
- return;
- }
- void ChatServer::PushMessage()
- {
- QString testString;
- testString=