socketclient.py 3.3 KB

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