服务器
- 新建工程,Base class选择QWidget,在工程文件tcpServer.pro中添加一行代码:QT += network。
QT += core gui
QT += network
ui中添加一个label,用于显示状态信息。
在widget.h文件中做以下更改。
添加头文件:
#include<QtNetwork/QtNetwork>
添加private对象:
QTcpServer *tcpServer;
添加私有槽函数:
private slots:
void sendMessage();
4.在widget.cpp文件中进行更改。
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
tcpServer = new QTcpServer(this);
if(!tcpServer->listen(QHostAddress::LocalHost,6666))
{ //监听本地主机的6666端口,如果出错就输出错误信息,并关闭
qDebug() << tcpServer->errorString();
close();
}
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));
}
监听主机的6666端口,然后关联了newConnection()和我们自己的sendMessage()函数。这时候是准备状态,服务器的socket并没有被打开。
如果6666端口有来自客户端socket请求,也就是客户端请求连接服务器,服务器的socket会被动打开,开始接受客户端的情求,此时服务器的socket阻塞,禁止接受其他客户端的socket请求,知道客户端返回信息后才返回。
第一次握手:客户端尝试连接服务器,向服务器发送syn包(同步序列编号Synchronize Sequence Numbers),syn=j,客户端进入SYN_SEND状态等待服务器确认
第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
void Widget::sendMessage()
{
QByteArray block; //用于暂存我们要发送的数据
QDataStream out(&block,QIODevice::WriteOnly);
//使用数据流写入数据
out.setVersion(QDataStream::Qt_4_6);
//设置数据流的版本,客户端和服务器端使用的版本要相同
out<<(quint16) 0;
out<<tr("你好啊!!!");
out.device()->seek(0);
out<<(quint16) (block.size()-sizeof(quint16));
//out<< (quint16) (block.size()–sizeof(quint16));
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
//我们获取已经建立的连接的子套接字
connect(clientConnection,SIGNAL(disconnected()),clientConnection,
SLOT(deleteLater()));
clientConnection->write(block);
clientConnection->disconnectFromHost();
ui->statusLabel->setText("send message successful!!!");
//ui->statusLabel->setText(“send message successful!!!”);
//发送数据成功后,显示提示
}
数据发送函数:
1. 为了客户端收到完整的文件大小,最开始写入完整文件的大小信息,服务器端最开始无法预知发送文件的大小,所以我们先使用了out<<(quint16) 0;在block的开始添加了一个quint16大小的空间,也就是两字节的空间,它用于后面放置文件的大小信息。然后out<
clientConnection->write(block);
将block的数据写入到建立连接的Tcp socket中
然后是clientConnection->disconnectFromHost();它表示当发送完成时就会断开连接,这时就会发出disconnected()信号,而最后调用deleteLater()函数保证在关闭连接后删除该套接字clientConnection。