三颗纽扣

世界上最宽广的是海洋,比海洋更宽广的是天空,比天空更宽广的是人的胸怀

导航

UDP 广播通信应用的一些摘要

做了一个简单的多机屏幕查看程序,摘录其中一些简单代码。

 

 获取本机 IP 地址

string hostName = Dns.GetHostName();   //得到本机的主机名
var localIpAddressList = Dns.GetHostEntry(hostName).AddressList; //取得本机IP
_localIp = localIpAddressList[0];

 

 

UDP 广播地址的计算

 

255.255.255.255是全局广播地址,虽然这个地址也能用来广播,但是在多网卡情况下不能很好的绑定到特定网卡上,对特定网卡,计算它的广播地址应该是网卡对应的 掩码取反,然后和 IP 地址求 OR.

 

没有标题的FORM, 只需要将 Form 的 min, max, control box 去掉,标题设为空即可,要在这种FORM上,按下鼠标能够拖动窗口,有好几种方法,个人觉得最好的是以下这种:

代码
const int WM_NCLBUTTONDOWN = 0x00A1;
//const int WM_NCHITTEST = 0x84;
const int HT_CAPTION = 0x2;
//const int HT_CLIENT = 0x1;

if (e.Button == MouseButtons.Left)
{
    Capture 
= false;
    Message msg 
= Message.Create(Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
    WndProc(
ref msg);
}

 

 

关于UPD通信的可靠性,和数据包的大小密切相关,在设置了UDP DontFragment = flase 参数后,由于允许对UDP包进行IP分片,因此理论上可以发送任意大小的UDP包,但是一般的 MTU 大小都只有 14xx 字节,因此超过 MTU 大小的 UDP包将被分片传输,这将导致丢包率上升,用PNG格式传输屏幕截图,大小一般在10K左右,有时候会连续10来个包丢失的。修改为只发送心跳广播信号(1字节),图片另外通过TCP通道传输,速度其实也不慢,一个远程调用,执行时间在0.1秒左右。

 

DotNet 远程调用在很多情况下可同样起到网络传输的效果,没有特别要求时,完全可以使用远程调用来代替网络编程。

 

远程调用的服务端注册代码:

代码
var channel = new TcpChannel(Port);
ChannelServices.RegisterChannel(channel, 
false);
            
RemotingConfiguration.ApplicationName 
= ServiceName;

WellKnownServiceTypeEntry WKSTE 
= new WellKnownServiceTypeEntry(typeof(RemotePanel), ServiceName, WellKnownObjectMode.SingleCall);
RemotingConfiguration.RegisterWellKnownServiceType(WKSTE);
            
RemotingConfiguration.CustomErrorsEnabled(
false);
RemotingConfiguration.CustomErrorsMode 
= CustomErrorsModes.Off;

 

 

采用 WellKnownServiceTypeEntry 方式注册,则客户端可不必进行注册,直接使用 getObject 即可获取远程对象。

代码
var url = String.Format("tcp://{0}:{1}/{2}", remoteIp, Port, ServiceName);

RemotePanel obj 
= null;

try
{
    obj 
= (RemotePanel) Activator.GetObject(typeof(RemotePanel), url);
}
catch (Exception e)
{
    Program.Log(
null, e.ToString());
}

return obj;

 

 

创建远程对象或调用远程方法的时候,如果出现网络故障,或者远程程序已退出,则会发生异常,特别如果远程程序未启动,则调用线程将被Block 较长的时间后才发出连接失败的异常,这个调用如果出现在有界面的程序中会照成程序假死的现象,简单的解决办法是让远程程序通过 UDP 广播心跳,客户端收到心跳后立即进行远程调用。

 

在多线程程序中,如果在一个线程中访问另一个线程创建的 Form,则将引发异常,最简单的解决方法是在访问代码中检测是否从另一线程访问,通过委托句柄进行访问,例如以下在窗口显示日志信息的代码,日志可能从其他线程发生过来:

代码
delegate void LogCallBack(object sender, String msg);

/// <summary>
/// Logs the specified MSG.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="msg">The MSG.</param>
private void log(object sender, String msg)
{
    TextBox textBox;

    
if (sender is Client)
    {
        textBox 
= txtLog2;
    }
    
else
    {
        textBox 
= txtLog;
    }

    
if (textBox.InvokeRequired)
    {
        LogCallBack d 
= log;
        Invoke(d, 
new[] {sender, msg });
        
return;
    }

    
if (textBox.TextLength > 60000)
    {
        textBox.Text 
= textBox.Text.Substring(30000);
    }

    textBox.AppendText(DateTime.Now.ToShortTimeString());
    textBox.AppendText(
"-");
    textBox.AppendText(msg);
    textBox.AppendText(
"\r\n");
}

 

 

posted on 2009-12-21 09:31  三颗纽扣  阅读(636)  评论(0编辑  收藏  举报