學而不思則罔,思而不學則殆。學習和思考是相輔相成的,經過這幾天對網絡編程的學習,收穫頗豐。接下來我將利用Qt作的一個以TcpIp協議爲傳輸方式的簡單的局域網聊天服務端與你們分享下:編程
首先談談我我的對Tcp協議的理解:Tcp就是網上購物,買家和買家之間的物品傳遞,快遞公司的扮演。快遞公司將賣家所要寄出的物品進行包裝,給予獨特的號碼,並從賣家獲取目的地地址,得知這些明確信息後準確將物品送到買家,買家簽收後,賣家經過快遞單號查詢到買家簽收的消息。數組
其次是這個簡單局域網聊天服務器的建立思路。以下圖是思路的框圖:服務器
一個服務器的創建,必需要有對外雙向通信的接口就是套接字(socket),因此須要建一個Mysocket的類,這樣才能夠將不一樣客戶端的消息發給其餘客戶端。以後還須要再建立一個Myserver的類,將每一個客戶端發送的消息經過Mysocket發送信號被接受。而後在每一個客戶端對應的每一個Myserver中將各自發送的信號發送給其餘客戶端,並再發送給server在UI界面上顯示。如圖:在Mysocket和Myserver以及Myserver和server之間的聯繫都是經過發送信號,並利用槽函數進行處理,因此這整個程序的關鍵是合理運用信號和槽函數,將信息順利傳達。網絡
而後是程序的展現和一些關鍵點的處理方式。socket
//========================Mysocket.c=============================//tcp
MyTcpSocket::MyTcpSocket(QObject *parent) :/*在構造函數中進行信號和槽函數的鏈接*/函數
QTcpSocket(parent)學習
{網站
connect(this,SIGNAL(readyRead()), /*讀信號和對應的槽函數處理*/ui
SLOT(slotReadyread()));
connect(this,SIGNAL(disconnected()), /*斷開鏈接的信號和對應的槽函數處理*/
SLOT(slotDisconnect()));
}
void MyTcpSocket::slotReadyread()
{
QString msg;
QByteArray ba; /*採用QByteArray字節數組的方式客戶端發送消息進行讀取* /
ba.resize(this->bytesAvailable()); /*判斷是否可讀*/
this->read(ba.data(),ba.size()); /*讀取客戶端發送的消息*/
msg=QString(ba); /*將接收到的消息轉化爲QString類型*/
emit updatemsg(msg,this->socketDescriptor(),this->peerAddress().toString());/*將客戶端的信息經過信號的方式發送出去(信號包括客戶端輸入內容、客戶端對應的描述符以及客戶端的IP地址)*/
}
void MyTcpSocket::slotDisconnect()
{
qDebug("Disconnect host");
emit signalDisconnect(this->socketDescriptor()); /*將斷開的客戶端所對應的描述符信號發送出去*/
}
//========================Myserver.c=============================//
MyTcpserver::MyTcpserver(QObject *parent) : /*在構造函數中監聽*/ QTcpServer(parent)
{
listen(QHostAddress::Any,8080);/*監放任何客戶端IP地址的連入,以及端口號爲8080的*/
/**/
}
void MyTcpserver::incomingConnection(qintptr socketDescriptor){/*incomingConnection這個函數在服務端被客戶端鏈接上後自動調用此函數,傳入的參數爲該客戶端特有的描述符*/
qDebug("incomingConnection");
MyTcpSocket* sock = new MyTcpSocket; /*新建一個Mysocket的對象*/
sock->setSocketDescriptor(socketDescriptor); /*設置sock的描述符*/
connect(sock,SIGNAL(signalDisconnect(qintptr)),
this,SLOT(slotDisconnect(qintptr))); /*斷開鏈接的信號和對應的槽函數處理*/
connect(sock,SIGNAL(updatemsg(QString,qintptr,QString)),
this,SLOT(slotupdatemsg(QString,qintptr,QString)));/*將Mysocket發送過來客戶端的信息進行處理,用於發送給UI界面*/
connect(sock,SIGNAL(updatemsg(QString,qintptr,QString)),
this,SLOT(slotrecivermsg(QString,qintptr,QString)));/*將Mysocket發送過來客戶端的信息進行處理,再發送給其餘連入的客戶端*/
clients << sock; /*建立的一個QList的容器類名爲clients,將每一個不一樣的客戶端放入到該容器中,以便後續處理*/
}
void MyTcpserver::slotDisconnect(qintptr sockfd)/*斷開槽函數處理主要是將斷開的客戶端從容器中移除*/
{
int i=0;
for(i=0;i<clients.count();i++){ /*遍歷容器中存入的客戶端*/
if(clients.at(i)->socketDescriptor()==sockfd){/*當找到容器中對應的那個斷開的客戶端後,將其移除*/
clients.removeAt(i);
break;
}
}
}
void MyTcpserver::slotupdatemsg(QString msg,qintptr sockfd,QString IP)
{
qDebug()<<"slotupdatemsgServer";
emit updatemsgServer(msg,IP); /*將客戶端信息經過信號的方式傳送給UI界面*/
}
void MyTcpserver::slotrecivermsg(QString msg,qintptr sockfd,QString IP)
{
QString message;
message=IP+" : "+msg; /*設定回覆給其餘客戶端的信息格式*/
int i=0;
for(i=0;i<clients.count();i++){
if(clients.at(i)->socketDescriptor()!=sockfd){ /*遍歷容器中存入的客戶端*/
clients.at(i)->write(message.toLatin1(),message.length());/*將消息發送給除本身之外的全部連入的客戶端*/
}
}
}
//========================server.c=============================//
tcpserver::tcpserver(QWidget *parent) : /*在構造函數中進行信號和槽函數的鏈接*/
QWidget(parent),
ui(new Ui::tcpserver)
{
ui->setupUi(this);
server = new MyTcpserver; /*新建一個MyTcpserver對象*/
connect(server,SIGNAL(updatemsgServer(QString,QString)),
this,SLOT(recivermsg(QString,QString)));/*將MyTcpservert發送過來客戶端的信息進行界面顯示處理*/
}
tcpserver::~tcpserver() /*析構函數中釋放ui*/
{
delete ui;
}
void tcpserver::recivermsg(QString msg,QString IP)
{
qDebug("recivermsg");
qDebug()<<msg;
ui->listWidget->addItem(IP+" : "+msg); /*顯示發送的信號到UI界面上*/
}
最後感謝匯文,在匯文培訓學習也有三個多月了,在這個融洽的你們庭中,感受天天都很充實,在學習中實踐,在實踐中收穫,願本身在未來能找到一份合適的工做。附上匯文網站可供瀏覽:www.huiwen.com