我正在尝试开发一个多播接收器程序,并完成了套接字初始化,如下所示:
public void initializeThread()
{
statuscheckthread = new Thread(SetSocketOptions);
statuscheckthread.IsBackground = true;
}
private void Form1_Load(object sender, EventArgs e)
{
rxsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Any, 9191);
rxsock.Bind(iep);
ep = (EndPoint)iep;
initializeThread();
statuscheckthread.Start();
}
public void SetSocketOptions()
{
initializeThread(); //re-initializes thread thus making it not alive
while (true)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
bool sockOptnSet = false;
while (!sockOptnSet)
{
try
{
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.50.50.50")));
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 64);
sockOptnSet = true;
}
catch
{
//Catch exception here
}
}
}
break; // Break out from loop once socket options are set
}
}
当我的PC没有连接到网络时,SetSocketOption方法抛出异常甚至连网络后, 我无法接收数据,因为未设置套接字选项。
为了避免这种情况,我使用了一个在后台检查中运行的线程 对于网络可用性,一旦网络可用,它就会设置套接字选项。
它适用于某些PC,但在其他一些PC中,NetworkInterface.GetIsNetworkAvailable()
在网络连接之前返回true
(正在确定网络)。
因此,为了确保设置Socket选项,我使用了bool
变量sockOptnSet
设为的
true
如果try块中的所有语句都按照方法中显示的方式执行public void SetSocketOptions()
这个程序在我试过的所有PC上运行良好,但我怀疑我可以依赖它来工作多少。
我的问题是:
1)这是一个好习惯吗?
2)如果没有,它可能导致的错误或问题是什么?我怎样才能以更好的方式实现它?
答案 0 :(得分:4)
这是一个好习惯吗?
不,不是一个好习惯。绝大多数例外情况(包括您的第一个例外)都属于烦恼例外。软件应该工作,在测试时运行良好,但不在用户的机器上运行。出了点问题,但是你不知道什么,并且没有任何有意义的事情你能做些什么。试图保持你的程序运行是没用的,它不能完成应该做的工作。在您的情况下,没有希望套接字在没有网络时会接收数据。而且,正如您所发现的那样,尝试解决问题只会引发更多问题。这很正常。
如果这是不好的做法,我该如何以更好的方式实施呢?
你需要人类的帮助。用户将不得不设置机器以提供有效的网络连接。这需要一个用户界面,你必须有办法告诉人类他需要做些什么来解决你的问题。你可以根据自己的意愿将其变得复杂或简单。只是一条错误消息,Exception.Message的逐字副本就足够了。为AppDomain.CurrentDomain.UnhandledException事件编写事件处理程序是一个非常好(和必需)的策略。 Microsoft花费了大量精力使异常消息尽可能清晰且有用,甚至以用户的母语为您本地化,您希望利用它。即使异常消息令人费解,对消息文本的快速Google查询也会返回数百次点击。有了这个事件处理程序,您就不必执行任何特殊操作。您的程序会自动终止,并且您的用户知道如何处理它。
你当然可以使它更复杂,你发现SetSocketOption()在网络可用后很可能会失败,但是当你等待足够长时间时就会工作。所以这实际上是一个错误的条件,你可以解决,只需等待足够长的时间。是否应该编写代码来处理这个问题是你必须自己决定的。当你对程序的行为方式有足够的经验时,这是你写的东西,你从来没有预先写过。通常是来自您的计划用户的反馈。
答案 1 :(得分:3)
评论中的一些好建议,让我们“扩展它。”
首先,我将所有这些套接字代码放在其自己的类中,在表单之外。这使它成为'自己的实体,在语义上更容易理解。此类可以具有属性Initialised
,该属性最初设置为false
。您在表单中执行的第一件事是在此类上调用Initialise
方法,该方法尝试设置套接字选项并在网络不可用时捕获相关的异常。如果 可用,我们会将Initialised
属性设置为true
。
如果不可用,我们设置一个超时(参见System.Threading.Timer
),在'x'秒后调用此相同的函数(可能带有重试计数)。我们再一次发现自己回到了这个Initialise
函数中,可能还有一个开头提到的重试计数。再一次,如果它可用,我们很好 - 如果没有,再次设置计时器。最后,在'x'重试后如果我们没有初始化,我们可以抛出异常或设置一些其他失败属性来表明我们无法继续。
您的Form
类可以定期检查(或挂钩事件)以确定套接字现在是否已准备好进行通信。如果失败你可以优雅地退出,或者因为我们的课程很好并且抽象,试图再次启动整个过程。