C# 网络编程之UDP
作者:seabluescn 发布时间:2021-10-02 16:06:40
一、概述
UDP和TCP是网络通讯常用的两个传输协议,C#一般可以通过Socket来实现UDP和TCP通讯,由于.NET框架通过UdpClient、TcpListener 、TcpClient这几个类对Socket进行了封装,使其使用更加方便, 本文就通过这几个封装过的类讲解一下相关应用。
二、UDP基本应用
与TCP通信不同,UDP通信是不分服务端和客户端的,通信双方是对等的。为了描述方便,我们把通信双方称为发送方和接收方。
发送方:
首先创建一个UDP对象:
string locateIP = "127.0.0.1"; //本机IP
int locatePort = 9001; //发送端口
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 = 9002; //接收端口
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 = 9001;
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 = 9002;
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 = 9002;
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"), 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 = 9002;
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"), 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"), 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 = 9002;
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
来源:https://www.cnblogs.com/seabluescn/p/12972417.html
猜你喜欢
- 本文提供了基于MD5加密16位和32位的方法,具体内容如下import java.io.IOException;import java.ma
- 1、数组理论基础数组是存放在连续内存空间上的相同类型数据的集合,可以通过下标索引的方式获取到下标下对应的数据。举个栗子(字符数组)~可以看到
- 本文介绍了详解Maven * Nexus的安装与使用,分享给大家,具体如下:1.安装1.1 安装docker并加速yum update &am
- RPC是远程过程调用的简称,广泛应用在大规模分布式应用中,作用是有助于系统的垂直拆分,使系统更易拓展。Java中的RPC框架比较多,各有特色
- 默认配置默认配置比较低,打开稍大点的项目就很容易卡掉,所以最好扩大一下内存。IntelliJ IDEA的VM配置IntelliJ IDEA2
- Java与C++实现相同的MD5加密算法1、Java版package com.lyz.utils.common;import java.io
- 由于一个线程的程序,如果调用一个功能是阻塞的,那么就会影响到界面的更新,导致使用人员操作不便。所以往往会引入双线程的工作的方式,主线程负责更
- 声明一个客户端对象:protected RedisClient Redis = new RedisClient("127.0.0
- 本文实例为大家分享了Unity Shader序列帧动画效果的具体代码,供大家参考,具体内容如下 实现原理主要的思想是设置显示UV
- 前言古语有云:道为术之灵,术为道之体;以道统术,以术得道。其中:“道”指“规律、道理、理论”,“术”指“方法、技巧、技术”。意思是:“道”是
- 今天记录一下验证码的实现,希望能够帮助到大家!首先我们看一下实现的效果:此验证码的实现没有用到太多的插件,话不多说直接上代码,大家拿过去就可
- Spring对配置类的处理主要分为2个阶段配置类解析阶段会得到一批配置类的信息,和一些需要注册的beanbean注册阶段将配置类解析阶段得到
- 1.小程序推送信息列如我们去餐厅等位有预约提醒,剩余桌数首先申请一个小程序,微信开放平台:小程序2.申请小程序信息,申请信息模板appid&
- Intellij是进行scala开发的一个非常好用的工具,可以非常轻松查看scala源码,当然用它来开发Java也是很爽的,之前一直在用sc
- 目录:1.list中添加,获取,删除元素;2.list中是否包含某个元素;3.list中根据索引将元素数值改变(替换);4.list中查看(
- 基于SSM框架的仓库管理系统功能:系统操作权限管理。系统提供基本的登入登出功能,同时系统包含两个角色:系统超级管理员和普通管理员,超级管理员
- 前言java有八个基本数据类型,每个都有对应的一个包装类,比如int对应的Integer。 Integer 是int的包装类型,数据类型是类
- 曾几何时,我们写代码的时候,每次写Bean的时候都会使用快捷键生成get/set方法,有时候我经常会想,既然每一个Bean我们都会给其提供g
- 官网教程一、翻转(镜像)头文件 quick_opencv.h:声明类与公共函数#pragma once#include <opencv
- 创建普通Maven工程导入所需依赖坐标:<dependencies> <!-- https://