t:利用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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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()
1
2
3
4
5
6
7
8
5.使用
现在就可以快乐的使用C++连接power pmac的API函数了!
std::shared_ptr<telnet> pmacConnect;
pmacConnect = std::shared_ptr<telnet>(new telnet);
pmacConnect->connect();
...
QString message;
...
pmacConnect->telSendMess(message);
————————————————
版权声明:本文为CSDN博主「机器人学渣」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42995327/article/details/115842862