用QT实现Wake On Lan功能(附全部程序源码)

2019-07-14 03:46发布

Wake On Lan也就是远程唤醒(远程开机),即通过一台PC向另一台已经关机但仍连接电源PC发送网络数据包,使其开机的功能,前提是两台PC同处一个局域网内,且被唤醒方的网卡支持网络唤醒功能(现在网卡基本上都支持啦)。 原理:PC关闭后,网卡仍能获取电源,一直监听“magic” packet到来,这种数据包可以是IP、IPX或者其它什么,其中封装了特制的字节序列,一旦收到这种数据包,通过网卡与主板的协作,实现远程启动。 Magic包的格式:如果目标主机的MAC地址为 01:02:03:04:05:06的话,包的组成应该如下: FFFFFFFFFFFF010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506010203040506
010203040506010203040506
由6个16进制字节的FF和至少重复16次MAC地址组成。 下面是在QT3中实现的源代码: //文件名:main.cpp
#include <qapplication.h>
#include 
"frmMain.h"

int main( int argc, char ** argv )
{
    QApplication a( argc, argv );
    Form1 w;
    w.show();
    a.connect( 
&a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
    
return a.exec();
}


   /****************************************************************************
** Form implementation generated from reading ui file 'frmMain.ui'
**文件名:frmMain.cpp
** Created: 星期四 十月 19 16:30:55 2006
**      by: The User Interface Compiler ($Id: qt/main.cpp   3.3.4   edited Nov 24 2003 $)
**
** WARNING! All changes made in this file will be lost!
***************************************************************************
*/


#include 
"frmMain.h"

#include 
<qvariant.h>
#include 
<qlineedit.h>
#include 
<qpushbutton.h>
#include 
<qlayout.h>
#include 
<qtooltip.h>
#include 
<qwhatsthis.h>
#include 
<qaction.h>
#include 
<qmenubar.h>
#include 
<qpopupmenu.h>
#include 
<qtoolbar.h>
#include 
<qimage.h>
#include 
<qpixmap.h>

#include 
"frmMain.ui.h"
/*
 *  Constructs a Form1 as a child of 'parent', with the
 *  name 'name' and widget flags set to 'f'.
 *
 
*/

Form1::Form1( QWidget
* parent, const char* name, WFlags fl )
    : QMainWindow( parent, name, fl )
{
    (
void)statusBar();
    
if ( !name )
    setName( 
"Form1" );
    setCentralWidget( 
new QWidget( this"qt_central_widget" ) );

    lineEdit1 
= new QLineEdit( centralWidget(), "lineEdit1" );
    lineEdit1
->setGeometry( QRect( 405027130 ) );

    pushButton2 
= new QPushButton( centralWidget(), "pushButton2" );
    pushButton2
->setGeometry( QRect( 1201108023 ) );

    
// toolbars

    languageChange();
    resize( QSize(
391250).expandedTo(minimumSizeHint()) );
    clearWState( WState_Polished );

    
// signals and slots connections
    connect( pushButton2, SIGNAL( clicked() ), this, SLOT( pushButton2_clicked() ) );
}


/*
 *  Destroys the object and frees any allocated resources
 
*/

Form1::
~Form1()
{
    
// no need to delete child widgets, Qt does it all for us
}


/*
 *  Sets the strings of the subwidgets using the current
 *  language.
 
*/

void Form1::languageChange()
{
    setCaption( tr( 
"Wake On Lan For QT" ) );
    lineEdit1
->setText("00-11-09-9C-CF-A2");
    pushButton2
->setText( trUtf8( "/xe8/xbf/x9c/xe7/xa8/x8b/xe5/xbc/x80/xe6/x9c/xba" ) );
}


  /****************************************************************************
** Form interface generated from reading ui file 'frmMain.ui'
**文件名:frmMain.h
** Created: 星期四 十月 19 15:44:26 2006
**      by: The User Interface Compiler ($Id: qt/main.cpp   3.3.4   edited Nov 24 2003 $)
**
** WARNING! All changes made in this file will be lost!
***************************************************************************
*/


#ifndef FORM1_H
#define FORM1_H

#include 
<qvariant.h>
#include 
<qmainwindow.h>

class QVBoxLayout;
class QHBoxLayout;
class QGridLayout;
class QSpacerItem;
class QAction;
class QActionGroup;
class QToolBar;
class QPopupMenu;
class QLineEdit;
class QPushButton;

class Form1 : public QMainWindow
{
    Q_OBJECT

public:
    Form1( QWidget
* parent = 0const char* name = 0, WFlags fl = WType_TopLevel );
    
~Form1();

    QLineEdit
* lineEdit1;
    QPushButton
* pushButton2;

public slots:
    
virtual void pushButton2_clicked();

protected:

protected slots:
    
virtual void languageChange();

}
;

#endif // FORM1_H
  /****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**文件名:frmMain.ui.h
** If you want to add, delete, or rename functions or slots, use
** Qt Designer to update this file, preserving your code.
**
** You should not define a constructor or destructor in this file.
** Instead, write your code in functions called init() and destroy().
** These will automatically be called by the form's constructor and
** destructor.
****************************************************************************
*/

#include 
"qsocketdevice.h"
#include <qcstring.h> 
#include 
<qmessagebox.h> 

void Form1::pushButton2_clicked()
{
//建立套接字相关对象
 QSocketDevice *MUReceiveSocket;   //套接字对象
 
//QSocketNotifier *MSocketNotifier;     //套接字监听对象
//初始化套接字相关对象
MUReceiveSocket=new QSocketDevice(QSocketDevice::Datagram);   
//UDP初始化
QHostAddress MyAddress;
QString FakeAddress;
QString SMacAddr
=lineEdit1->text();//网卡的mac地址
const Port=0;//目标机器的端口号

//检查MAC地址是否等于17
if (SMacAddr.length()!=17{
    QMessageBox::warning(
this,"MAC Address ERR","MAC Address must be =17");
    
return
}

//检查MAC地址是否正确
 for (int i=2;i<17;i=i+3{
     
if (SMacAddr[i]!='-'{
          QMessageBox::warning(
this,"MAC Address ERR","MAC Adresse must be like this: 00-D0-4C-BF-52-BA");
         
return;
     }

 }


char MACAddr[6]; 
char MagicPacket[102];//实现远程开机的Magic包

int j=sscanf(SMacAddr, "%2x-%2x-%2x-%2x-%2x-%2x",
                
&MACAddr[0], &MACAddr[1], &MACAddr[2], &MACAddr[3], &MACAddr[4], &MACAddr[5]);
 
if (j!=6)
 
{
  QMessageBox::warning(
this,"MAC Address ERR","Invalid MAC Adresse!");
  
return;
 }


//把magicpacket数组前6个字符设置成16进制的ff
 memset(MagicPacket, 0xff6);

 
int packetsize=6;//初始值是6,不要搞错了啊。我就是因为大意,把初始会值写成0,实在是太顺手了。
//构建MagicPacket
for (i=0;i<16;i++
{
 memcpy(MagicPacket
+packetsize,MACAddr,6);
 packetsize
+=6;
}


FakeAddress 
= "192.168.1.255";  //取得接口IP
MyAddress.setAddress(FakeAddress);
MUReceiveSocket
->writeBlock(MagicPacket,102,MyAddress,Port);


}


 
 Main.cpp、frmMain.cpp和frmMain.h是做完界面后QT自动生成的啦,主要的代码编写工作都在frmMain.ui.h。在frmMain.ui.h中实现Magic包的构建,并通过UDP方式将其广播出去。 在QT3中实现UDP网络功能的类是qsocketdevice,见源码。而在QT4中没有这个类,代之的是QUdpSocket,所以这个源码在QT4中无法通过编译。有兴趣的,可以自行修改。源码很简短,并有较详细的注释,我相信大家都能明白。该源码在XP+QT3+VC6中编译通过。 提醒一点的就是在写程序时尽量不要把C++的变量与QT的变量混用,虽然大多时候都能通过编译,但得到的数值并不一定是正确的,而且有时会出错的莫名其妙。我只是个QT的初学都,C++也没学多久,以前一直都是用delphi,有什么错误请大家多指教。