socket是一种实现网络不同主机进程通信的一种机制。根据是否面向连接,可以将socket通信分为面向连接的数据流和面向无连接的数据报通信。两者在实现的地方,有类似的地方:都需要创建相应的socket对象。但是,两者也有一定的区别。面向连接的TCP通信需要双方建立可行的数据连接后才能通信,而面向无连接的UDP通信则只是简单的将数据发送到对应的目标主机即可。
一、TCP通信编程流程
面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。这个过程类似打电话,先拨号振铃,等待对方接听后,才能进行通话。在一个TCP连接中,仅有2方进行彼此通信,广播和多播不能用于TCP。
首先,在linux上服务器端的工作流程:
(1)建立socket对象,指定通信协议。
(2)将创建的socket对象与当前主机的某个IP地址和端口绑定。
(3)使socket对象处于监听状态,并设置监听队列的大小。
客户端的工作流程:
(1)建立socket对象,指定通信协议。
(2)应用程序可以显式的绑定IP地址和端口。
接着建立通信连接。
(1)客户端向服务器发出连接请求。
(2)服务器监听到该请求,并接受请求,从而建立连接。
然后双方发送接收数据。
通信完成后,双方都需要关闭socket对象。
在Qt中,对一些函数进行了封装。使用起来更方便。在Qt中的TCP服务器封装在QTcpServer这个类中,TCP客户端封装在QTcpSocket这个类中。
Qt中TCP服务器的使用:
(1)创建TCP服务器:
QTcpServer *tcpServer;
tcpServer = new QTcpServer(this);
(2)TCP服务器监听:
tcpServer->listen(QHostAddress::Any,ui->txtPortServer->text().toInt() //ui->txtPortServer->text().toInt()是服务器的端口号
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnect()));
当有新的连接时,触发newConnect()函数。
void MainWindow::newConnect()
{
tcpClient = tcpServer->nextPendingConnection(); //得到每个连进来的socket
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readMessageFromTCPClient())); //有可读的信息,触发读函数槽
}
当客户端向服务器发送数据的时候,准备接收数据。
Qt中TCP客户端的使用:
(1)创建TCP客户端:
QTcpSocket *tcpClient;
tcpClient = new QTcpSocket(this);
(2)TCP客户端连接服务器:
tcpClient->connectToHost(ui->txtIPServer->text(),ui->txtPortServer->text().toInt());//ui->txtIPServer->text()是服务器的IP地址
//ui->txtPortServer->text().toInt()是服务器的端口号
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readMessageFromTCPServer()));
TCP 客户端连接TCP服务器后,将客户端的readRead()信号和readMessageFromTCPServer()槽函数进行连接,准备读服务器发送过来的数据。
然后双方发送接收数据:
TCP服务器和TCP客户端的发送数据:
QString strMesg= ui->lineEdit->text();
tcpClient->write(strMesg.toStdString().c_str(),strlen(strMesg.toStdString().c_str())); //发送数据
TCP服务器接收数据:
QByteArray qba= tcpClient->readAll(); //读取客户端发来的数据
TCP客户端接收数据:
QByteArray qba= tcpClient->readAll(); //读取服务器发来的数据
二、UDP通信编程流程
面向无连接的socket通信是不可靠传输,在通信前不需要建立可靠连接。双方实现数据他哦给那些的基本流程如下:
首先,服务器工作流程:
(1)建立socket对象,指定通信协议。
(2)将创建的soket对象与某一个端口绑定。
客户端工作流程:
(1)建立socket对象,指定通信协议。
(2) 将创建的soket对象与某一个端口绑定。
接着通信双方进行数据传输。
通信完成后,关闭socket对象。
在Qt中,对一些函数进行了封装。使用起来更方便。在Qt中的UDP服务器和客户端都封装在QUdpSocket这个类中。
Qt中UDP服务器的使用:
(1)创建UDP服务器:
QUdpSocket *udpServer;
udpServer = new QUdpSocket(this);
udpServer->bind(QHostAddress::Any,ui->txtPortServer->text().toInt(),QUdpSocket::ShareAddress);
connect(udpServer,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
把udpServer的readRead信号和readPendingDatagrams()槽函数连接起来,当有数据过来的时候就执行槽函数。
Qt中UDP客户端的使用:
(1)创建UDP服务器:
QUdpSocket *udpClient;
udpClient = new QUdpSocket(this);
(2)绑定端口
udpClient->bind(QHostAddress::Any,ui->txtPortServerC->text().toInt(),QUdpSocket::ShareAddress);
connect(udpClient,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
把udpClient的readRead信号和readPendingDatagrams()槽函数连接起来,当有数据过来的时候就执行槽函数。
然后双方发送接收数据:
UDP服务器发送数据:
udpServer->writeDatagram(strMesg.toAscii(), strMesg.length(),QHostAddress::Broadcast, senderPort);//UDP服务器向刚才接受到的data of client发送数据
QHostAddress *ip;
ip = new QHostAddress(ui->txtIPServer->text());
udpClient->writeDatagram(strMesg.toAscii(),strMesg.length(),*ip, ui->txtPortServer->text().toInt());
UDP服务器和客户端接收数据:
void MainWindow::readPendingDatagrams()
{
QByteArray datagram;
if(ui->rdbtnsever->isChecked())
{
datagram.resize(udpServer->pendingDatagramSize());
while (udpServer->hasPendingDatagrams())
{
udpServer->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort); //读IP为sender,端口为senderPort的客户端数据
qDebug()<textUdpServer->setText(buf);
ui->label_5->setText("对方IP"+sender.toString());
}
}
else if(ui->rdbtnclient->isChecked())
{
datagram.resize(udpClient->pendingDatagramSize());
while(udpClient->hasPendingDatagrams())
{
udpClient->readDatagram(datagram.data(),datagram.size());
qDebug()<textUdpClient->setText(buf);
}
}
}