Qt:利用telnet连接PMAC

Qt:利用telnet连接PMAC
 

POWER PMAC是一个新版的运动控制器,与原来的turbo PMAC相比缺少了一套基于C++且类似于PComm32的通讯库,但不管是哪种PMAC,本意都是利用TCP/IP的协议来与上位机进行连接。Power PMAC是利用Telnet协议来进行通讯的,本代码是利用Qt来实现Telnet系统,准确的来说是利用windows和linux下的套接字来实现。另外当然也可以使用Qt自带的网络套接字来实现连接。
 

1. PMAC连接的方式

Power PMAC是利用telnet的方式来进行通讯,我们可以打开windows下的功能与服务,将telnet服务开启。



然后打开cmd,使用telnet命令:telnet 192.168.0.110后面的ip地址是下位机power pmac的地址,telnet默认的端口是23号,但连通pmac时,这时候相当于进入访问了pmac的操作系统,需要输入账号和密码(本例中):

账号:root
密码:deltatau

然后继续在终端中输入启动程序:gpascii

这样就可以启动PMAC了,但是问题来了:对于我们进行控制开发,想要使用一种自动的程序进行调试,控制PMAC,发送数据给PMAC,例如采集图像信息然后经过处理反馈给PMAC,使用C++设计API函数来自动的对PMAC进行连接呢?

步骤:

1.创建套接字,与PMAC建立连接,端口号为23(telnet端口为23);

2.与PMAC进行协商;只有完成了协商才能够实现相互间的通讯,协商时需要三个字节:首先需要读取IAC,读取到了才能进行下一步,第二个字节是命令码,即WILL 、 DO 、 WONT 、 DONT 四者之一,最后一位是选项码,对应的是选项功能;例如服务器消息: 255 251 24(IAC WILL 24—要求激活终端类型),这时你需要发送:255 253 24(IAC DO 24—执行激活终端类型),这样就可以建立协商了。
参考文献:
Telnet协议详解及使用C# 用Socket 编程来实现Telnet协议

telnet命令:
在这里插入图片描述
telnet协商:
在这里插入图片描述
选项码:
在这里插入图片描述
3.建立协商以后,输入账号,密码,以及要启动的程序,这个时候就可以和PMAC自动的建立连接了。
 

2. windows下的代码:

 
telnet.h:

#ifndef TELNET_H
#define TELNET_H
#include <QObject>
#include <iostream>
#include <time.h>
#include <Windows.h>
#include <QString>
#include <QDebug>

//#pragma comment(lib,"ws2_32.lib")

class telnet:public QObject
{
    Q_OBJECT
public:
    telnet();
    ~telnet();
    void connect();
    SOCKET sock2;
    inline bool telSendMess(QString str);
    QString reciveMess();
    bool ConnectStatus;

protected:
    void telnetnvt();
private:
    HANDLE stou1;
signals:
    void connectedReady(bool);
};
#endif // TELNET_H

 
telnet.cpp:

#include <iostream>
#include "telnet.h"

#define WILL  251
#define WONT  252
#define DO    253
#define DONT  254
#define IAC   255

using namespace std;

telnet::telnet():ConnectStatus(false)
{
    stou1 = GetStdHandle(STD_OUTPUT_HANDLE);

    //socket版本
    WORD wVersion;
    wVersion = MAKEWORD(2, 1);

    //初始化套接字库
    WSADATA wsaData;
    WSAStartup(wVersion, &wsaData);

    SOCKADDR_IN server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;

    //监听23端口
    //server_addr.sin_addr.S_un.S_addr=INADDR_ANY;
    server_addr.sin_port = htons(IPPORT_TELNET);//IPPORT_TELNET
    server_addr.sin_addr.s_addr = inet_addr("192.168.0.110");
    memset(server_addr.sin_zero, 0x00, 8);

    if ((sock2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
        qDebug()<<QString::fromLocal8Bit("套接字创建失败!")<<endl;
    if (::connect(sock2, (struct sockaddr *) &server_addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
        qDebug()<<QString::fromLocal8Bit("PMAC连接失败!")<<endl;
    else
    {
        qDebug()<<QString::fromLocal8Bit("PMAC创建成功")<<endl;
    }
    Sleep(3000);

    //与服务器协商
    telnetnvt();
}

telnet::~telnet()
{
    //关闭套接字
    closesocket(sock2);
    WSACleanup();
}

void telnet::connect()
{
    Sleep(1000);
    telSendMess("root");//root
    Sleep(1000);
    qDebug()<<"root\n";

    telSendMess("deltatau");//deltatau
    Sleep(1000);
    qDebug()<<"deltatau\n";

    //get into the shell;
    telSendMess("gpascii");//gpascii
    Sleep(1000);
    qDebug()<<"gpascii\n";
}

//发送数据
inline bool telnet::telSendMess(QString str)
{
    char pBuff[256]={0};
    int nRet = str.length();
    QByteArray ba = str.toLatin1();
    strncpy(pBuff, ba.data(), nRet);

    if(send(sock2,ba.data(),nRet,0)<0)
    {
        qDebug()<<QString::fromLocal8Bit("发送失败:")<<ba.length()<<endl;
        emit connectedReady(false);
        return false;
    }
    else if(!ConnectStatus)
    {
        ConnectStatus = true;
        qDebug()<<QString::fromLocal8Bit("发送成功")<<endl;
        emit connectedReady(true);
    }
    //cout<<ba.data()<<endl;
    send(sock2, "\r\n", 1, 0);//这个控制字符必须要---
    return true;
}

//接收数据
QString telnet::reciveMess()
{
    char msg[1024] = {0};
    memset(msg, 0, 1024);
    int res = recv(sock2, msg, 1024, 0);
    if (res == SOCKET_ERROR)
    {
        qDebug()<<"Receive Failed\n";
        return nullptr;
    }
    if (res == 0)
    {
        Sleep(10);
        qDebug()<<"Can't get the message!\n";
    }

    return QString(msg);
}

void telnet::telnetnvt()
{
    unsigned char strRecvBuf[3] = {0};
    while(1)
    {
        //选项协商需要 3 个字节
        //例如 IAC DONT ECHO
        //第一个 IAC 一个字节 (0xff)
        if(recv(sock2, (char*)(strRecvBuf), 1, 0)!=1)
            return;

        //如果不是IAC 选项
        if(strRecvBuf[0] != IAC)
            break;

        //第二个字节是 WILL 、 DO 、 WONT 、 DON''T 四者之一
        //最后一个 ID 字节指明激活或禁止选项。
        if(recv(sock2, (char*)(strRecvBuf+1), 2, 0)!=2)//接收到两个字节,WILL和ID
            return;

        //查看第二个字节是什么,以选择相应的代码
        switch(strRecvBuf[1])
        {
            case WILL:	//WILL
                strRecvBuf[1] = DO;	//DO
                break;

            case WONT:	//WONT
                strRecvBuf[1] = DONT;	//DONT
                break;

            case DO:	//DO
            case DONT:	//DONT
                strRecvBuf[1] = WONT;	//WONT
                break;

            default:
                return;
        }

        //发送信息反馈
        send(sock2, (char*)strRecvBuf, 3, 0);
        //qDebug()<<strRecvBuf[1];
    }
}

Tips: 使用reciveMess函数时一定要判断是否有信息传输回来,缓冲区是否有数据,否则就会出现线程阻塞,一直等待读取。

另外在windows下使用TCP/IP网络,一定要在CMakeLists.txt文件中添加这么一句 link_libraries(ws2_32 wsock32)
 

3.Linux下的代码:

 
telnet.h

#ifndef TELNET_H
#define TELNET_H
#include <QObject>
#include <iostream>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QTcpServer>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <stdlib.h>
#include <QString>
//#include <winsock2.h>

class telnet:public QObject
{
    Q_OBJECT
public:
    telnet();
    ~telnet();
    int sock2;
    void connet();
    void  telSendMess(QString str,int hSocket);
    QString reciveMess();
    bool hasconnect;

protected:
        void telnetnvt();
signals:
    void connectedReady(bool);
private slots:
        void connected()
        {
            qDebug()<<"connect successed!"<<endl;
        }
        void error(QAbstractSocket::SocketError)
        {
            qDebug()<<"can't connect,faild!\n";
        }
        void error()
        {
            qDebug()<<"can't connect,faild!\n";
        }
        void connectionError(QAbstractSocket::SocketError error)
        {
            qDebug()<<"connection Error\n";
        }
        void disconnected()
        {
            qDebug()<<"has disconnect\n";
        }
};
#endif // TELNET_H

telnet.cpp

#include <iostream>
#include "sock.h"
#include <time.h>
//#include <Windows.h>

using namespace std;

telnet::telnet():hasconnect(false)
{
    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));/*将serv_addr各个字段清零*/
    server_addr.sin_family=AF_INET;
    //监听23端口
    //server_addr.sin_addr.S_un.S_addr=INADDR_ANY;
    server_addr.sin_port = htons(IPPORT_TELNET);//IPPORT_TELNET
    server_addr.sin_addr.s_addr = inet_addr("192.168.0.110");//192.168.0.110 192.168.10.129
    if ((sock2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
        qDebug()<<"the socket created failed!\n";
    else{
        qDebug()<<"the socket created successful\n";
    }
    if (::connect(sock2, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
        qDebug()<<"pmac connect failed!\n";
    else
    {
        qDebug()<<"PMAC creat successful!\n";
    }
    usleep(3000);
    //与服务器协商
    telnetnvt();
}

telnet::~telnet()
{
    //关闭套接字
    close(sock2);
}

void telnet::connet()
{
    usleep(500);
    //reciveMess();
    telSendMess("root", sock2);//root
    reciveMess();
    sleep(1);


    telSendMess("deltatau", sock2);//deltatau
    sleep(1);
    reciveMess();

    //qDebug()<<"-------------------------------get into the shell--------------------------------\n";
    telSendMess("gpascii", sock2);//gpascii
    sleep(1);
    reciveMess();
    //reciveMess();

    //qDebug()<<"---------------------------------发送变量数据---------------------------------------\n";
}

void  telnet::telSendMess(QString str,int hSocket)
{
    char pBuff[256]={0};
    int nRet = str.length();
    QByteArray ba = str.toLatin1();
    strncpy(pBuff, ba.data(), nRet);
    /*while (nRet--)
    {
        int resp = send(hSocket, &pBuff[i], 1, 0);
        qDebug()<<pBuff[i];
        i++;
        //if (nRet == 0) break;
    }
    */
    if(send(hSocket,ba.data(),nRet,0)<0)
    {
        qDebug()<<"发送失败:"<<ba.length()<<endl;
        emit connectedReady(false);
    }
    else if(!hasconnect)
    {
        hasconnect = true;
        qDebug()<<"发送成功\n";
        emit connectedReady(true);
    }
    //qDebug()<<ba.data()<<endl;
    send(hSocket, "\r\n", 1, 0);//这个控制字符必须要---------------------------
}

QString telnet::reciveMess()
{
    char msg[1024] = {0};
    memset(msg, 0, 1024);
    int res = recv(sock2, msg, 1024, 0);
    if (res == -1)
    {
        qDebug()<<"接收失败\n";
        return 0;
    }
    if (res == 0)
    {
        usleep(10);
        qDebug()<<"can't get the message!\n";
    }
    //printf("%s\n",msg);
    //qDebug()<<msg<<endl;
    return QString(msg);
}

void telnet::telnetnvt()
{
    unsigned char strRecvBuf[3] = {0};
    while(1)
    {
        if(recv(sock2, (char*)(strRecvBuf), 1, 0)!=1)
            return;
        if(strRecvBuf[0] != 255)
            break;
        if(recv(sock2, (char*)(strRecvBuf+1), 2, 0)!=2)
            return;

    switch(strRecvBuf[1]){
        case 251:	//WILL
            strRecvBuf[1] = 253;	//DO
            break;

        case 252:	//WONT
            strRecvBuf[1] = 254;	//DONT
            break;

        case 253:	//DO
        case 254:	//DONT
            strRecvBuf[1] = 252;	//WONT
            break;
        default:
            return;
    }
    send(sock2, (char*)strRecvBuf, 3, 0);
    //qDebug()<<strRecvBuf[1];
    }
}

4.CMAKE:

如果是在windows下,需要添加link_libraries(ws2_32 wsock32),为了避免麻烦,我们可以在CMAKE中添加:

IF(CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_COMPILER "clang")
    link_libraries(ws2_32 wsock32)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
    set(CMAKE_C_COMPILER "clang") #gcc
    set(CMAKE_CXX_COMPILER "clang++") #g++
    set(CMAKE_CXX_FLAGS "-std=c++11 -O3 -Wall")
ENDIF()

5.使用

现在就可以快乐的使用C++连接power pmac的API函数了!

std::shared_ptr<telnet> pmacConnect;
pmacConnect = std::shared_ptr<telnet>(new telnet);
pmacConnect->connect();
...
QString message;
...
pmacConnect->telSendMess(message);
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值