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

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

 

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

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

    Broadcast属性对应的 SocketOptionLevelSocket

  则调用为

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

相关文章: