I'm working on a basic socket server in C# that needs to run as part of a Windows Forms application. I started with the asynchronous socket server code from MSDN . Like many socket server code samples, this one is a console mode application. Here's a sample of the StartListening() method that gets called from Main():
public static void StartListening()
{
// data buffer for incoming data
byte[] bytes = new byte[1024];
IPAddress ipAddress = IPAddress.Parse(serverIpAddress);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, portNumber);
// create TCP/IP socket
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// bind socket to the local endpoint and listen for incoming connections
try
{
serverSocket.Bind(localEndPoint);
serverSocket.Listen(100);
while (true)
{
// set the allDone ManualResetEvent to nonsignaled state
allDone.Reset();
// start an asynchronous socket to listen for connections
Console.WriteLine("Waiting for a connection...");
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
// wait until a connection is made before continuing
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
As you can see, there's a while(true) loop in there which uses a ManualResetEvent to wait until a client connection is established before entering the next iteration of the while loop. I'm not sure why they included the Console.WriteLine(\\n"Press ENTER to continue...")
statement since there's no way to break out of the while(true) loop.
Anyway, in thinking about converting this into a WinForms application, I would obviously need to run the server on another thread but when the user closes my application, I want to make sure that the socket server gets shutdown "properly". My best guess at what that means is closing any open client connections, breaking out of the listening loop and then shutting down the server socket (not necessarily in that order).
I've seen some suggestions that recommend just making the server thread a background thread and letting it get destroyed when the application is shutdown but that doesn't seem very "clean". If, for example, a client is connected and sending data when the application is closed, what does that do to the client? Can anyone suggest a "best practice" with regard to shutting down a socket server properly?
I would wrap that entire thing in a Task and use a cancellation token.
See https://msdn.microsoft.com/en-us/library/hh160373(v=vs.110).aspx for a good example on using tasks and cancellation tokens. You can make the cancellation token cancel the task when you want to shut down the socket server.
Inside the task an exception is raised. In the exception handler you call Socket.Close which will stop the BeginAccept call (EndAccept will be called but the Socket.Handle will be -1).
Actually you don't need a thread, cause you're already listening asynchronously.
Just call serverSocket.BeginAccept
again at the end of AcceptCallback
. Then the shutdown of your server reduces to serverSocket.Close()
(obviously, serverSocket
needs to be a class field).
Finally, in AcceptCallback
you would need to catch the exception of EndAccept
. That, btw, is the reason, why there's Console.Writeline
and Console.Readkey
in the example: it's executed when an exception occurs.
This block: Console.WriteLine("\\nPress ENTER to continue..."); Console.Read(); is there because the way this method is written it will exit the loop if an exception is thrown.
I would write it like this to fit your parameters:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { private Socket serverSocket; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { StartListening(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { serverSocket.Close(); } public void StartListening() { byte[] bytes = new byte[1024]; IPAddress ipAddress = IPAddress.Parse(serverIpAddress); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, portNumber); serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { serverSocket.Bind(localEndPoint); serverSocket.Listen(100); while(true) { allDone.Reset(); Console.WriteLine("Waiting for a connection..."); serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket); // wait until a connection is made before continuing allDone.WaitOne(); } } catch(Exception e) { Console.WriteLine(e.ToString()); } finally { serverSocket.Close(); } Console.WriteLine("\\nPress ENTER to continue..."); Console.Read(); } } }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.