r"""Socket-based `IOStream` implementation. This class supports the read and write methods from `BaseIOStream` plus a `connect` method. The ``socket`` parameter may either be connected or unconnected. For server operations the socket is the result of calling `socket.accept <soc
| 1074 | |
| 1075 | |
| 1076 | class IOStream(BaseIOStream): |
| 1077 | r"""Socket-based `IOStream` implementation. |
| 1078 | |
| 1079 | This class supports the read and write methods from `BaseIOStream` |
| 1080 | plus a `connect` method. |
| 1081 | |
| 1082 | The ``socket`` parameter may either be connected or unconnected. |
| 1083 | For server operations the socket is the result of calling |
| 1084 | `socket.accept <socket.socket.accept>`. For client operations the |
| 1085 | socket is created with `socket.socket`, and may either be |
| 1086 | connected before passing it to the `IOStream` or connected with |
| 1087 | `IOStream.connect`. |
| 1088 | |
| 1089 | A very simple (and broken) HTTP client using this class: |
| 1090 | |
| 1091 | .. testcode:: |
| 1092 | |
| 1093 | import tornado.ioloop |
| 1094 | import tornado.iostream |
| 1095 | import socket |
| 1096 | |
| 1097 | async def main(): |
| 1098 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) |
| 1099 | stream = tornado.iostream.IOStream(s) |
| 1100 | await stream.connect(("friendfeed.com", 80)) |
| 1101 | await stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n") |
| 1102 | header_data = await stream.read_until(b"\r\n\r\n") |
| 1103 | headers = {} |
| 1104 | for line in header_data.split(b"\r\n"): |
| 1105 | parts = line.split(b":") |
| 1106 | if len(parts) == 2: |
| 1107 | headers[parts[0].strip()] = parts[1].strip() |
| 1108 | body_data = await stream.read_bytes(int(headers[b"Content-Length"])) |
| 1109 | print(body_data) |
| 1110 | stream.close() |
| 1111 | |
| 1112 | if __name__ == '__main__': |
| 1113 | asyncio.run(main()) |
| 1114 | |
| 1115 | .. testoutput:: |
| 1116 | :hide: |
| 1117 | |
| 1118 | """ |
| 1119 | |
| 1120 | def __init__(self, socket: socket.socket, *args: Any, **kwargs: Any) -> None: |
| 1121 | self.socket = socket |
| 1122 | self.socket.setblocking(False) |
| 1123 | super().__init__(*args, **kwargs) |
| 1124 | |
| 1125 | def fileno(self) -> Union[int, ioloop._Selectable]: |
| 1126 | return self.socket |
| 1127 | |
| 1128 | def close_fd(self) -> None: |
| 1129 | self.socket.close() |
| 1130 | self.socket = None # type: ignore |
| 1131 | |
| 1132 | def get_fd_error(self) -> Optional[Exception]: |
| 1133 | errno = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) |
no outgoing calls