zoukankan      html  css  js  c++  java
  • 【笔记】组播的使用

      UDP相对于TCP来说,虽然是无连接,不可靠传输,但是可以实现组播,可以同时给多个主机发送数据,比如聊天室之类的应用,如果为每个用户之间都建立一个Tcp连接,而且每次发送的数据又是相同的,这样做使得程序开销大,而且占用内存多,Udp还有一个广播的服务,但是广播不能筛选,也就是说广播会向所有在同一子网的主机发送数据,这样无疑也增加了网络负担,这时就可以通过Udp的组播来实现,最近一直在摸索中,下面对做一下组播的总解

      组播的地址采用D类IP地址,范围是从 224.0.0.0239.255.255.255,下面有几个保留地址,一般不作为用户使用的地址

        224.0.0.1 - 该子网上的所有主机。

        224.0.0.2 - 该子网上的所有路由器。

        224.0.0.5 - 开放最短路径优先(Open Shortest Path First,OSPF)算法第2版,设计用于到达某个网络上的所有OSPF路由器。

        224.0.0.6 - 开放最短路径优先算法第2版,设计用于到达某个网络上的所有OSPF指定的路由器。

        224.0.0.9 - 路由信息协议(Routing Information Protocol,RIP)第2版。

        224.0.1.1 - 网络时间协议(Network Time Protocol)。

        过多详细介绍见百度百科  http://baike.baidu.com/view/1871353.htm

      对组播的使用:创建套接字,绑定本地地址,加入组播,监听组播信息

    1、首先定义一个套接字状态信息,用于异步时保存信息

            public class StateObject
            {
                public Socket sock;
                public byte[] buffer = new byte[1024];
                public EndPoint endpoint;
                public StateObject(Socket sock, EndPoint endpoint)
                {
                    this.sock = sock;
                    this.endpoint = endpoint;
                }
            }

    2、创建套接字,绑定本地地址,加入组播,监听组播信息

            private static IPAddress mcastAddress;
            private static int mcastPort;
            private static Socket mcastSocket; 
            private static MulticastOption mcastOption;
    
            private void btnJoin_Click(object sender, EventArgs e)
            {
                //组播地址和端口
                mcastAddress = IPAddress.Parse("224.168.100.2");
                mcastPort = 8000;
                try
                {
                    //组播套接字,绑定本地地址(组播端口)
                    mcastSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(tbLocalIP.Text), mcastPort);
                    mcastSocket.Bind(localEP);
    
                    //加入组播
                    mcastOption = new MulticastOption(mcastAddress, IPAddress.Parse(tbLocalIP.Text));
                    mcastSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);
    
                    //开始接收信息
                    byte[] bytes = new Byte[1024];
                    EndPoint remoteEP = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
                    StateObject so = new StateObject(mcastSocket, remoteEP);
                    mcastSocket.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None, ref so.endpoint, ReceiveFromCallback, so);
                }
                catch (Exception) 
                {
                }
            }
            private void ReceiveFromCallback(IAsyncResult ar)
            {
                StateObject so = ar.AsyncState as StateObject;
                try
                {
                    int length = so.sock.EndReceiveFrom(ar, ref so.endpoint);
                    string recvstr = System.Text.Encoding.UTF8.GetString(so.buffer, 0, length);
                    MessageBox.Show(recvstr);
                    //继续接收消息
                    so.sock.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None, ref so.endpoint, ReceiveFromCallback, so);
                }
                catch (SocketException)
                {
                    //连接断开
                }
                catch (ObjectDisposedException)
                {
                    //套接字关闭
                }
            }

    3、向组播发送信息,只要加入了该多播组的成员都能收到该信息

            private void btnSendMsg_Click(object sender, EventArgs e)
            {
                try
                {
                    IPEndPoint endPoint = new IPEndPoint(mcastAddress, mcastPort);
                    mcastSocket.SendTo(System.Text.Encoding.UTF8.GetBytes("你好"), endPoint);
                }
                catch (SocketException)
                {
                    //连接断开
                }
                catch (ObjectDisposedException)
                {
                    //套接字关闭
                }
            }

     4、最后说下套接字属性的设置问题,也就是SetSocketOption函数

      该函数有四个重载,分别设置不同属性,具体属性定义在MSDN上有

         http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.setsocketoption(v=VS.80).aspx    

        Socket.SetSocketOption (SocketOptionLevel, SocketOptionName, Boolean) 将指定的 Socket 选项设置为指定的 Boolean 值。
        Socket.SetSocketOption (SocketOptionLevel, SocketOptionName, Byte[]) 将指定的 Socket 选项设置为指定的值,表示为字节数组。
        Socket.SetSocketOption (SocketOptionLevel, SocketOptionName, Int32) 将指定的 Socket 选项设置为指定的整数值。
        Socket.SetSocketOption (SocketOptionLevel, SocketOptionName, Object) 将指定的 Socket 选项设置为指定值,表示为对象。

    具体属性说明,具体属性对于的SocketOptionLevel可以查看上面地址,不同的函数对于的设置又不一样

    http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketoptionname(v=vs.80).aspx

     成员名称说明
    由 .NET Compact Framework 支持 AcceptConnection 套接字正在侦听。 
    由 .NET Compact Framework 支持 AddMembership 添加一个 IP 组成员。 
    由 .NET Compact Framework 支持 AddSourceMembership 联接源组。 
    由 .NET Compact Framework 支持 BlockSource 阻止源中的数据。 
    由 .NET Compact Framework 支持 Broadcast 允许在套接字上发送广播消息。 
    由 .NET Compact Framework 支持 BsdUrgent 使用 RFC-1222 中定义的紧急数据。此选项只能设置一次,而且设置以后就不能关闭。 
    由 .NET Compact Framework 支持 ChecksumCoverage 设置或获取 UDP 校验和覆盖。 
    由 .NET Compact Framework 支持 Debug 记录调试信息。 
    由 .NET Compact Framework 支持 DontFragment 不对 IP 数据报进行分段。 
    由 .NET Compact Framework 支持 DontLinger 完全关闭套接字,不做逗留。 
    由 .NET Compact Framework 支持 DontRoute 不路由,将数据包直接发送到接口地址。 
    由 .NET Compact Framework 支持 DropMembership 放置一个 IP 组成员。 
    由 .NET Compact Framework 支持 DropSourceMembership 放置一个源组。 
    由 .NET Compact Framework 支持 Error 获取错误状态并清除。 
    由 .NET Compact Framework 支持 ExclusiveAddressUse 使套接字能够为独占访问进行绑定。 
    由 .NET Compact Framework 支持 Expedited 使用 RFC-1222 中定义的加急数据。此选项只能设置一次,而且设置以后就无法关闭。 
    由 .NET Compact Framework 支持 HeaderIncluded 指示应用程序为输出数据报提供 IP 头。 
      HopLimit 指定 Internet 协议版本 6 (IPv6) 数据包的最大路由器跃点数目。这类似于 Internet 协议版本 4 的生存时间 (TTL)。 
    由 .NET Compact Framework 支持 IPOptions 指定要插入到输出数据报中的 IP 选项。 
    由 .NET Compact Framework 支持 IpTimeToLive 设置 IP 头生存时间字段。 
    由 .NET Compact Framework 支持 KeepAlive 使用 keep-alive。 
    由 .NET Compact Framework 支持 Linger 如果存在未发送的数据,则在关闭时逗留。 
    由 .NET Compact Framework 支持 MaxConnections 不受支持;如果使用,将引发 SocketException。 
    由 .NET Compact Framework 支持 MulticastInterface 为输出的多路广播数据包设置接口。 
    由 .NET Compact Framework 支持 MulticastLoopback IP 多路广播环回。 
    由 .NET Compact Framework 支持 MulticastTimeToLive IP 多路广播生存时间。 
    由 .NET Compact Framework 支持 NoChecksum 发送校验和设置为零的 UDP 数据报。 
    由 .NET Compact Framework 支持 NoDelay 为发送合并禁用 Nagle 算法。 
    由 .NET Compact Framework 支持 OutOfBandInline 接收正常数据流中的带外数据。 
    由 .NET Compact Framework 支持 PacketInformation 返回有关接收到的数据包的信息。 
    由 .NET Compact Framework 支持 ReceiveBuffer 指定为接收保留的每个套接字缓冲区空间的总量。这与最大消息大小或 TCP 窗口的大小无关。 
    由 .NET Compact Framework 支持 ReceiveLowWater 为 Receive 操作指定低水印。 
    由 .NET Compact Framework 支持 ReceiveTimeout 接收超时。此选项只适用于同步方法,它对异步方法(如 BeginSend 方法)无效。 
    由 .NET Compact Framework 支持 ReuseAddress 允许将套接字绑定到已在使用中的地址。 
    由 .NET Compact Framework 支持 SendBuffer 指定为发送保留的每个套接字缓冲区空间的总量。这与最大消息大小或 TCP 窗口的大小无关。 
    由 .NET Compact Framework 支持 SendLowWater 为 Send 操作指定低水印。 
    由 .NET Compact Framework 支持 SendTimeout 发送超时。此选项只适用于同步方法,它对异步方法(如 BeginSend 方法)无效。 
    由 .NET Compact Framework 支持 Type 获取套接字类型。 
    由 .NET Compact Framework 支持 TypeOfService 更改服务字段的 IP 头类型。 
    由 .NET Compact Framework 支持 UnblockSource 取消阻止先前被阻止的源。 
      UpdateAcceptContext 使用现有套接字的属性更新已接受套接字的属性。这等效于使用 Winsock2 SO_UPDATE_ACCEPT_CONTEXT 套接字选项,并且仅在面向连接的套接字上受支持。 
      UpdateConnectContext 使用现有套接字的属性更新已连接套接字的属性。这等效于使用 Winsock2 SO_UPDATE_CONNECT_CONTEXT 套接字选项,并且仅在面向连接的套接字上受支持。 
    由 .NET Compact Framework 支持 UseLoopback 可能时避开硬件。 
     

    例如在使用Udp广播数据的时候,需要设置Broadcast属性为true

      在函数 Socket.SetSocketOption (SocketOptionLevel, SocketOptionName, Boolean)

        Broadcast属性对应的 SocketOptionLevelSocket

      则调用为

        sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);

  • 相关阅读:
    信号量整理
    Linux下串口配置初步探寻
    Vmware启动ubuntu 出现错误。
    软件工程结课作业
    第四次博客作业-结对项目
    20194731 软件工程第三次作业——博文软件质量保障初探
    20194731 第一次作业-博客初体验
    20194731 自动生成四则运算题第一版报告
    误删除 mySQL 用户解决办法
    mySQL的安装过程---二进制和源码安装
  • 原文地址:https://www.cnblogs.com/bomo/p/2868576.html
Copyright © 2011-2022 走看看