mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-24 05:03:34 -04:00
Use more efficient ReceiveAsync/SendAsync for even less memory allocations
This commit is contained in:
parent
6711538f06
commit
51a25d7c44
@ -25,39 +25,48 @@ namespace MCGalaxy.Network {
|
|||||||
readonly Socket socket;
|
readonly Socket socket;
|
||||||
|
|
||||||
byte[] unprocessed = new byte[352];
|
byte[] unprocessed = new byte[352];
|
||||||
byte[] recvBuffer = new byte[256];
|
byte[] recvBuffer = new byte[256];
|
||||||
int unprocessedLen;
|
int unprocessedLen;
|
||||||
|
readonly SocketAsyncEventArgs recvArgs = new SocketAsyncEventArgs();
|
||||||
|
|
||||||
byte[] sendBuffer = new byte[1536];
|
byte[] sendBuffer = new byte[1536];
|
||||||
readonly object sendLock = new object();
|
readonly object sendLock = new object();
|
||||||
readonly Queue<byte[]> sendQueue = new Queue<byte[]>(64);
|
readonly Queue<byte[]> sendQueue = new Queue<byte[]>(64);
|
||||||
volatile bool sendInProgress;
|
volatile bool sendInProgress;
|
||||||
|
readonly SocketAsyncEventArgs sendArgs = new SocketAsyncEventArgs();
|
||||||
|
|
||||||
public TcpSocket(Player p, Socket s) {
|
public TcpSocket(Player p, Socket s) {
|
||||||
player = p; socket = s;
|
player = p; socket = s;
|
||||||
|
|
||||||
|
recvArgs.SetBuffer(recvBuffer, 0, recvBuffer.Length);
|
||||||
|
recvArgs.Completed += recvCallback;
|
||||||
|
recvArgs.UserToken = this;
|
||||||
|
|
||||||
|
sendArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
|
||||||
|
sendArgs.Completed += sendCallback;
|
||||||
|
sendArgs.UserToken = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string RemoteIP {
|
public string RemoteIP {
|
||||||
get { return ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(); }
|
get { return ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LowLatency {
|
public bool LowLatency { set { socket.NoDelay = value; } }
|
||||||
set { socket.NoDelay = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static AsyncCallback recvCallback = new AsyncCallback(ReceiveCallback);
|
static EventHandler<SocketAsyncEventArgs> recvCallback = RecvCallback;
|
||||||
public void ReceiveNextAsync() {
|
public void ReceiveNextAsync() {
|
||||||
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, recvCallback, this);
|
// ReceiveAsync returns false if completed sync
|
||||||
|
if (!socket.ReceiveAsync(recvArgs)) RecvCallback(null, recvArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReceiveCallback(IAsyncResult result) {
|
static void RecvCallback(object sender, SocketAsyncEventArgs e) {
|
||||||
TcpSocket s = (TcpSocket)result.AsyncState;
|
TcpSocket s = (TcpSocket)e.UserToken;
|
||||||
Player p = s.player;
|
Player p = s.player;
|
||||||
if (p.disconnected) return;
|
if (p.disconnected) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int recvLen = s.socket.EndReceive(result);
|
int recvLen = e.BytesTransferred;
|
||||||
if (recvLen == 0) { p.Disconnect(); return; }
|
if (recvLen == 0) { p.Disconnect(); return; }
|
||||||
|
|
||||||
// Packets may not always be fully received in a Receive call
|
// Packets may not always be fully received in a Receive call
|
||||||
@ -84,14 +93,14 @@ namespace MCGalaxy.Network {
|
|||||||
Player.connections.Remove(p);
|
Player.connections.Remove(p);
|
||||||
p.RemoveFromPending();
|
p.RemoveFromPending();
|
||||||
p.disconnected = true;
|
p.disconnected = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception ex) {
|
||||||
Logger.LogError(e);
|
Logger.LogError(ex);
|
||||||
p.Leave("Error!");
|
p.Leave("Error!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static AsyncCallback sendCallback = new AsyncCallback(SendCallback);
|
static EventHandler<SocketAsyncEventArgs> sendCallback = SendCallback;
|
||||||
public void Send(byte[] buffer, bool sync = false) {
|
public void Send(byte[] buffer, bool sync = false) {
|
||||||
// Abort if socket has been closed
|
// Abort if socket has been closed
|
||||||
if (player.disconnected || !socket.Connected) return;
|
if (player.disconnected || !socket.Connected) return;
|
||||||
@ -127,14 +136,16 @@ namespace MCGalaxy.Network {
|
|||||||
Buffer.BlockCopy(buffer, 0, sendBuffer, 0, buffer.Length);
|
Buffer.BlockCopy(buffer, 0, sendBuffer, 0, buffer.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.BeginSend(sendBuffer, 0, buffer.Length, SocketFlags.None, sendCallback, this);
|
sendArgs.SetBuffer(0, buffer.Length);
|
||||||
|
// SendAsync returns false if completed sync
|
||||||
|
if (!socket.SendAsync(sendArgs)) SendCallback(null, sendArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SendCallback(IAsyncResult result) {
|
static void SendCallback(object sender, SocketAsyncEventArgs e) {
|
||||||
TcpSocket s = (TcpSocket)result.AsyncState;
|
TcpSocket s = (TcpSocket)e.UserToken;
|
||||||
try {
|
try {
|
||||||
// TODO: Need to check if all data was sent or not?
|
// TODO: Need to check if all data was sent or not?
|
||||||
int sent = s.socket.EndSend(result);
|
int sent = e.BytesTransferred;
|
||||||
lock (s.sendLock) {
|
lock (s.sendLock) {
|
||||||
s.sendInProgress = false;
|
s.sendInProgress = false;
|
||||||
if (s.sendQueue.Count > 0) {
|
if (s.sendQueue.Count > 0) {
|
||||||
@ -154,6 +165,8 @@ namespace MCGalaxy.Network {
|
|||||||
try { socket.Shutdown(SocketShutdown.Both); } catch { }
|
try { socket.Shutdown(SocketShutdown.Both); } catch { }
|
||||||
try { socket.Close(); } catch { }
|
try { socket.Close(); } catch { }
|
||||||
lock (sendLock) { sendQueue.Clear(); }
|
lock (sendLock) { sendQueue.Clear(); }
|
||||||
|
try { recvArgs.Dispose(); } catch { }
|
||||||
|
try { sendArgs.Dispose(); } catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user