企业网站开发注册,wordpress插件权限不足,h5视频,虚拟主机哪家好为了使用Qt自带的Socket进行网络编程#xff0c;先必须熟悉Socket编程的原理#xff0c;另外还需对Qt一些基本类的操作比较熟悉。由于刚接触不久#xff0c;所以还是以看人家的代码来学习。这次主要是学Qt下UDP的编程#xff0c;且熟悉一些Qt下代码的编写流程#xff0c;所… 为了使用Qt自带的Socket进行网络编程先必须熟悉Socket编程的原理另外还需对Qt一些基本类的操作比较熟悉。由于刚接触不久所以还是以看人家的代码来学习。这次主要是学Qt下UDP的编程且熟悉一些Qt下代码的编写流程所以本文参照的是《Qt及Qt Quick开发实战精解》一书中的第5个例子局域网聊天工具中的UDP聊天部分。 另外http://www.yafeilinux.com/ 上有其源码和相关教程下载。 该程序实现的功能是局域网内每个用户登录到聊天软件则软件界面的右端可以显示在线用户列表分别显示的是用户名主机名ip地址。软件左边那大块是聊天内容显示界面这里局域网相当于qq中的qq群即群聊。每个人可以在聊天输入界面中输入文字并发送。其聊天界面如下 该程序实现的是每个用户登录既是客户端又是服务器端这就需要看你站在哪个角度看问题了。简单的说当用户发送信息给别人时就是客户端当接收别人的信息是就可以看做是服务器端。 下面分服务器端和客户端2部分来介绍。 服务器端:建立一个UDP Socket并绑定在固定端口后用信号与槽的方式进行监听是否有数据来临。如果用接收其数据并分析数据的消息类型如果消息是新用户登录则更新用户列表并在聊天显示窗口中添加新用户上线通知同理如果是用户下线则在用户列表中删除该用户且在聊天显示窗口中显示下线通知如果是聊天消息则接收该消息并且在窗口中显示。其流程图如下 客户端首先当客户端登录时获取本机的用户名计算机名和ip地址并广播给局域网的服务器更新用户列表。然后当客户端需要发送信息时则在聊天输入栏中输入信息并按发送键发送聊天内容当然于此同时也广播本地系统的各种信息。其流程图如下 程序主要代码和注释如下 widget.h: #ifndef WIDGET_H
#define WIDGET_H#include QWidget
class QUdpSocket;namespace Ui {
class Widget;
}// 枚举变量标志信息的类型分别为消息新用户加入用户退出文件名拒绝接受文件
enum MessageType{Message, NewParticipant, ParticipantLeft, FileName, Refuse};class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent 0);~Widget();protected:void newParticipant(QString userName,QString localHostName, QString ipAddress);void participantLeft(QString userName,QString localHostName, QString time);void sendMessage(MessageType type, QString serverAddress);QString getIP();QString getUserName();QString getMessage();private:Ui::Widget *ui;QUdpSocket *udpSocket;qint16 port;private slots:void processPendingDatagrams();void on_sendButton_clicked();
};#endif // WIDGET_H widget.cpp: #include widget.h
#include ui_widget.h
#include QUdpSocket
#include QHostInfo
#include QMessageBox
#include QScrollBar
#include QDateTime
#include QNetworkInterface
#include QProcessWidget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui-setupUi(this);udpSocket new QUdpSocket(this);//创建一个QUdpSocket类对象该类提供了Udp的许多相关操作port 45454;//此处的bind是个重载函数连接本机的port端口采用ShareAddress模式(即允许其它的服务连接到相同的地址和端口特别是//用在多客户端监听同一个服务器端口等时特别有效)和ReuseAddressHint模式(重新连接服务器)udpSocket-bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);//readyRead()信号是每当有新的数据来临时就被触发connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));sendMessage(NewParticipant);//打开软件时就向外发射本地信息让其他在线用户得到通知
}Widget::~Widget()
{delete ui;
}// 使用UDP广播发送信息MessageType是指头文件中的枚举数据类型
//sendMessage即把本机的主机名用户名消息内容后ip地址广播出去
void Widget::sendMessage(MessageType type, QString serverAddress)
{QByteArray data; //字节数组//QDataStream类是将序列化的二进制数据送到io设备因为其属性为只写QDataStream out(data, QIODevice::WriteOnly);QString localHostName QHostInfo::localHostName();//返回主机名QHostInfo包含了一些关于主机的静态函数QString address getIP(); //调用自己类中的getIP()函数//将typegetUserName()localHostName按照先后顺序送到out数据流中消息类型type在最前面out type getUserName() localHostName;switch(type){case Message :if (ui-messageTextEdit-toPlainText() ) { //将输入框里的文字转化成纯文本发送//当发送的文本为空时创建一个警告信息窗口tr函数为译本函数即译码后面的text内容QMessageBox::warning(0,tr(警告),tr(发送内容不能为空),QMessageBox::Ok); return;}out address getMessage();//将ip地址和得到的消息内容输入out数据流ui-messageBrowser-verticalScrollBar() //返回垂直条-setValue(ui-messageBrowser-verticalScrollBar()-maximum());//设置垂直滑动条的最大值break;case NewParticipant :out address; //为什么此时只是输出地址这一项呢因为此时不需要传递聊天内容break;case ParticipantLeft :break;case FileName :break;case Refuse :break;}//一个udpSocket已经于一个端口bind在一起了这里的data是out流中的data最多可以传送8192个字节但是建议不要超过//512个字节因为这样虽然可以传送成功但是这些数据需要在ip层分组QHostAddress::Broadcast是指发送数据的目的地址//这里为本机所在地址的广播组内所有机器即局域网广播发送udpSocket-writeDatagram(data,data.length(),QHostAddress::Broadcast, port);//将data中的数据发送
}// 接收UDP信息
void Widget::processPendingDatagrams()
{//hasPendingDatagrams返回true时表示至少有一个数据报在等待被读取while(udpSocket-hasPendingDatagrams()){QByteArray datagram;//pendingDatagramSize为返回第一个在等待读取报文的sizeresize函数是把datagram的size归一化到参数size的大小一样datagram.resize(udpSocket-pendingDatagramSize());//将读取到的不大于datagram.size()大小数据输入到datagram.data()中datagram.data()返回的是一个字节数组中存储//数据位置的指针udpSocket-readDatagram(datagram.data(), datagram.size());QDataStream in(datagram, QIODevice::ReadOnly);//因为其属性为只读所以是输入int messageType; //此处的int为qint32在Qt中qint8为charqint16为uintin messageType; //读取1个32位长度的整型数据到messageTyep中QString userName,localHostName,ipAddress,message;QString time QDateTime::currentDateTime().toString(yyyy-MM-dd hh:mm:ss);//将当前的时间转化到括号中的形式switch(messageType){case Message://in后面如果为Qstring则表示读取一个直到出现\0的字符串in userName localHostName ipAddress message;ui-messageBrowser-setTextColor(Qt::blue);//设置文本颜色ui-messageBrowser-setCurrentFont(QFont(Times New Roman,12));//设置字体大小// ui-messageBrowser-append([ userName ] time);//输出的格式为用户名加时间显示//输出的格式为主机名加时间显示但输出完后为什么会自动换行呢ui-messageBrowser-append([ localHostName ] time);ui-messageBrowser-append(message);//消息输出break;case NewParticipant:in userName localHostName ipAddress;newParticipant(userName,localHostName,ipAddress);break;case ParticipantLeft:in userName localHostName;participantLeft(userName,localHostName,time);break;case FileName:break;case Refuse:break;}}
}// 处理新用户加入
void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
{//此处的findItems表示找到与内容localHostName匹配的item其匹配是基于变体的匹配模式bool isEmpty ui-userTableWidget-findItems(localHostName, Qt::MatchExactly).isEmpty();if (isEmpty) { //没有找到相应的主机名//新建3个小的item分别为user,host,ipQTableWidgetItem *user new QTableWidgetItem(userName);QTableWidgetItem *host new QTableWidgetItem(localHostName);QTableWidgetItem *ip new QTableWidgetItem(ipAddress);ui-userTableWidget-insertRow(0);//先设置的是第0行即新来的用户放在最上面ui-userTableWidget-setItem(0,0,user);//第0行的第1列...ui-userTableWidget-setItem(0,1,host);ui-userTableWidget-setItem(0,2,ip);ui-messageBrowser-setTextColor(Qt::gray);ui-messageBrowser-setCurrentFont(QFont(Times New Roman,10));//arg为返回后面文本的一个副本,%1表示输出的内容按照第1个.arg后面的输出ui-messageBrowser-append(tr(%1 在线).arg(userName));ui-userNumLabel-setText(tr(在线人数%1).arg(ui-userTableWidget-rowCount()));//在线人数为条目的行数
sendMessage(NewParticipant);//该句的功能是让新来的用户也能收到其它在线用户的信息可拥于更新自己的好友列表}
}// 处理用户离开
void Widget::participantLeft(QString userName, QString localHostName, QString time)
{//找到第一个对应的主机名int rowNum ui-userTableWidget-findItems(localHostName, Qt::MatchExactly).first()-row();ui-userTableWidget-removeRow(rowNum); //此句执行完后rowCount()内容会自动减1ui-messageBrowser-setTextColor(Qt::gray);//设置文本颜色为灰色ui-messageBrowser-setCurrentFont(QFont(Times New Roman, 10));ui-messageBrowser-append(tr(%1 于 %2 离开).arg(userName).arg(time));ui-userNumLabel-setText(tr(在线人数%1).arg(ui-userTableWidget-rowCount()));
}// 获取ip地址获取本机ip地址(其协议为ipv4的ip地址)
QString Widget::getIP()
{//QList是Qt中一个容器模板类是一个数组指针QListQHostAddress list QNetworkInterface::allAddresses();//此处的所有地址是指ipv4和ipv6的地址//foreach (variable, container),此处为按照容器list中条目的顺序进行迭代foreach (QHostAddress address, list) { if(address.protocol() QAbstractSocket::IPv4Protocol)return address.toString();}return 0;
}// 获取用户名
QString Widget::getUserName()
{QStringList envVariables;//将后面5个string存到envVariables环境变量中envVariables USERNAME.* USER.* USERDOMAIN.* HOSTNAME.* DOMAINNAME.*;//系统中关于环境变量的信息存在environment中QStringList environment QProcess::systemEnvironment();foreach (QString string, envVariables) {//indexOf为返回第一个匹配list的索引,QRegExp类是用规则表达式进行模式匹配的类int index environment.indexOf(QRegExp(string));if (index ! -1) {//stringList中存的是environment.at(index)中出现号前的字符串QStringList stringList environment.at(index).split();if (stringList.size() 2) {return stringList.at(1);//at(0)为文字USERNAME.at(1)为用户名break;}}}return unknown;
}// 获得要发送的消息
QString Widget::getMessage()
{QString msg ui-messageTextEdit-toHtml();//转化成html语言进行发送
ui-messageTextEdit-clear();//发送完后清空输入框ui-messageTextEdit-setFocus();//重新设置光标输入焦点即焦点保持不变return msg;
}// 发送消息
void Widget::on_sendButton_clicked()
{sendMessage(Message);
} main: #include QtGui/QApplication
#include widget.h
#include QTextCodec //处理不同语言编码的类int main(int argc, char *argv[])
{QApplication a(argc, argv);QTextCodec::setCodecForTr(QTextCodec::codecForLocale());//对不同的文字选择不同的编码Widget w;w.show();return a.exec();
}