开始我们明确,此软件是在局域网里提供收发信息的聊天软件,也就是用网线连接,之后通过网线收发信息。既然如此,那么首先要把IP设在同一网段。这个工作之前篇“基于ARM的视频监控”已经有详细解释以及附图,在此不详述。之后,那就需要连接,连接当然要选择端口号,这个在程序已经设定好了,不用担心,这里我开的是9090端口,很显然这么大端口基本是没什么服务会用到的,所以是安全的。 然后数据传输的具体实现,首先,传输数据,当然要有个缓冲区,数据先传进缓冲区,之后在从缓冲区读取,不然数据没办法凭空传输,这就好比一个容器,当然这里缓冲区和caches是不一样的,caches是为了提高程序运行速度,当然如果有中断,或者多线程存在就要用volatile来定义了。 呵呵,扯远了。。。 这边我们事先要清空缓冲区,这是一件很重要的事,不然很有可能出现乱码等。不过如果数据和少,很可能自动传输不是很顺利,所以我们需要考虑到这点,那么需要人工加一句推代码,为了能让数据完全传输。 好了,大概流程就是这样,不过没做界面美化,要做的话,网上可以的荡美化包,有做好的。先贴效果图:
ARM端,初始监听状态。
PC机端,还没连接。
ARM端,已连接上。
PC机端输入IP连接上ARM端。
从PC端发送消息给ARM端,ARM端接受到消息。
ARM端发送来的消息在PC端显示。
PC端断开聊天。
断开后ARM端效果。
当然还有一些功能,比如说清屏,还有在ARM端也可以断开。
下面部分代码
PC端:
#include "socketwidget.h" #include "ui_socketwidget.h" /*客户端程序*/ SocketWidget::SocketWidget(QWidget *parent) : QWidget(parent), ui(new Ui::SocketWidget) { ui->setupUi(this); socket = new QTcpSocket(this); connect(ui->pushButton_connect,SIGNAL(clicked()),this,SLOT(onConnect())); //点击相关按钮触发相关槽函数 connect(ui->pushButton_disconnect,SIGNAL(clicked()),this,SLOT(onDisconnect())); connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(onSend())); connect(socket,SIGNAL(connected()),this,SLOT(imcoming())); //管道建立后触发相关函数 ui->pushButton_send->setShortcut(tr("Ctrl+R")); //设置发送相关快捷键 } /*连接按钮点击后的函数*/ void SocketWidget::onConnect() { ui->pushButton_connect->setDisabled(true); //设置相关按键使能与否 // socket->connectToHost("localhost",9090); socket->connectToHost(QString(ui->lineEdit_socket->text()),9090); //这里可以在lineEdit里写相应ip,如果只是测试只要输入localhost即可,且配置好端口 if(!socket->waitForConnected(3000)) //等待3s,如果管道没接通那么则行{}内容 { ui->pushButton_connect->setEnabled(true); ui->textEdit->append("connect failed!"); return; } ui->pushButton_disconnect->setEnabled(true); //设置相关按键使能与否 ui->pushButton_send->setEnabled(true); ui->textEdit->append("connected to host"); // connect(socket,SIGNAL(readyRead()),this,SLOT(onread())); } /*点击Disconnect按钮后执行函数*/ void SocketWidget::onDisconnect() { socket->abort(); //强行断开管道 ui->textEdit->append("disconnected!"); //设置相关按键使能与否 ui->pushButton_connect->setEnabled(true); ui->pushButton_disconnect->setDisabled(true); ui->pushButton_send->setDisabled(true); // connect(socket,SIGNAL(readyRead()),this,SLOT(onread())); } /*点击Send按钮后触发函数*/ void SocketWidget::onSend() { socket->write(ui->lineEdit->text().toAscii()); //写信息进管道 socket->flush(); //推信息 ui->lineEdit->clear(); } /*读信息函数*/ void SocketWidget::onread() { char bufclient[100]; //缓冲区 memset(bufclient,0,sizeof(bufclient)); //清空缓冲区 int lengthc = socket->bytesAvailable(); //从管道中计算传送数据长度 socket->read(bufclient,lengthc); //把指定长度数据从管道中放入缓冲区buf ui->textEdit->insertPlainText("\n"); ui->textEdit->insertPlainText("server : "); //显示相关发信息人,以及时间等 ui->textEdit->insertPlainText(QDateTime::currentDateTime().toString("yyyy-mm-dd ")); ui->textEdit->insertPlainText(QTime::currentTime().toString("hh:mm:ss"));//textEdit文本框显示当前时间 ui->textEdit->insertPlainText("\n"); ui->textEdit->append(bufclient); //显示信息 ui->textEdit->insertPlainText("\n"); //ui->textEdit->append(bufclient); } /*管道建立后,触发的相关函数*/ void SocketWidget::imcoming() { ui->textEdit->append("connected."); connect(socket,SIGNAL(readyRead()),this,SLOT(onread())); //准备,然后触发读信息槽 connect(socket,SIGNAL(disconnected()),this,SLOT(enServerButton()));//管道断开,触发相关槽 } /*断开后,各按键相关使能函数*/ void SocketWidget::enServerButton() { ui->pushButton_connect->setEnabled(true); //各按键使能 ui->pushButton_disconnect->setDisabled(true); ui->pushButton_send->setDisabled(true); // socket->abort(); } /*析构函数*/ SocketWidget::~SocketWidget() { delete socket; delete ui; }
#ifndef SOCKETWIDGET_H #define SOCKETWIDGET_H #include <QWidget> #include <QTcpSocket> #include <QTextCodec> #include <QTime> #include <QDateTime> namespace Ui { class SocketWidget; } class SocketWidget : public QWidget { Q_OBJECT public: explicit SocketWidget(QWidget *parent = 0); ~SocketWidget(); private: Ui::SocketWidget *ui; QTcpSocket *socket; private slots: void onConnect(); void onDisconnect(); void onSend(); void onread(); void imcoming(); void enServerButton(); }; #endif // SOCKETWIDGET_H
ARM端;
#include "serverwidget.h" #include "ui_serverwidget.h" /*服务器端程序*/ ServerWidget::ServerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ServerWidget) { ui->setupUi(this); server = new QTcpServer(this); if(!server->listen(QHostAddress::Any,9090)) //如果服务没监听到9090端口执行{}里信息 { ui->textEdit->append("Listening filed!"); return; } ui->textEdit->append("Listening..."); connect(server,SIGNAL(newConnection()),this,SLOT(imcoming())); //如果有新的连接信息newConnection(),触发imcoming() // connect(ui->pushButton_connect,SIGNAL(clicked()),this,SLOT(onConnect())); connect(ui->pushButton_disconnect,SIGNAL(clicked()),this,SLOT(onDisconnect())); //断开触发相应操作 connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(onSend())); //点击发送,触发相应槽 } //void ServerWidget::onConnect() //{ // ui->pushButton_connect->setDisabled(true); //// socket->connectToHost("localhost",9090); // // if(!socket->waitForConnected(3000)) // // { // //ui->pushButton_connect->setEnabled(true); // ui->textEdit->append("connect failed!"); // return; // // } // ui->pushButton_disconnect->setEnabled(true); // ui->pushButton_send->setEnabled(true); // ui->textEdit->append("connect to host"); //} /*点击断开连接按钮后的相应操作函数*/ void ServerWidget::onDisconnect() { // socket->disconnect(); socket->abort(); //让管道失效 ui->textEdit->append("disconnected!"); //显示断开信息 //ui->pushButton_connect->setEnabled(true); ui->pushButton_disconnect->setDisabled(true); //设置相应按键使能与否,防止错误点击 ui->pushButton_send->setDisabled(true); // connect(socket,SIGNAL(disconnected()),this,SLOT(enServerButton())); } /*点击发送按钮后相应操作函数*/ void ServerWidget::onSend() { socket->write(ui->lineEdit->text().toAscii()); //把相关数据送入管道 socket->flush(); //防止数据较少不能自动发送,所以推一把 ui->lineEdit->clear(); //清除lineEdit里信息,为了界面效果 } /*新连接信息来之后(再次按下connect按钮(包括第一次))触发的相关函数*/ void ServerWidget::imcoming() { socket = server->nextPendingConnection(); //把客户端的socket端口存入到服务器端的socket端口,理论上只有一个socket ui->textEdit->append("connected."); ui->pushButton_disconnect->setEnabled(true); //设置相应按键使能与否,防止错误点击,以及逻辑效果 ui->pushButton_send->setEnabled(true); connect(socket,SIGNAL(readyRead()),this,SLOT(onread())); //管道准备好读取数据,触发onread() connect(socket,SIGNAL(disconnected()),this,SLOT(enServerButton())); //管道没连接,那么出发enServerButton()设置相关按键使能与否 } /*管道断开设置相关按钮使能与否函数*/ void ServerWidget::enServerButton() { ui->pushButton_disconnect->setDisabled(true); ui->pushButton_send->setDisabled(true); // socket->abort(); } /*读信息函数*/ void ServerWidget::onread() { char buf[100]; //暂存数据中转站 memset(buf,0,sizeof(buf)); //先清0 int length = socket->bytesAvailable(); //从管道中计算传送数据长度 socket->read(buf,length); //把指定长度数据从管道中放入缓冲区buf ui->textEdit->insertPlainText("\n"); //显示通信对象,以及时间等信息 ui->textEdit->insertPlainText("socket : "); ui->textEdit->insertPlainText(QDateTime::currentDateTime().toString("yyyy-mm-dd ")); ui->textEdit->insertPlainText(QTime::currentTime().toString("hh:mm:ss"));//textEdit文本框显示当前时间 ui->textEdit->insertPlainText("\n"); ui->textEdit->append(buf); ui->textEdit->insertPlainText("\n"); // ui->textEdit->append(buf); } /*析构函数*/ ServerWidget::~ServerWidget() { delete server; //new之后最好是delete下,不然很容易产生野指针 delete ui; }
#ifndef SERVERWIDGET_H #define SERVERWIDGET_H #include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QTextCodec> #include <QTime> #include <QDate> namespace Ui { class ServerWidget; } class ServerWidget : public QWidget { Q_OBJECT public: explicit ServerWidget(QWidget *parent = 0); ~ServerWidget(); private: Ui::ServerWidget *ui; QTcpServer *server; QTcpSocket *socket; private slots: void imcoming(); void onread(); private slots: // void onConnect(); void onDisconnect(); void onSend(); void enServerButton(); }; #endif // SERVERWIDGET_H
当然这个软件也可以用于局域网PC与PC机之间,或者ARM板与ARM板之间。 经过测试。
提供源码链接: