egametang/ET · error · Exception
TChannel已经被Dispose, 不能发送消息
Error message
TChannel已经被Dispose, 不能发送消息
What it means
TChannel.Send checks IsDisposed before queuing and throws if the channel's socket has been closed. This guards against use-after-free: someone is trying to send on a channel that is already torn down.
Source
Thrown at Packages/cn.etetet.core/Scripts/Core/Share/Network/TChannel.cs:97
Log.Info($"channel dispose: {this.Id} {this.RemoteAddress} {this.Error}");
long id = this.Id;
this.Id = 0;
this.Service.Remove(id);
this.socket.Close();
this.innArgs.Dispose();
this.outArgs.Dispose();
this.innArgs = null;
this.outArgs = null;
this.socket = null;
}
public void Send(MemoryBuffer stream)
{
if (this.IsDisposed)
{
throw new Exception("TChannel已经被Dispose, 不能发送消息");
}
switch (this.Service.ServiceType)
{
case ServiceType.Inner:
{
int messageSize = (int) (stream.Length - stream.Position);
if (messageSize > ushort.MaxValue * 16)
{
throw new Exception($"send packet too large: {stream.Length} {stream.Position}");
}
this.sendCache.WriteTo(0, messageSize);
this.sendBuffer.Write(this.sendCache, 0, PacketParser.InnerPacketSizeLength);
break;
}
case ServiceType.Outer:
{View on GitHub (pinned to 5cab01f7a8)
Solutions
- Null/clear channel references when the channel is disposed or errors out.
- Check IsDisposed at the call site before sending.
- Drive sends only through the session lifecycle that owns the channel.
Example fix
// before channel.Send(memoryBuffer); // after if (channel == null || channel.IsDisposed) return; channel.Send(memoryBuffer);
Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
public static bool CanSend(TChannel c) => c != null && !c.IsDisposed;
Try / catch
null
Prevention
- Null out session channel references on remove/error.
- Check IsDisposed before Send at the session layer.
- Never enqueue work for a channel past its lifecycle end.
When it happens
Trigger: Application code holding a channel reference after disconnect/error and calling Send, or a send queued during shutdown racing with Dispose.
Common situations: Session not notified of channel removal, reconnect logic reusing a stale channel, or shutdown ordering where Send runs after Dispose.
Related errors
- recv packet size error, 可能是外网探测端口: {this.packetSize}
- send packet too large: {stream.Length} {stream.Position}
- socket set buffer error: {this.sendBuffer.First.Length}, {th
- bind error: {ipEndPoint}
- socket error: {e.LastOperation}
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/f35538a3c80a5841.
Report an issue: GitHub.