How to gracefully close Async Server Socket? WITH#

I saw a lot of questions about handling sockets without excluded exception objects, so I decided to hack it and see if it could be done. Here are my findings.

Problem?

You have a piece of code that uses Socket from System.Net.Sockets, which is a server socket. The problem is that you want to close the socket, and every time you try to get an ObjectDisposedException.

Your code might look something like this:

private static ManualResetEvent allDone = new ManualResetEvent(false); private Socket ear; public void Start() { new Thread(() => StartListening()).Start(); } private void StartListening() { IP = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).First(); port = 11221; IPEndPoint localEndPoint = new IPEndPoint(IP, Port); ear = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ear.Bind(localEndPoint); ear.Listen(100); try { while (true) { allDone.Reset(); ear.BeginAccept(new AsyncCallback(AcceptCallback), ear); allDone.WaitOne(); } } catch (ObjectDisposedException e) { Console.WriteLine("Socket Closed"); } } private void AcceptCallback(IAsyncResult ar) { allDone.Set(); Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); StateObject state = new StateObject(); state.workSocket = handler; handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } public static void ReadCallback(IAsyncResult ar) { String content = String.Empty; StateObject state = (StateObject) ar.AsyncState; Socket handler = state.workSocket; int bytesRead = handler.EndReceive(ar); if (bytesRead > 0) { state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); content = state.sb.ToString(); if (content.IndexOf("<EOF>") > -1) { Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content ); } else { handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } } } public void Stop() { ear.Close(); } 

Running code similar to the above will give you an error in AcceptCallback, which is trying to complete the reception. Even if you catch this, you still get an error in the StartListening () method.

+6
source share
1 answer

So here is how I fixed it:

First I added the logical name IsListening.

Next, I changed the condition that holds the ear during (IsListening).

In the stop method, I set the IsListening variable to false before calling ear.close (), and finally I will test the ear inside AcceptCallback after Manual SetEvent.

The end result is as follows:

  private static ManualResetEvent allDone = new ManualResetEvent(false); private Socket ear; public void Start() { new Thread(() => StartListening()).Start(); } private void StartListening() { IP = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).First(); port = 11221; IPEndPoint localEndPoint = new IPEndPoint(IP, Port); ear = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ear.Bind(localEndPoint); ear.Listen(100); IsListening = true; while (IsListening) { allDone.Reset(); ear.BeginAccept(new AsyncCallback(AcceptCallback), ear); allDone.WaitOne(); } Console.WriteLine("Socket Closed"); } private void AcceptCallback(IAsyncResult ar) { allDone.Set(); if (IsListening == false) return; Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); StateObject state = new StateObject(); state.workSocket = handler; handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } public static void ReadCallback(IAsyncResult ar) { String content = String.Empty; StateObject state = (StateObject) ar.AsyncState; Socket handler = state.workSocket; int bytesRead = handler.EndReceive(ar); if (bytesRead > 0) { state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); content = state.sb.ToString(); if (content.IndexOf("<EOF>") > -1) { Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content ); } else { handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } } } public void Stop() { IsListening = false; ear.Close(); } 

There is no exception now. Hope this helps someone else!

+9
source

Source: https://habr.com/ru/post/955445/


All Articles