我正在使用C#中的基本套接字服务器,它需要作为Windows窗体应用程序的一部分运行。我从MSDN开始使用异步套接字服务器代码。与许多套接字服务器代码示例一样,这是一个控制台模式应用程序。这是从Main()调用的StartListening()方法的示例:
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();
}
正如您所看到的,那里有一个while(true)循环,它使用ManualResetEvent等待,直到建立客户端连接,然后才进入while循环的下一次迭代。我不确定他们为什么包含Console.WriteLine(\n"Press ENTER to continue...")
语句,因为没有办法摆脱while(true)循环。
无论如何,在考虑将其转换为WinForms应用程序时,我显然需要在另一个线程上运行服务器,但是当用户关闭我的应用程序时,我想确保套接字服务器关闭"正确& #34 ;.我最好的猜测是什么意思是关闭任何打开的客户端连接,打破监听循环,然后关闭服务器套接字(不一定按顺序)。
我已经看到一些建议,建议只是让服务器线程成为后台线程,并在应用程序关闭时让它被销毁,但这看起来不是很干净"。例如,如果客户端已连接并在应用程序关闭时发送数据,那么这对客户端有何影响?任何人都可以建议一个最佳实践"关于正确关闭套接字服务器?
答案 0 :(得分:1)
我会将整个事情包装在一个Task中并使用取消令牌。
有关使用任务和取消令牌的好例子,请参阅https://msdn.microsoft.com/en-us/library/hh160373(v=vs.110).aspx。当您要关闭套接字服务器时,可以使取消令牌取消该任务。
在任务内部引发异常。在异常处理程序中,您调用Socket.Close将停止BeginAccept调用(将调用EndAccept,但Socket.Handle将为-1)。
答案 1 :(得分:1)
实际上你不需要线程,因为你已经异步监听了。
只需在serverSocket.BeginAccept
结束时再次致电AcceptCallback
。
然后关闭服务器的时间减少到serverSocket.Close()
(显然,serverSocket
必须是类字段。)
最后,在AcceptCallback
中,您需要捕获EndAccept
的例外情况。那个,顺便说一句,原因是,为什么示例中有Console.Writeline
和Console.Readkey
:它在异常发生时执行。
答案 2 :(得分:1)
此块: Console.WriteLine(" \ n按ENTER继续......"); Console.Read(); 是因为编写此方法的方式,如果抛出异常,它将退出循环。
我会这样写它以适合您的参数:
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();
}
}
}