mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-23 04:32:50 -04:00
Optimise sending to avoid unnecessary pinning
This commit is contained in:
parent
e0875e0924
commit
0a6b5d3ee0
@ -36,7 +36,7 @@ namespace MCGalaxy.Network {
|
||||
void Send(byte[] buffer, bool sync = false);
|
||||
|
||||
/// <summary> Sends a block of low-priority data, either synchronously or asynchronously. </summary>
|
||||
void SendLowPriority(byte[] buffer, bool sync = false);
|
||||
void SendLowPriority(byte[] buffer);
|
||||
|
||||
/// <summary> Closes this network socket. </summary>
|
||||
void Close();
|
||||
|
@ -13,6 +13,7 @@ or implied. See the Licenses for the specific language governing
|
||||
permissions and limitations under the Licenses.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
@ -27,6 +28,11 @@ namespace MCGalaxy.Network {
|
||||
byte[] recvBuffer = new byte[256];
|
||||
int unprocessedLen;
|
||||
|
||||
byte[] sendBuffer = new byte[1536];
|
||||
readonly object sendLock = new object();
|
||||
readonly Queue<byte[]> sendQueue = new Queue<byte[]>(64);
|
||||
volatile bool sendInProgress;
|
||||
|
||||
public TcpSocket(Player p, Socket s) {
|
||||
player = p; socket = s;
|
||||
}
|
||||
@ -39,6 +45,7 @@ namespace MCGalaxy.Network {
|
||||
set { socket.NoDelay = value; }
|
||||
}
|
||||
|
||||
|
||||
static AsyncCallback recvCallback = new AsyncCallback(ReceiveCallback);
|
||||
public void ReceiveNextAsync() {
|
||||
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, recvCallback, this);
|
||||
@ -73,8 +80,7 @@ namespace MCGalaxy.Network {
|
||||
} catch (SocketException) {
|
||||
p.Disconnect();
|
||||
} catch (ObjectDisposedException) {
|
||||
// Player is no longer connected, socket was closed
|
||||
// Mark this as disconnected and remove them from active connection list
|
||||
// Socket was closed by another thread, mark as disconnected
|
||||
Player.connections.Remove(p);
|
||||
p.RemoveFromPending();
|
||||
p.disconnected = true;
|
||||
@ -91,68 +97,63 @@ namespace MCGalaxy.Network {
|
||||
if (player.disconnected || !socket.Connected) return;
|
||||
|
||||
try {
|
||||
if (sync)
|
||||
if (sync) {
|
||||
socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
|
||||
else
|
||||
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, this);
|
||||
buffer = null;
|
||||
} catch (SocketException e) {
|
||||
buffer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
lock (sendLock) {
|
||||
if (sendInProgress) { sendQueue.Enqueue(buffer); }
|
||||
else { DoSendAsync(buffer); }
|
||||
}
|
||||
} catch (SocketException) {
|
||||
player.Disconnect();
|
||||
#if DEBUG
|
||||
Logger.LogError(e);
|
||||
#endif
|
||||
} catch (ObjectDisposedException) {
|
||||
// socket was already closed by another thread.
|
||||
buffer = null;
|
||||
// Socket was already closed by another thread
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do this seprately
|
||||
public void SendLowPriority(byte[] buffer, bool sync = false) {
|
||||
Send(buffer, sync);
|
||||
public void SendLowPriority(byte[] buffer) { Send(buffer, false); }
|
||||
|
||||
void DoSendAsync(byte[] buffer) {
|
||||
sendInProgress = true;
|
||||
// BlockCopy has some overhead, not worth using for very small data
|
||||
if (buffer.Length <= 16) {
|
||||
for (int i = 0; i < buffer.Length; i++) {
|
||||
sendBuffer[i] = buffer[i];
|
||||
}
|
||||
} else {
|
||||
Buffer.BlockCopy(buffer, 0, sendBuffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
socket.BeginSend(sendBuffer, 0, buffer.Length, SocketFlags.None, sendCallback, this);
|
||||
}
|
||||
|
||||
static void SendCallback(IAsyncResult result) {
|
||||
// TODO: call EndSend, need to check if all data was sent or not!
|
||||
/*TcpSocket s = (TcpSocket)result.AsyncState;
|
||||
|
||||
TcpSocket s = (TcpSocket)result.AsyncState;
|
||||
try {
|
||||
// TODO: Need to check if all data was sent or not?
|
||||
int sent = s.socket.EndSend(result);
|
||||
} catch (SocketException e) {
|
||||
lock (s.sendLock) {
|
||||
s.sendInProgress = false;
|
||||
if (s.sendQueue.Count > 0) {
|
||||
s.DoSendAsync(s.sendQueue.Dequeue());
|
||||
}
|
||||
}
|
||||
} catch (SocketException) {
|
||||
s.player.Disconnect();
|
||||
#if DEBUG
|
||||
Logger.LogError(e);
|
||||
#endif
|
||||
} catch (ObjectDisposedException) {
|
||||
// socket was already closed by another thread.
|
||||
}*/
|
||||
// Socket was already closed by another thread
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Close() {
|
||||
// Try to close the socket. Sometimes socket is already closed, so just hide this.
|
||||
#if !DEBUG
|
||||
try { socket.Shutdown(SocketShutdown.Both); } catch { }
|
||||
try { socket.Close(); } catch { }
|
||||
|
||||
#else
|
||||
try {
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
Logger.Log(LogType.Debug, "Socket was shutdown for " + name ?? ip);
|
||||
} catch (Exception e) {
|
||||
Exception ex = new Exception("Failed to shutdown socket for " + name ?? ip, e);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
|
||||
try {
|
||||
socket.Close();
|
||||
Logger.Log(LogType.Debug, "Socket was closed for " + name ?? ip);
|
||||
} catch (Exception e) {
|
||||
Exception ex = new Exception("Failed to close socket for " + name ?? ip, e);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
#endif
|
||||
lock (sendLock) { sendQueue.Clear(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,42 +54,42 @@ namespace MCGalaxy {
|
||||
}
|
||||
|
||||
void SendCpeExtensions() {
|
||||
Send(Packet.ExtInfo(26), true);
|
||||
Send(Packet.ExtInfo(26));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAppearance, 1), true); // fix for classicube client, doesn't reply if only send EnvMapAppearance with version 2
|
||||
Send(Packet.ExtEntry(CpeExt.ClickDistance, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.CustomBlocks, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAppearance, 1)); // fix for classicube client, doesn't reply if only send EnvMapAppearance with version 2
|
||||
Send(Packet.ExtEntry(CpeExt.ClickDistance, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.CustomBlocks, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.HeldBlock, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.TextHotkey, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EnvColors, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.HeldBlock, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.TextHotkey, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.EnvColors, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.SelectionCuboid, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.BlockPermissions, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.ChangeModel, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.SelectionCuboid, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.BlockPermissions, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.ChangeModel, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAppearance, 2), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EnvWeatherType, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.HackControl, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAppearance, 2));
|
||||
Send(Packet.ExtEntry(CpeExt.EnvWeatherType, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.HackControl, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.EmoteFix, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.FullCP437, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.LongerMessages, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EmoteFix, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.FullCP437, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.LongerMessages, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.BlockDefinitions, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.BlockDefinitionsExt, 2), true);
|
||||
Send(Packet.ExtEntry(CpeExt.TextColors, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.BlockDefinitions, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.BlockDefinitionsExt, 2));
|
||||
Send(Packet.ExtEntry(CpeExt.TextColors, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.BulkBlockUpdate, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.MessageTypes, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.ExtPlayerList, 2), true);
|
||||
Send(Packet.ExtEntry(CpeExt.BulkBlockUpdate, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.MessageTypes, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.ExtPlayerList, 2));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAspect, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.PlayerClick, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EntityProperty, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.EnvMapAspect, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.PlayerClick, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.EntityProperty, 1));
|
||||
|
||||
Send(Packet.ExtEntry(CpeExt.ExtEntityPositions, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.TwoWayPing, 1), true);
|
||||
Send(Packet.ExtEntry(CpeExt.ExtEntityPositions, 1));
|
||||
Send(Packet.ExtEntry(CpeExt.TwoWayPing, 1));
|
||||
}
|
||||
|
||||
void CompleteLoginProcess() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user