public void dispose() throws IOException {
		plugin.removeHandler(this);
		flushXReqQueue(new TraceRmiError("Socket closed"));

		terminateTerminals();

		socket.close();
		synchronized (openTxes) {
			while (!openTxes.isEmpty()) {
				Tid nextKey = openTxes.keySet().iterator().next();
				OpenTx openTx = openTxes.remove(nextKey);
				openTx.tx.close();
			}
		}

		for (OpenTrace open : openTraces.clearAll()) {
			if (traceManager == null || traceManager.isSaveTracesByDefault()) {
				try (CloseableTaskMonitor monitor = plugin.createMonitor()) {
					open.trace.save("Save on Disconnect", monitor);
				}
				catch (IOException e) {
					Msg.error(this, "Could not save " + open.trace);
				}
				catch (CancelledException e) {
					// OK. Move on
				}
			}
			open.dispose(this);
		}
		closed.complete(null);
		plugin.listeners.invoke().disconnected(this);
	}
Create a handler

<p>
Note it is common for this to be constructed by a TCP <em>client</em>.

@param plugin the Trace RMI plugin
@param socket the socket to the back-end debugger
@throws IOException if there is an issue with the I/O streams
Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java