Commands to Configure unix telnet to show and rece

2019-08-27 23:49发布

问题:

I have a special application (8051 simulator from ucsim) on a local server that transmits and expects non-printable characters on only one port. Essentially, I'm defining my own data format.

Telnet would have been the perfect program if I can see the hex codes of each character returned back in 30 columns as well as being able to type hex codes of characters going out. Problem is, the telnet shipped with Linux only allows 1 row of hex characters and may alter behaviour when certain characters are received.

So far, the closest solution I have is to run the realterm program in wine and choose hex display, but the problem with it is that it locks up if I switch windows. until I stop the server from transmitting and receiving characters. So I'm looking for a native linux solution to all this.

As for receiving data, I can easily get away with this command:

nc 127.0.0.1 port | od -tx1 -w30

But when it comes to sending data on the same open port as what data is flowing out on, I try this command:

echo -e -n "\x11\x22\x33" | nc 127.0.0.1 port

where 11, 22, 33, are hexadecimal digits to send back out to the server. Problem is when I try this command, it just stalls and I have to press CTRL+C to exit.

Is my logic correct here?

or are there better commands I can use in unix to see hexadecimal characters from a server that transmits binary and also transmit binary codes of the hexadecimal characters typed in at the local console?

It would be perfect if the realterm program currently works in linux without the need of wine.

P.S. I'm sorry if this forum isn't the perfect place for this question, but personally, I wouldn't mind making a unix script of 50 commands if that's what it takes to get what I achieve, because the application I'm looking for has yet to exist for linux.

回答1:

nc will read from its standard input and send that data over the network connection. So if you simply want to be able to type hex digits into the terminal and have the corresponding binary sent to the simulator, you could use something like xxd -r -p to pipe data into nc. I.e. change nc 127.0.0.1 ... to xxd -r -p | nc 127.0.0.1 ....

You can then type "41 42 43 44" (followed by return, because interactive input is line-buffered) into the xxd command and that should deliver "ABCD" to the simulator. xxd in its -r -p mode treats any non-hex digits as separators, so it's safe to put spaces between pairs of hex digits for readability if you want.

If you wanted to be able to send different types of data (hex, binary) from a variety of sources (interactive, cat'ed from files) during the course of a development session then you could probably rig up a second persistent nc listener on a different port to collect that data and feed it into the stdin of the existing nc.


Update with a Python program that will read hex from stdin and send the corresponding binary over a network connection, and will read data from the connection and write is as hex to standard output. Save it as something like nethex.py and invoke it as python nethex.py <host> <port>.

#!/usr/bin/env python

import binascii
import re
import socket
import sys
import threading


def breakstring(string, maxchars):
    return [ string[pos:(pos + maxchars)]
             for pos in xrange(0, len(string), maxchars) ]

def to_hex(bytes):
    lines = breakstring(binascii.hexlify(bytes), 32)
    return ''.join([ (' '.join(breakstring(line, 2)) + '\n') for line in lines ])


def from_hex(s):
    hexlist = re.sub('[^0-9A-Fa-f]', ' ', s).split()
    pairs = [ '0' + hexstr if len(hexstr)%2 else hexstr for hexstr in hexlist ]
    return binascii.unhexlify(''.join(pairs))


def connect(addr, port):
    conn = None

    infos = socket.getaddrinfo(addr, port, 0, socket.SOCK_STREAM)
    for info in infos:
        fam, typ, proto, fqdn, sa = info
        try:
            conn = socket.socket(fam, typ, proto)
        except socket.error:
            sys.stderr.write('socket: ' + str(se) + '\n')
            continue

        try:
            conn.connect(sa)
        except socket.error as se:
            sys.stderr.write('connect: ' + str(se) + '\n')
            conn.close()
            conn = None
            continue

        break

    return conn


class SockDrainer(threading.Thread):

    def __init__(self, sock, sink):
        super(SockDrainer, self).__init__()
        self.sock = sock
        self.sink = sink

    def run(self):
        drain(self.sock, self.sink)


def drain(sock, dest):
    while True:
        data = sock.recv(2048)
        if not data:
            break
        outdata = to_hex(data)
        dest.write(outdata)
        dest.flush()


def fill(sock, source):
    while True:
        data = source.readline()
        if not data:
            break
        try:
            outdata = from_hex(data)
            sock.send(outdata)
        except socket.error:
            break

    try:
        sock.shutdown(socket.SHUT_WR)
    except socket.error:
        pass


def nethex(addr, port):
    conn = connect(addr, port)

    if conn is not None:
        drainer = SockDrainer(conn, sys.stdout)
        drainer.daemon = True   # thread will not block process termination
        drainer.start()

        fill(conn, sys.stdin)

        drainer.join()          # wait for rx'ed data to be handled

        conn.close()

    return conn is not None


if __name__ == '__main__':
    result = nethex(sys.argv[1], sys.argv[2])
    sys.exit(0 if result else 1)