一、概述

UDP和TCP是网络通讯常用的两个传输协议,C#一般可以通过Socket来实现UDP和TCP通讯,由于.NET框架通过UdpClient、TcpListener 、TcpClient这几个类对Socket进行了封装,使其使用更加方便, 本文就通过这几个封装过的类讲解一下相关应用。

二、UDP基本应用

与TCP通信不同,UDP通信是不分服务端和客户端的,通信双方是对等的。为了描述方便,我们把通信双方称为发送方和接收方。

发送方:

首先创建一个UDP对象:

            string locateIP = "127.0.0.1";    //本机IP

            int locatePort = ;            //发送端口

            IPAddress locateIpAddr = IPAddress.Parse(locateIP);

            IPEndPoint locatePoint = new IPEndPoint(locateIpAddr, locatePort);

            UdpClient  udpClient = new UdpClient(locatePoint);

发送数据:

            string remoteIP = "127.0.0.1";             //目标机器IP

            int remotePort = ;                     //接收端口          

            IPAddress remoteIpAddr = IPAddress.Parse(remoteIP);

            IPEndPoint remotePoint = new IPEndPoint(remoteIpAddr, remotePort);

            byte[] buffer = Encoding.UTF8.GetBytes(“hello”);

            udpClient.Send(buffer, buffer.Length, remotePoint);

以上就完成了一个发送任务,一个较完整的发送代码如下:

    public partial class FormServer : Form
{
private UdpClient udpClient = null; private void btnConnect_Click(object sender, EventArgs e)
{
string locateIP = "127.0.0.1";
int locatePort = ;
IPAddress locateIpAddr = IPAddress.Parse(locateIP);
IPEndPoint locatePoint = new IPEndPoint(locateIpAddr, locatePort);
udpClient = new UdpClient(locatePoint); this.groupWork.Enabled = true;
} private void Send_Click(object sender, EventArgs e)
{
string text = this.txtSend.Text.Trim();
string remoteIP = "127.0.0.1";
int remotePort = ;
byte[] buffer = Encoding.UTF8.GetBytes(text); if (udpClient != null)
{
IPAddress remoteIp = IPAddress.Parse(remoteIP);
IPEndPoint remotePoint = new IPEndPoint(remoteIp, remotePort);
udpClient.Send(buffer, buffer.Length, remotePoint);
} Debug.WriteLine("Send OK");
}
}

接收端:

首先创建一个UDP对象:

            string locateIP = "127.0.0.1";

            int locatePort = ;

            IPAddress locateIpAddr = IPAddress.Parse(locateIP);

            IPEndPoint locatePoint = new IPEndPoint(locateIpAddr, locatePort);

            UdpClient  udpClient = new UdpClient(locatePoint);

接收数据:

    IPEndPoint remotePoint = new IPEndPoint(IPAddress.Parse("1.1.1.1"), );

     var received = udpClient.Receive(ref remotePoint);

     string info = Encoding.UTF8.GetString(received);

     string from=$” {remotePoint.Address}:{remotePoint.Port}”;

注意两点:

1、remotePoint是获得发送方的IP信息,定义时可以输入任何合法的IP和端口信息;

2、Receive方法是阻塞方法,所以需要在新的线程内运行,程序会一直等待接收数据,当接收到一包数据时程序就返回,要持续接收数据需要重复调用Receive方法。

一个较完整的接收端代码如下:

   public partial class FormClent : Form
{
private UdpClient udpClient = null; private void btnConnect_Click(object sender, EventArgs e)
{
string locateIP = "127.0.0.1";
int locatePort = ;
IPAddress locateIpAddr = IPAddress.Parse(locateIP);
IPEndPoint locatePoint = new IPEndPoint(locateIpAddr, locatePort);
udpClient = new UdpClient(locatePoint);
IPEndPoint remotePoint = new IPEndPoint(IPAddress.Parse("1.1.1.1"), ); Task.Run(() =>
{
while (true)
{
if (udpClient != null)
{
var received = udpClient.Receive(ref remotePoint);
string info = Encoding.UTF8.GetString(received);
string from=$” {remotePoint.Address}:{remotePoint.Port}”;
}
}
});
}
}

三、丢包和乱序问题

当发送端发送一包数据时,不管对方是否接收都是发送成功的,UDP协议本身并不会对发送的可靠性进行验证。(这里的可靠性是指是否接收到,如果对方接收到数据包,其内容还是可靠的,这个在链路层进行了保证。)同时,由于网络延时等因素,先发送的包并不能确定先被接收到,所以由于这两个原因,UDP通信存在丢包和乱序的情况。

某些业务场景下,比如实时状态监控,可能对丢包和乱序情况并不敏感, 可以不用处理,但大部分情况下还是介意丢包的,简单的处理办法就是把包的头部固定长度的空间拿出来存放核对信息,比如包编号,如果有缺失,可以要求发送方重发,也可以进行排序。

四、将数据接收包装为事件

我们对UdpClent又进行一次封装,启用一个线程进行接收数据,将接收到的数据包通过事件发布出来,这样使用起来就更方便了。

namespace Communication.UDPClient
{
public class UdpStateEventArgs : EventArgs
{
public IPEndPoint remoteEndPoint;
public byte[] buffer = null;
} public delegate void UDPReceivedEventHandler(UdpStateEventArgs args); public class UDPClient
{
private UdpClient udpClient;
public event UDPReceivedEventHandler UDPMessageReceived; public UDPClient(string locateIP, int locatePort)
{
IPAddress locateIp = IPAddress.Parse(locateIP);
IPEndPoint locatePoint = new IPEndPoint(locateIp, locatePort);
udpClient = new UdpClient(locatePoint); //监听创建好后,创建一个线程,开始接收信息
Task.Run(() =>
{
while (true)
{
UdpStateEventArgs udpReceiveState = new UdpStateEventArgs(); if (udpClient != null)
{
IPEndPoint remotePoint = new IPEndPoint(IPAddress.Parse("1.1.1.1"), );
var received = udpClient.Receive(ref remotePoint);
udpReceiveState.remoteEndPoint = remotePoint;
udpReceiveState.buffer = received;
UDPMessageReceived?.Invoke(udpReceiveState);
}
else
{
break;
}
}
});
}
}
}

具体使用办法:

        private void btnConnect_Click(object sender, EventArgs e)
{
string locateIP = "127.0.0.1";
int locatePort = ;
UDPClient udpClient = new UDPClient(locateIP, locatePort);
udpClient.UDPMessageReceived += UdpClient_UDPMessageReceived;
} private void UdpClient_UDPMessageReceived(UdpStateEventArgs args)
{
var remotePoint = args.remoteEndPoint;
string info = Encoding.UTF8.GetString(args.buffer);
}

限于篇幅,我们只封装了数据接收,时间使用时需要把发送功能也封装进去,使这个类同时具备发送和接收功能,发送功能的封装比较简单就不贴代码了。

传送门:

C#网络编程入门系列包括三篇文章:

(一)C#网络编程入门之UDP

(二)C#网络编程入门之TCP

(三)C#网络编程入门之HTTP

C#网络编程入门之UDP的更多相关文章

  1. C#网络编程入门之TCP

    目录: C#网络编程入门系列包括三篇文章: (一)C#网络编程入门之UDP (二)C#网络编程入门之TCP (三)C#网络编程入门之HTTP 一.概述 UDP和TCP是网络通讯常用的两个传输协议,C# ...

  2. 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

    本文引用了“帅地”发表于公众号苦逼的码农的技术分享. 1.引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢 ...

  3. 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

    本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言   老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...

  4. 脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

    本文原作者阮一峰,作者博客:ruanyifeng.com. 1.前言 新一代HTTP/2 协议的主要目的是为了提高网页性能(有关HTTP/2的介绍,请见<从HTTP/0.9到HTTP/2:一文读 ...

  5. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...

  6. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  7. 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

    .引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...

  8. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

  9. [转帖]脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

    脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手   http://www.52im.net/thread-1729-1-1.html     1.引言 网络编程中TCP协议的三次握手和 ...

随机推荐

  1. 家用PC机打造VSphere5.1 测试环境:之部署VCenter Server 5.1

    家用PC机打造VSphere5.1 测试环境前言:实践出真知,同样学习VMware VSphere 的朋友,也需要不断的测试总结,再测试再总结只有不断的积累才能学好,但是动辄几万的服务器不是所有朋友都 ...

  2. KMP+Tire树(模板)

    \(\color{Red}{KMP板子}\) #include <bits/stdc++.h> using namespace std; const int maxn=1e6+9; int ...

  3. 步入LTE、多址技术

    LTE系统的主要性能和目标 与3G相比,LTE主要性能特性: 带宽灵活配置:支持1.4MHz, 3MHz, 5MHz, 10Mhz, 15Mhz, 20MHz 峰值速率(20MHz带宽):下行100M ...

  4. Spring Cloud学习 之 Spring Cloud Ribbon(负载均衡器源码分析)

    文章目录 AbstractLoadBalancer: BaseLoadBalancer: DynamicServerListLoadBalancer: ServerList: ServerListUp ...

  5. mac下xampp使用phpmyadmin搭建后台

    情景 使用xampp搭建一个后端环境,前提已经有后端和数据库配置文件 安装和启动xampp 安装xampp没什么可说的,在https://www.apachefriends.org/index.htm ...

  6. 【T-SQL】基础 —— 语法(1)

    USE master--检查是否已经存在一个表,如果有就删除IF(EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ' ...

  7. [hdu5199]统计数据的水题

    题意:统计一个数出现了多少次,统计后删去它所有的出现.思路:乱搞..自己没事写的hash,不过赶脚效率有点低. #pragma comment(linker, "/STACK:1024000 ...

  8. [带符号大整数模板]vector版

    #include <iostream> #include <cstdio> #include <vector> #include <cstring> u ...

  9. Office 2016 英文版(VOL版)下载

    Office 2016 英文版(大客户版)下载磁力链接: 1.专业版(含project.visio) ProPlus, Project Pro, Visio Pro (x86-x64) magnet: ...

  10. Linux系统如何安装qt-desinger

    前言:最近想在python3.7.3下玩下PyQt5,写UI有两种方式一种是使用手写,第二个就是使用Qt Designer工具来写,所以首先就是安装PyQt5和pyqt5-tools工具了. 一.安装 ...