【问题标题】:Connect to cisco router with c++ via serial interface通过串行接口使用 C++ 连接到 cisco 路由器
【发布时间】:2012-10-29 16:17:23
【问题描述】:

我想从我的 c++ 应用程序连接到 Cisco 路由器。 需要它才能获得接口状态。 我的 linux station (Ubuntu) 和路由器通过串口连接。

从 puty 或 minicom 或控制台连接工作。

例如:

root@test:/etc/minicom# cu -l /dev/ttyS0 -s 9600
Connected.

Router#show int summary

 *: interface is up
 IHQ: pkts in input hold queue     IQD: pkts dropped from input queue
 OHQ: pkts in output hold queue    OQD: pkts dropped from output queue
 RXBS: rx rate (bits/sec)          RXPS: rx rate (pkts/sec)
 TXBS: tx rate (bits/sec)          TXPS: tx rate (pkts/sec)
 TRTL: throttle count

现在我尝试用 C++(或 C)做同样的事情,但读取挂起。

我的c代码:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int fd1;
int fd2;
char *buff, *buffer, *bufptr;
int wr, rd, nbytes, tries;

int configure_port(int fd)      // configure the port
        {
    struct termios port_settings;     // structure to store the port settings in
    bzero(&port_settings, sizeof(port_settings));
    cfsetispeed(&port_settings, B9600);    // set baud rates
    cfsetospeed(&port_settings, B9600);

    port_settings.c_cflag &= ~PARENB;    // set no parity, stop bits, data bits
    port_settings.c_cflag &= ~CSTOPB;
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;

    tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to the port
    return (fd);

}
int main() {
    fd1 = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd1 == -1) {
        perror("open_port: Unable to open /dev/ttyS0 – ");
    } else {
        fcntl(fd1, F_SETFL, 0);
    }
    printf("Port 1 has been sucessfully opened and %d is the file description\n",fd1);
    configure_port(fd1);

wr = write(fd1, "\r", 1);
cout << " wr status " << wr << endl;
wr = write(fd1, "\r", 1);
cout << " wr  status " << wr << endl;
wr = write(fd1, "ena\r", 4);
cout << " wr status " << wr << endl;
wr = write(fd1, "show int sum\r", 13);
cout << " wr status " << wr << endl;
rd = read(fd1, buff, 50);
cout << " rd status " << rd << endl;
cout << rd << endl;
    return 0;
}

【问题讨论】:

  • 你设置好port_settings了吗?我注意到它没有初始化为零......
  • 我的第一个建议是“尝试 cu”(Linux)或“超级终端”(Windows)。但你已经做到了——RS232 连接正常。问:您是否尝试过将“port_settings”初始化为零?
  • @paulsm4 我是新手,你能把'port_settings'解释为0吗?
  • @Useless 如果你想添加 bzero(&port_settings, sizeof(port_settings));比这导致阅读挂起。没有它读取失败
  • 好的,首先:读取失败时,错误是什么?其次,如果读取挂起,大概它至少成功等待数据......我认为正确的行尾肯定是\r?您可以strace cu 和您的进程,比较确切他们都写给/dev/ttyS0 ...

标签: c linux serial-port cisco hardware-interface


【解决方案1】:

在修改 port_settings 结构之前,您不会先对其进行归零。这肯定是一个错误,尽管它可能不是问题的根源。您是否尝试过构建互联网上提供的数十个“termios 示例程序”之一以进行比较?

【讨论】:

  • 我尝试清零但读取挂起。我从互联网上复制我的示例。我也试过这个例子 - stackoverflow.com/questions/6947413/… ,但阅读仍然挂起
  • 您找不到 任何 与您的串行端口相关的工作示例?这似乎很奇怪。尝试在 minicom 运行和(挂起的)程序运行时运行 stty &lt; /dev/ttyS0,看看有什么区别。另外:请将您的示例程序修剪为最小子集。我认为没有理由使用fcntl 清除文件描述符标志、使用非阻塞 I/O 或使用 NOCTTY 以交互方式运行进程...
【解决方案2】:

这项工作 - 可能睡眠丢失了。

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>

using namespace std;

int set_interface_attribs(int fd, int speed, int parity) {
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd, &tty) != 0) {
        printf("err");//error_message("error %d from tcgetattr", errno);
        return -1;
    }

    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
    // disable IGNBRK for mismatched speed tests; otherwise receive break
    // as \000 chars
    tty.c_iflag &= ~IGNBRK;         // ignore break signal
    tty.c_lflag = 0;                // no signaling chars, no echo,
                                    // no canonical processing
    tty.c_oflag = 0;                // no remapping, no delays
    tty.c_cc[VMIN] = 0;            // read doesn't block
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
                                     // enable reading
    tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
    tty.c_cflag |= parity;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        printf("err");//error_message("error %d from tcsetattr", errno);
        return -1;
    }
    return 0;
}

void set_blocking(int fd, int should_block) {
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd, &tty) != 0) {
        printf("err");//error_message("error %d from tggetattr", errno);
        return;
    }

    tty.c_cc[VMIN] = should_block ? 1 : 0;
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
        printf("err");//error_message("error %d setting term attributes", errno);
}

int main(int argc, char **argv) {
    char *portname = "/dev/ttyS0";
    int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        printf("err");//error_message("error %d opening %s: %s", errno, portname,strerror(errno));
        return -1;
    }

    set_interface_attribs(fd, B9600, 0); // set speed to 115,200 bps, 8n1 (no parity)
    set_blocking(fd, 0);                // set no blocking
    write(fd, "\r", 1);           // send 7 character greeting
    write(fd, "\r", 1);
    usleep(100000);
    char buf[1000];
    write(fd, "ena\r", 4);
    memset(&buf, 0, sizeof buf);
    usleep(100000);
    write(fd, "show int sum\r", 15);
    sleep(1);
    memset(&buf, 0, sizeof buf);
    int n = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
    cout << " n " << n << endl;
    cout << " buf " << buf <<  endl;
    close(fd);
}

【讨论】:

  • 依靠睡眠或其他延迟来捕获完整回复是一种不可靠的实现,如果有一天连接的设备回复更慢,它可能会中断。您希望循环读取,直到通过指定的终止字符/条件收到完整回复,或者使用读取函数读取直到这种条件(或超时或其他故障)。
  • @ChrisStratton 你能不能参考一下“read with timeout”
  • 查看 select() 或相关的系统调用作为实现超时数据检查的一种方法,并且只有在它们指示数据可用时才读取。或者您可以将端口置于非阻塞模式并定期轮询它(但要注意,在紧密循环中的忙等待会占用大量 CPU 并降低其他任务的性能)。您似乎已经在设置非阻塞 I/O,因此缩短睡眠时间并进入循环直到收到完整的消息是可行的 - 但要注意在单个 multi 中收集一条消息的结尾和另一条消息的开头-字节读取。
【解决方案3】:

您应该使用 SNMP 来获取接口状态/统计信息,而不是连接到串行控制台。

这正是 SNMP 设计的目的。

【讨论】:

  • 管控电脑无法与路由器联网(安全),需要串口连接。
猜你喜欢
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 2022-11-09
  • 2015-06-04
  • 1970-01-01
  • 1970-01-01
  • 2014-08-04
  • 2017-07-31
相关资源
最近更新 更多