如何“刷新”TCP客户端缓冲区?
我从几个示例中提取了一个连接到服务器的全双工C#TCP客户端。 基本概念是客户端和服务器都发送/接收消息(命令和事件)。 因此,我开发了一个FullDuplexSocket类,它公开了一个Send方法来向服务器发送消息,以及一个事件处理程序来接收来自服务器的消息。 一切正常,除了我似乎无法刷新从服务器收到的消息的缓冲区。 每次服务器发送新消息时,套接字中的缓冲区都包含所有旧消息(已读取) 和新消息。 我可以通过已知的分隔符(/ r / n)拆分消息并跟踪它们,但这可能是长时间运行通信时内存问题的根源。 [编辑:将代码更新为不再存在缓冲区问题并且工作正常的解决方案]。
有没有人有什么建议。 总重写??? 代码如下,希望它能帮助他人。
这是FullDuplexSocket类:
using System; using System.Text; using System.Net.Sockets; namespace Utilities { public class StateObject{ public Socket workSocket = null; public const int BUFFER_SIZE = 1024; public byte[] buffer = new byte[BUFFER_SIZE]; } public class FullDuplexSocket : IDisposable { public event NewMessageHandler OnMessageReceived; public delegate void NewMessageHandler(string Message); public event DisconnectHandler OnDisconnect; public delegate void DisconnectHandler(string Reason); private Socket _socket; private bool _useASCII = true; private string _remoteServerIp = ""; private int _port = 0; /// /// Constructer of a full duplex client socket. The consumer should immedately define /// and event handler for the OnMessageReceived event after construction has completed. /// /// The remote Ip address of the server. /// The port that will used to transfer/receive messages to/from the remote IP. /// The character type to encode/decode messages. Defaulted to use ASCII, but setting the value to false will encode/decode messages in UNICODE. public FullDuplexSocket(string RemoteServerIp, int Port, bool UseASCII = true) { _useASCII = UseASCII; _remoteServerIp = RemoteServerIp; _port = Port; try //to create the socket and connect { _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.Connect(RemoteServerIp, _port); } catch (Exception e) { throw new Exception("Unable to connect to the remote Ip.", e); } try //to listen to the socket { StateObject stateObject = new StateObject(); stateObject.workSocket = _socket; _socket.BeginReceive ( stateObject.buffer, //Buffer to load in our state object 0, //Start at the first position in the byte array StateObject.BUFFER_SIZE, //only load up to the max per read 0, //Set socket flags here if necessary new AsyncCallback(ReadFromSocket), //Who to call when data arrives stateObject //state object to use when data arrives ); } catch (Exception e) { throw new Exception("Unable to start listening to the socket.", e); } } /// /// This will read the bytes from the socket, convert the bytes to a string and fire the OnMessageReceived event. /// If the socket is forcibly closed, the OnDisconnect event will be fired. This happens when the other side of /// the socket connection on the remote Ip is no longer available. /// /// public void ReadFromSocket(IAsyncResult asyncResult) { StateObject stateObject = (StateObject)asyncResult.AsyncState; //pull out the state object int bytesReceived = 0; try //to receive the message. { bytesReceived = stateObject.workSocket.EndReceive(asyncResult); } catch (Exception e) //Exception will occur if connection was forcibly closed. { RaiseOnDisconnect(e.Message); return; } if (bytesReceived > 0) { RaiseOnMessageReceived ( _useASCII ? Encoding.ASCII.GetString(stateObject.buffer, 0, bytesReceived) : Encoding.Unicode.GetString(stateObject.buffer, 0, bytesReceived) ); stateObject.workSocket.BeginReceive ( stateObject.buffer, //Buffer to load in our state object 0, //Start at the first position in the byte array StateObject.BUFFER_SIZE, //only load up to the max per read 0, //Set socket flags here if necessary new AsyncCallback(ReadFromSocket), //Who to call when data arrives stateObject //state object to use when data arrives ); } else { stateObject.workSocket.Close(); RaiseOnDisconnect("Socket closed normally."); return; } } /// /// Broadcast a message to the IP/Port. Consumer should handle any exceptions thrown by the socket. /// /// The message to be sent will be encoded using the character set defined during construction. public void Send(string Message) { //all messages are terminated with /r/n Message += Environment.NewLine; byte[] bytesToSend = _useASCII ? Encoding.ASCII.GetBytes(Message) : Encoding.Unicode.GetBytes(Message); int bytesSent = _socket.Send(bytesToSend); } /// /// Clean up the socket. /// void IDisposable.Dispose() { try { _socket.Close(); RaiseOnDisconnect("Socket closed via Dispose method."); } catch { } try { _socket.Dispose(); } catch { } } /// /// This method will gracefully raise any delegated events if they exist. /// /// private void RaiseOnMessageReceived(string Message) { try //to raise delegates { OnMessageReceived(Message); } catch { } //when none exist ignore the Object Reference Error } /// /// This method will gracefully raise any delegated events if they exist. /// /// private void RaiseOnDisconnect(string Message) { try //to raise delegates { OnDisconnect(Message); } catch { } //when none exist ignore the Object Reference Error } } }
该类的消费者将简单地执行以下操作:
using System; namespace Utilities { public class SocketConsumer { private FullDuplexSocket _fds; public Consumer() { _fds = new FullDuplexSocket("192.168.1.103", 4555); _fds.OnMessageReceived += fds_OnMessageReceived; _fds.Send("Hello World!"); } void fds_OnMessageReceived(string Message) { Console.WriteLine("Message: {0}", Message); } } }
任何帮助都会很棒。 谢谢!
即使缓冲区尚未填充,您也调用bytesRead < count
(如果bytesRead < count
)。 考虑切换到await
应用程序的异步部分。 这摆脱了可怕的回调递归。