基于C#的UDP协议的同步实现

一、摘要

   总结基于C#的UDP协议的同步通信。

 

二、实验平台

   Visual Studio 2010

 

三、实验原理

   UDP传输协议同TCP传输协议的区别可查阅相关文档,此处不再赘述。

 

四、实例

 4.1 采用socket实现UDP

  由于UDP是一种无连接的协议。因此,为了使服务器应用能够发送和接收UDP数据包,则需要做两件事情:
(1) 创建一个Socket对象;
(2) 将创建的套接字对象与本地IPEndPoint进行绑定。
  完成上述步骤后,那么创建的套接字就能够在IPEndPoint上接收流入的UDP数据包,或者将流出的UDP数据包发送到网络中
其他任意设备。使用UDP进行通信时,不需要连接。因为异地的主机之间没有建立连接,所以UDP不能使用标准的Send()和Receive()t套接字方法,而是使用两个其他的方法:SendTo()和ReceiveFrom()。

    SendTo()方法指定要发送的数据,和目标机器的IPEndPoint。该方法有多种不同的使用方法,可以根据具体的应用进行选择,但是至少要指定数据包和目标机器。如下:
    SendTo(byte[] data,EndPoint Remote)
    ReceiveFrom()方法同SendTo()方法类似,但是使用EndPoint对象声明的方式不一样。利用ref修饰,传递的不是一个EndPoint对象,而是将参数传递给一个EndPoint对象。

 

  UDP应用不是严格意义上的真正的服务器和客户机,而是平等的关系,即没有主与次的关系。为了简便起见,仍然把下面的这个应用叫做UDP服务器。

  服务器端代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDP
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data = new byte[1024];

            //得到本机IP,设置TCP端口号         
            IPEndPoint ip = new IPEndPoint(IPAddress.Any, 8001);
            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //绑定网络地址
            newsock.Bind(ip);

            Console.WriteLine("This is a Server, host name is {0}", Dns.GetHostName());

            //等待客户机连接
            Console.WriteLine("Waiting for a client");

            //得到客户机IP
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)(sender);
            recv = newsock.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

            //客户机连接成功后,发送信息
            string welcome = "你好 ! ";

            //字符串与字节数组相互转换
            data = Encoding.ASCII.GetBytes(welcome);

            //发送信息
            newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
            while (true)
            {
                data = new byte[1024];
                //发送接收信息
                recv = newsock.ReceiveFrom(data, ref Remote);
                Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
                newsock.SendTo(data, recv, SocketFlags.None, Remote);
            }
        }

    }
}

  对于接收流入的UDP服务器程序来说,必须将程序与本地系统中指定的UDP端口进行绑定。这就可以通过使用合适的本地IP地址创建一个IPEndPoint对象,以及合适的UDP端口号。上述范例程序中的UDP服务器能够在端口8001从网络上接收任意流入的UDP数据包。

 

  UDP客户机程序与服务器程序非常类似。
  因为客户机不需要在指定的UDP端口等待流入的数据,因此,不使用Bind()方法,而是使用在数据发送时系统随机指定的一个UDP端口,而且使用同一个端口接收返回的消息。在开发产品时,要为客户机指定一套UDP端口,以便服务器和客户机程序使用相同的端口号。UDP客户机程序首先定义一个IPEndPoint,UDP服务器将发送数据包到这个IPEndPoint。如果在远程设备上运行UDP服务器程序,在IPEndPoint定义中必须输入适当的IP地址和UDP端口号信息。

  客户端代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPClient
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
            string input, stringData;

            //构建TCP 服务器
            Console.WriteLine("This is a Client, host name is {0}", Dns.GetHostName());

            //设置服务IP,设置TCP端口号
            IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8001);

            //定义网络类型,数据连接类型和网络协议UDP
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            string welcome = "你好! ";
            data = Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ip);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)sender;

            data = new byte[1024];
            //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制
            int recv = server.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
            while (true)
            {
                input = Console.ReadLine();
                if (input == "exit")
                    break;
                server.SendTo(Encoding.ASCII.GetBytes(input), Remote);
                data = new byte[1024];
                recv = server.ReceiveFrom(data, ref Remote);
                stringData = Encoding.ASCII.GetString(data, 0, recv);
                Console.WriteLine(stringData);
            }
            Console.WriteLine("Stopping Client.");
            server.Close();
        }

    }
}

 

  上述代码的实现逻辑为:相关设置完成后,服务器端先向客户端发送信息,之后客户端通过键盘发送字符串,服务器端收到后再发送给客户端,如此循环。

4.2 采用UDPClient类实现

服务器端代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Custom
{
    // 设置IP,IPV6
    private static readonly IPAddress GroupAddress = IPAddress.Parse("IP地址");
    // 设置端口
    private const int GroupPort = 11000;

    private static void StartListener()
    {
        bool done = false;

        UdpClient listener = new UdpClient();

        IPEndPoint groupEP = new IPEndPoint(GroupAddress, GroupPort);

        try
        {
            //IPV6,组播
            listener.JoinMulticastGroup(GroupAddress);

            listener.Connect(groupEP);

            while (!done)
            {
                Console.WriteLine("Waiting for broadcast");

                byte[] bytes = listener.Receive(ref groupEP);

                Console.WriteLine("Received broadcast from {0} :\n {1}\n", groupEP.ToString(), Encoding.ASCII.GetString(bytes, 0, bytes.Length));
            }

            listener.Close();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

    }

    public static int Main(String[] args)
    {
        StartListener();

        return 0;
    }
}

 

客户端代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Client
{

    private static IPAddress GroupAddress = IPAddress.Parse("IP地址");

    private static int GroupPort = 11000;

    private static void Send(String message)
    {
        UdpClient sender = new UdpClient();

        IPEndPoint groupEP = new IPEndPoint(GroupAddress, GroupPort);

        try
        {
            Console.WriteLine("Sending datagram : {0}", message);

            byte[] bytes = Encoding.ASCII.GetBytes(message);

            sender.Send(bytes, bytes.Length, groupEP);

            sender.Close();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

    }

    public static int Main(String[] args)
    {
        Send(args[0]);

        return 0;
    }
}

 

   以上代码需要说明的是:

(1) 上述代码是基于IPV6地址的组播模式。IPv4中的广播(broadcast)可以导致网络性能的下降甚至广播风暴(broadcast storm)。在IPv6中就不存在广播这一概念了,取而代之的是组播(multicast)和任意播(anycast)。

(2) IPV6地址表示方法:

a) X:X:X:X:X:X:X:X(每个X代表16位的16进制数字),不区分大小写;

b) 排头的0可省略,比如09C0就可以写成9C0,0000可以写成0;

c) 连续为0的字段可以以::来代替,但是整个地址中::只能出现一次,比如FF01:0:0:0:0:0:0:1就可以简写成FF01::1。

(3) 如果是采用窗体的形式建议使用这种格式,否则在接收数据时可能会出现死机的现象。

// 创建一个子线程

            Thread thread = new Thread(
                delegate()
                {
                    try
                    {
                        //在这里写你的代码
                    }
                    catch (Exception )
                    {

                    }
                }
            );

            thread.Start();

 

 

 

 

 


转自:http://www.cnblogs.com/sunev/archive/2012/08/08/2627247
2019-03-02 23:42

知识点

相关教程

更多

C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息

在前面几篇文章中,逐步从原有微信的API封装的基础上过渡到微信应用平台管理系统里面,逐步介绍管理系统中的微信数据的界面设计,以及相关的处理操作过程的逻辑和代码,希望从更高一个层次,向大家介绍微信的应用开发过程。本篇主要介绍在管理系统中,如何实现微信用户分组信息的同步操作。 其实微信能够风风火火的原因,主要就是因为有用户信息,所以同步并管理好微信账号的关注用户数据是非常重要的。有了微信用户的数据,你

用C#捕捉键盘和鼠标

用C#捕捉键盘和鼠标 直接把下面代码copy到VS05编译器中运行. using System ;  using System.Drawing ;  using System.Collections ;  using System.ComponentModel ;  using System.Windows.Forms ;  using System.Data ; public class For

[转] C#开源项目大全

原文地址: http://www.fast818.com/n171.ashx 转自:http://www.cnblogs.com/chaosimple/p/3371004

微信C#响应代码

暂时只把代码贴上来,自己Mark着 1. 从微信GET access_token    string urlGet = @"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx3de0ac694cbc35f1&secret=ab49137d7f8098ec655b5614

微信公众平台的C#实现

using System;  using System.Collections.Generic;  using System.Linq;  using System.Web;  using System.Web.Security;  using System.Xml;  using System.IO;  using System.Text;  namespace School.Web.Frame

C#开发微信公众化平台

C#开发微信公众化平台                             写在前面               服务号和订阅号 URL配置 创建菜单 查询、删除菜单 接受消息 发送消息(图文、菜单事件响应) 示例Demo下载 后记           最近公司在做微信开发,其实就是接口开发,网上找了很多资料,当然园友也写了很多教程,但都是理论说了一大堆,实用指导或代码很少。如果你自己仔细研究

高性能solr c#客户端EasyNet.Solr

EasyNet.Solr(http://easynet.codeplex.com)是由本人开发的 solr(http://lucene.apache.org/solr)c#客户端。它具有以下特性: 1.支持solr 3.1(不兼容solr 1.4.x) 2. 默认支持solr最高效的javabin协议 3.基于接口的序列化和反序列化协议,没有采用反射 4. 可以在架构基础上方便扩展处理solr支持

LeetCode:Word Break(DP)

题目地址:http://oj.leetcode.com/problems/word-break/ 简单的动态规划问题,采用自顶向下的备忘录方法,代码如下:     1 class Solution { 2 public: 3     bool dictContain(unordered_set<string> &dict, string s) 4     { 5

C#中Image.FromFile()的用法

谁能告诉我这个方法的具体用法我是这样写的Image.FromFile("1.jpg");报错。谁能告诉我答案。

【转】C# 中@符号在字符串中的作用

@符号是特殊而又实用的C#符号。 比如它在string中的应用。 1 字符@表示,其后的字符串是个“逐字字符串”(verbatim string)。 // 这个说法来自C# Primer 中文版(Stanley B. Lippman, 侯捷/陈硕合译) 2 对于逐字字符串字面变量(verbatim string literal ),我们不再需要使用“转义序列”就可以指定反斜线之类的特殊字符。@的这

C#开发微信门户及应用(3)--文本消息和图文消息的应答

微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下、学习下微信的相关开发,也就成为计划的安排事情之一了。本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程。 在前面两篇两篇随笔《C#开发微信门户及应用(1)--开始使用微信接口》和《C#开发微信门户及应用(2)--微信消息的处理和应答》里面

C#开发微信公众平台-就这么简单(附Demo)

原文: C#开发微信公众平台-就这么简单(附Demo)  写在前面   服务号和订阅号 URL配置 创建菜单 查询、删除菜单 接受消息 发送消息(图文、菜单事件响应) 示例Demo下载 后记     最近公司在做微信开发,其实就是接口开发,网上找了很多资料,当然园友也写了很多教程,但都是理论说了一大堆,实用指导或代码很少。如果你自己仔细研究下,其实就那么点东西,C#实现起来也很简单,原本不想写这篇

C#开发微信门户及应用(12)-使用语音处理

我们知道,微信最开始就是做语音聊天而使得其更加流行的,因此语音的识别处理自然也就成为微信交流的一个重要途径,微信的开发接口,也提供了对语音的消息请求处理。本文主要介绍如何利用语音的识别,对C#开发的微信门户应用的整个事件链的处理操作,使得在我们的微信账号里面,更加方便和多元化对用户的输入进行处理。 1、微信语音接口的定义0  微信的API这么定义语音的识别的:开通语音识别功能,用户每次发送语音给公

C#开发微信门户及应用(5)--用户分组信息管理

在上个月的对C#开发微信门户及应用做了介绍,写过了几篇的随笔进行分享,由于时间关系,间隔了一段时间没有继续写这个系列的博客了,并不是对这个方面停止了研究,而是继续深入探索这方面的技术,为了更好的应用起来,专心做好底层的技术开发。本篇继续上一篇的介绍,主要介绍分组管理方面的开发应用,这篇的内容和上一篇,作为一个完整的用户信息和分组信息管理的组合。 1、用户分组管理内容  用户分组的引入,主要是方便管

C#开发微信门户及应用(1)--开始使用微信接口

C#开发微信门户及应用(1)--开始使用微信接口       微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下、学习下微信的相关开发,也就成为日常计划的重要事情之一了。本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验总结,希望给大家了解一下相关的开发历程。本随笔主要针对微信开发过程的前期准备和一些初始的工作的介绍。 在写下

最新教程

更多

java线程状态详解(6种)

java线程类为:java.lang.Thread,其实现java.lang.Runnable接口。 线程在运行过程中有6种状态,分别如下: NEW:初始状态,线程被构建,但是还没有调用start()方法 RUNNABLE:运行状态,Java线程将操作系统中的就绪和运行两种状态统称为“运行状态” BLOCK:阻塞状态,表示线程阻塞

redis从库只读设置-redis集群管理

默认情况下redis数据库充当slave角色时是只读的不能进行写操作,如果写入,会提示以下错误:READONLY You can't write against a read only slave.  127.0.0.1:6382> set k3 111  (error) READONLY You can't write against a read only slave. 如果你要开启从库

Netty环境配置

netty是一个java事件驱动的网络通信框架,也就是一个jar包,只要在项目里引用即可。

Netty基于流的传输处理

​在TCP/IP的基于流的传输中,接收的数据被存储到套接字接收缓冲器中。不幸的是,基于流的传输的缓冲器不是分组的队列,而是字节的队列。 这意味着,即使将两个消息作为两个独立的数据包发送,操作系统也不会将它们视为两个消息,而只是一组字节(有点悲剧)。 因此,不能保证读的是您在远程定入的行数据

Netty入门实例-使用POJO代替ByteBuf

使用TIME协议的客户端和服务器示例,让它们使用POJO来代替原来的ByteBuf。

Netty入门实例-时间服务器

Netty中服务器和客户端之间最大的和唯一的区别是使用了不同的Bootstrap和Channel实现

Netty入门实例-编写服务器端程序

channelRead()处理程序方法实现如下

Netty开发环境配置

最新版本的Netty 4.x和JDK 1.6及更高版本

电商平台数据库设计

电商平台数据库表设计:商品分类表、商品信息表、品牌表、商品属性表、商品属性扩展表、规格表、规格扩展表

HttpClient 上传文件

我们使用MultipartEntityBuilder创建一个HttpEntity。 当创建构建器时,添加一个二进制体 - 包含将要上传的文件以及一个文本正文。 接下来,使用RequestBuilder创建一个HTTP请求,并分配先前创建的HttpEntity。

MongoDB常用命令

查看当前使用的数据库    > db    test  切换数据库   > use foobar    switched to db foobar  插入文档    > post={"title":"领悟书生","content":"这是一个分享教程的网站","date":new

快速了解MongoDB【基本概念与体系结构】

什么是MongoDB MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

windows系统安装MongoDB

安装 下载MongoDB的安装包:mongodb-win32-x86_64-2008plus-ssl-3.2.10-signed.msi,按照提示步骤安装即可。 安装完成后,软件会安装在C:\Program Files\MongoDB 目录中 我们要启动的服务程序就是C:\Program Files\MongoDB\Server\3.2\bin目录下的mongod.exe,为了方便我们每次启动,我

Spring boot整合MyBatis-Plus 之二:增删改查

基于上一篇springboot整合MyBatis-Plus之后,实现简单的增删改查 创建实体类 添加表注解TableName和主键注解TableId import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baom

分布式ID生成器【snowflake雪花算法】

基于snowflake雪花算法分布式ID生成器 snowflake雪花算法分布式ID生成器几大特点: 41bit的时间戳可以支持该算法使用到2082年 10bit的工作机器id可以支持1024台机器 序列号支持1毫秒产生4096个自增序列id 整体上按照时间自增排序 整个分布式系统内不会产生ID碰撞 每秒能够产生26万ID左右 Twitter的 Snowflake分布式ID生成器的JAVA实现方案