socketclient.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from __future__ import print_function
  2. # Adapted from https://github.com/benthor/remotty/blob/master/socketclient.py
  3. import sys
  4. import tty
  5. import fcntl
  6. import os
  7. import termios
  8. import threading
  9. import errno
  10. import logging
  11. log = logging.getLogger(__name__)
  12. class SocketClient:
  13. def __init__(self,
  14. socket_in=None,
  15. socket_out=None,
  16. socket_err=None,
  17. raw=True,
  18. ):
  19. self.socket_in = socket_in
  20. self.socket_out = socket_out
  21. self.socket_err = socket_err
  22. self.raw = raw
  23. self.stdin_fileno = sys.stdin.fileno()
  24. def __enter__(self):
  25. self.create()
  26. return self
  27. def __exit__(self, type, value, trace):
  28. self.destroy()
  29. def create(self):
  30. if os.isatty(sys.stdin.fileno()):
  31. self.settings = termios.tcgetattr(sys.stdin.fileno())
  32. else:
  33. self.settings = None
  34. if self.socket_in is not None:
  35. self.set_blocking(sys.stdin, False)
  36. self.set_blocking(sys.stdout, True)
  37. self.set_blocking(sys.stderr, True)
  38. if self.raw:
  39. tty.setraw(sys.stdin.fileno())
  40. def set_blocking(self, file, blocking):
  41. fd = file.fileno()
  42. flags = fcntl.fcntl(fd, fcntl.F_GETFL)
  43. flags = (flags & ~os.O_NONBLOCK) if blocking else (flags | os.O_NONBLOCK)
  44. fcntl.fcntl(fd, fcntl.F_SETFL, flags)
  45. def run(self):
  46. if self.socket_in is not None:
  47. self.start_background_thread(target=self.send, args=(self.socket_in, sys.stdin))
  48. recv_threads = []
  49. if self.socket_out is not None:
  50. recv_threads.append(self.start_background_thread(target=self.recv, args=(self.socket_out, sys.stdout)))
  51. if self.socket_err is not None:
  52. recv_threads.append(self.start_background_thread(target=self.recv, args=(self.socket_err, sys.stderr)))
  53. for t in recv_threads:
  54. t.join()
  55. def start_background_thread(self, **kwargs):
  56. thread = threading.Thread(**kwargs)
  57. thread.daemon = True
  58. thread.start()
  59. return thread
  60. def recv(self, socket, stream):
  61. try:
  62. while True:
  63. chunk = socket.recv(4096)
  64. if chunk:
  65. stream.write(chunk)
  66. stream.flush()
  67. else:
  68. break
  69. except Exception as e:
  70. log.debug(e)
  71. def send(self, socket, stream):
  72. while True:
  73. chunk = stream.read(1)
  74. if chunk == '':
  75. socket.close()
  76. break
  77. else:
  78. try:
  79. socket.send(chunk)
  80. except Exception as e:
  81. if hasattr(e, 'errno') and e.errno == errno.EPIPE:
  82. break
  83. else:
  84. raise e
  85. def destroy(self):
  86. if self.settings is not None:
  87. termios.tcsetattr(self.stdin_fileno, termios.TCSADRAIN, self.settings)
  88. sys.stdout.flush()
  89. if __name__ == '__main__':
  90. import websocket
  91. if len(sys.argv) != 2:
  92. sys.stderr.write("Usage: python socketclient.py WEBSOCKET_URL\n")
  93. sys.exit(1)
  94. url = sys.argv[1]
  95. socket = websocket.create_connection(url)
  96. print("connected\r")
  97. with SocketClient(socket, interactive=True) as client:
  98. client.run()