下面的NetworkEndpoint类作为网络连接(客户端或服务器)任何一方的一个简单的发送/接收接口,只要提供一个套接字即可操作。
对于当前状态下的代码,我有两个主要的担忧:
if (Receiving) return; in void InitializeReceiveLoop())但是还有其他一些我忽略的线程安全问题吗??我对C#的知识主要是自学的,所以如果我的代码没有反映最佳实践或标准样式指南,我很抱歉。
任何有关这些问题的建议或关于改进我的代码的一般性建议都将不胜感激。
public class NetworkEndpoint {
private Socket connection;
public bool Connected { get => connection != null ? connection.Connected : false; }
public bool Receiving { get; private set; }
public event EventHandler<NetworkReceiveEventArgs> DataReceived;
private void OnDataReceived(NetworkHeader header, byte[] data) =>
DataReceived?.Invoke(this, new NetworkReceiveEventArgs(header, data));
public event EventHandler Disconnected;
private void OnDisconnected() =>
Disconnected?.Invoke(this, new EventArgs());
public NetworkEndpoint(Socket socket) {
connection = socket ?? throw new ArgumentNullException("socket");
Receiving = false;
}
public void Send(NetworkHeader header, byte[] data) {
if (!Connected) throw new InvalidOperationException("NetworkEndpoint must be connected before sending.");
try {
connection.Send(ByteUtils.Combine(header.Serialize(), data));
} catch (SocketException ex) {
Disconnect();
}
}
public void Disconnect() {
connection?.Shutdown(SocketShutdown.Both);
connection?.Close();
connection = null;
OnDisconnected();
}
public void InitializeReceiveLoop() {
if (Receiving) return;
Receiving = true;
BeginReceive();
}
private byte[] headBuffer = new byte[NetworkHeader.ByteSize];
private void BeginReceive() {
connection.BeginReceive(headBuffer, 0, NetworkHeader.ByteSize, SocketFlags.None, EndReceive, null);
}
private void EndReceive(IAsyncResult result) {
bool fullyReceived = false;
byte[] dataBuffer = null;
NetworkHeader header = null;
try {
if (connection.EndReceive(result) > 0) {
header = NetworkHeader.Deserialize(headBuffer);
dataBuffer = new byte[header.DataSize];
int receivedLength = connection.Receive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None);
fullyReceived = (receivedLength == header.DataSize);
}
} catch (SocketException) { }
if (fullyReceived) {
OnDataReceived(header, dataBuffer);
BeginReceive();
} else if (connection.Connected) Disconnect();
}
}发布于 2019-06-26 06:32:45
Connected不是线程安全的.使用Interlocked.CompareExchange以原子方式获取连接。DataReceived和Disconnected从未被清除。这会导致内存泄漏。实现Clear函数和/或实现IDisposable。Send,Disconnect,EndReceive不线程安全.考虑使用互斥锁。fullyReceived上检查receivedLength == header.DataSize是很天真的,可能会被破坏。TCP消息可以在几个数据包中发送。使用内部缓冲区代替。此外,receivedLength = 0是确定没有更多数据可用的一种干净方法。SocketException是一种代码气味.https://codereview.stackexchange.com/questions/222944
复制相似问题