对 C# 中 UDP 协议的套接字感到困惑

2024-02-22

我刚刚开始通过各种 Google 搜索学习套接字,但在弄清楚如何在 C# 中正确使用套接字时遇到一些问题,我需要一些帮助。

我有一个测试应用程序(Windows 窗体)和一个不同的类(实际上在它自己的 .dll 中,但这无关紧要)我有我的套接字代码的所有服务器/客户端代码。

问题1)

在我的测试应用程序的服务器部分,用户可以单击“开始侦听”按钮,我的套接字应用程序的服务器部分应该开始侦听指定地址和端口上的连接,到目前为止一切顺利。

但是,该应用程序将被阻止,并且在有人连接到服务器之前我无法执行任何操作。如果没有人连接怎么办?我该怎么处理?我可以指定接收超时,但那又怎样呢?它抛出异常,我该怎么办?我想要的是在主应用程序上进行某种活动,以便用户知道应用程序没有冻结并且正在等待连接。但如果没有建立连接,它应该超时并关闭所有内容。

也许我应该使用异步调用来发送/接收方法,但它们看起来很混乱,我无法使其工作,只能同步工作(我将在下面发布我当前的代码)。

问题2)

当某些发送/接收呼叫超时时,我是否需要关闭任何内容?正如您将在我当前的代码中看到的那样,我在套接字上有一堆关闭,但这感觉不太对劲。但当操作超时并且我没有关闭套接字时,感觉也不对劲。

总结我的两个问题......我想要一个不会阻塞的应用程序,以便用户知道服务器正在等待连接(例如带有一点选框动画)。如果一段时间后从未建立连接,我想关闭所有应该关闭的东西。当建立连接或者在一段时间后没有发生连接时,我想将结果通知主应用程序。

这是我的一些代码,其余的类似。这Packetclass 是一个自定义类,代表我的自定义数据单元,它只是一堆基于enums现在,使用将它们转换为字节并返回属性的方法。

开始监听连接的函数是这样的:

public void StartListening(string address, int port) {
    try {
        byte[] bufferBytes = new byte[32];

        if(address.Equals("0.0.0.0")) {
            udpSocket.Bind(new IPEndPoint(IPAddress.Any, port));
        } else {
            udpSocket.Bind(new IPEndPoint(IPAddress.Parse(address), port));
        }

        remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

        int numBytesReceived = udpSocket.ReceiveFrom(bufferBytes, ref remoteEndPoint);

        if(numBytesReceived == 0) {
            udpSocket.Close();
            return;
        }

        Packet syncPacket = new Packet(bufferBytes);

        if(syncPacket.PacketType != PacketType.Control) {
            udpSocket.Close();
            return;
        }
    } catch {
        if(udpSocket != null) {
            udpSocket.Close();
        }
    }
}

我确信我有一堆不必要的代码,但我对此很陌生,我不确定该怎么做,非常感谢任何修复我的代码以及如何解决上述问题的帮助。

EDIT:

我可能应该声明我的要求是使用 UDP 并自己在应用层实现这些东西。您可以将其视为家庭作业,但我没有标记为这样,因为代码无关紧要,不会成为我成绩的一部分,而且我的问题(我的问题)是“如何编码”,因为我的套接字经验很少,而且不是教过。

不过,我必须说,我现在解决了我的问题,我想...我在演示应用程序上使用线程,这给我带来了一些问题,现在我在协议连接中使用它,更有意义,我可以轻松更改我的自定义协议类属性并从演示应用程序中读取这些属性。

我指定了一个超时,如果达到超时则抛出 SocketException。每当捕获到这样的异常时,套接字连接就会关闭。我只是说连接握手,仅此而已。如果没有捕获到异常,则代码可能会顺利进行并建立连接。

请相应地调整您的答案。现在,我将其中任何一个标记为已接受的答案都没有意义,希望您理解。


你的事情有点不对劲。

首先,UDP是无连接的。您不连接或断开连接。您所做的只是发送和接收(每次都必须指定目的地)。您还应该知道 UDP 唯一承诺的是每次读取时都会收到完整的消息。 UDP 不保证您的消息按正确的顺序到达或完全到达。

另一方面,TCP 是基于连接的。您连接、发送/接收,最后断开连接。 TCP 是基于流的(而 UDP 是基于消息的),这意味着您可以在第一次读取时获得一半消息,在第二次读取时获得另一半消息。 TCP 向您保证一切都会按正确的顺序到达(或者会失败;)。因此,使用 TCP 意味着您应该拥有某种逻辑来知道完整消息何时到达,以及用于构建完整消息的缓冲区。

下一个大问题是关于阻塞。由于您是新手,因此我建议您使用线程来处理套接字。将侦听器套接字放在一个线程中,将每个连接套接字放在一个单独的线程中(5 个连接的客户端 = 5 个线程)。

我还建议您使用 TCP,因为构建完整的消息比排序消息和构建事务系统更容易(如果您想确保所有消息到达/来自客户端,则需要该系统)。

Update

你还是把UDP搞错了。关闭除了清理系统资源之外不做任何事情。你应该这样做:

public void MySimpleServer(string address, int port) 
{
    try 
    {
        byte[] bufferBytes = new byte[32];

        if(address.Equals("0.0.0.0")) {
            udpSocket.Bind(new IPEndPoint(IPAddress.Any, port));
        } else {
            udpSocket.Bind(new IPEndPoint(IPAddress.Parse(address), port));
        }

        remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        while (serverCanRun)
        {
            int numBytesReceived = udpSocket.ReceiveFrom(bufferBytes, ref remoteEndPoint);

            // just means that one of the clients closed the connection using Shutdown.
            // doesnt mean that we cant continue to receive.
            if(numBytesReceived == 0)
                continue; 

            // same here, loop to receive from another client.
            Packet syncPacket = new Packet(bufferBytes);
            if (syncPacket.PacketType != PacketType.Control)
                continue; 

            HandlePacket(packet, endPoint);
        }
    } catch {
        if(udpSocket != null) {
            udpSocket.Close();
        }
    }
}

看?由于没有连接,关闭 UDP 套接字以开始侦听另一个套接字只是浪费时间。同一个套接字可以从所有知道正确端口和地址的 udp 客户端接收数据。这就是remoteEndPoint是为了.它告诉哪个客户端发送消息。

Update 2

小更新,总结我的所有评论。

UDP 是无连接的。您永远无法检测连接是否已建立或断开。 UDP 套接字上的 Close 方法只会释放系统资源。致电client.Close()不会通知服务器套接字(与 TCP 一样)。

检查连接是否打开的最佳方法是创建 ping/pong 类型的数据包。即客户端发送 PING 消息,服务器以 PONG 响应。请记住,如果消息未到达,UDP 不会尝试重新发送消息。因此,在假设服务器已关闭之前,您需要重新发送 PING 几次(如果您没有收到 PONG)。

至于客户端关闭,您需要向服务器发送自己的消息,告诉它客户端将停止与服务器通信。为了可靠性,这里也是同样的情况,请继续重新发送 BYE 消息,直到收到回复。

恕我直言,如果您想要可靠性,则必须实现 UDP 事务系统。 SIP (google rfc3261) 是使用 UDP 上的事务的协议示例。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对 C# 中 UDP 协议的套接字感到困惑 的相关文章

  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • pthread_cond_timedwait() 和 pthread_cond_broadcast() 解释

    因此 我在堆栈溢出和其他资源上进行了大量搜索 但我无法理解有关上述函数的一些内容 具体来说 1 当pthread cond timedwait 因为定时器值用完而返回时 它如何自动重新获取互斥锁 互斥锁可能被锁定在其他地方 例如 在生产者
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 如何忽略“有符号和无符号整数表达式之间的比较”?

    谁能告诉我必须使用哪个标志才能使 gcc 忽略 有符号和无符号整数表达式之间的比较 警告消息 gcc Wno sign compare 但你确实应该修复它警告你的比较
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐

  • 使用 EC2(Amazon Web Services)自动 Ejabberd 集群[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 Using Ejabberd http www process one net en ejabberd in EC2 http aws amazon
  • 在 Android 上检测 4K UHD 屏幕

    我正在尝试检测设备何时能够以 4K UHD 3840x2160 分辨率输出 nVidia Shield TV 和 Sony Xperia Z5 Premium 等许多设备即使支持 UHD 也会报告以 1080p 运行 因为它们默认为非视频布
  • Windows 7 左键单击时钟弹出窗口

    当在 Windows 7 也可能是 Vista 上单击任务栏中的时钟时 会打开一个弹出窗口 显示日历和时钟 因此不是日期和时间调整窗口 我如何自己打开这个窗口 在 C 中首选 我希望timedate cpl会调用它 但这会打开日期和时间调整
  • 如何在 Tkinter 中获得带有滚动条的框架?

    我想要一个Frame 用户可以根据应用程序的需要添加任意数量的文本字段 该应用程序以一个文本字段和该文本字段下方的一个按钮开始 当用户按下按钮时 新的文本条目将添加到第一个文本条目下方 这可能会重复无数次 在窗口的中间 会有一个Text小部
  • docker 中的特权模式以集群形式组成

    我在用docker compose yml在具有树莓派集群的 docker swarm 中部署服务 我的服务需要访问树莓派 GPIO 并且需要特权模式 我使用 docker 版本 18 02 和 docker compose 版本 3 6
  • 返回流而不是列表[重复]

    这个问题在这里已经有答案了 在 Java 8 中我越来越多地替换Collection返回值与Stream 所以我曾经拥有过 public List
  • 我可以使用 Google Chrome 扩展程序阻止alert()吗

    我可以创建一个 Google Chrome 扩展来阻止该页面执行alert 正如 MrGlass 所说 目前 Chrome 扩展程序在单独的环境中运行 限制了对实际应用程序的访问 window对象并提供仅对扩展有效的副本 为了解决这个问题
  • Django - 区分不同类型的 IntegrityError

    我正在使用 django MySQL 有时 我将重复的数据插入数据库 这会导致 django 引发错误IntegrityErrror 问题是 django python 对几个不同的版本使用相同的错误MySQL 错误 http dev my
  • write_some 与 write - boost asio

    为什么有人想使用write some什么时候它可能无法将所有数据传输给对等方 从升压write some文档 write some 操作可能不会将所有数据传输到对等方 如果需要确保所有数据都被写入 请考虑使用 write 函数 在阻塞操作完
  • is_numeric、intval、ctype__digit..您可以信赖它们吗?

    is numeric intval ctype digit 您可以信赖它们吗 或者我必须使用正则表达式 function isNum str return preg match 0 9 str 你们有什么感想 我是傻子吗 之间的一个重要区别
  • 如何使用 OpenSSL 提取公钥?

    以下命令生成一个包含公钥和私钥的文件 openssl genrsa des3 out privkey pem 2048 Source here http www openssl org docs HOWTO keys txt 使用OpenS
  • make:安装:找不到命令

    当我尝试安装时git从它的源头开始qnx 我收到以下错误 请注意 pound 是 sudo 的提示qnx configure without iconv with perl usr pkg bin perl with python usr
  • 在哪里可以找到使用 boto3 编写自定义 AWS 凭证提供程序的文档?

    我希望创建一个 python 进程来在运行时刷新临时 AWS 凭证 有效期为 30 分钟 以确保我的代码可以连续运行超过 30 分钟 什么是 RefreshableCredentials 以及如何使用它 经过大量研究后 我终于得出结论 bo
  • 使用jest 模拟react-router-dom 钩子不起作用

    我正在使用 Enzyme 的浅层方法来测试使用useParams钩子从 URL 参数中获取 ID 我试图嘲笑useParams挂钩 这样它就不会调用实际的方法 但它不起作用 我还在得到TypeError Cannot read proper
  • 从 Windows 进行 Linux 开发的最佳设置? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 从 Windows 工作站开发 Linux 应用程序的最佳设置是什么 现在 我通过 SSH 连接到我们的 Linux 开发服务器 并使用 Ecl
  • 结构图 - 构造函数中依赖项的集合

    我的注册表中有以下代码 Scan x gt x Assembly Assembly GetExecutingAssembly x AddAllTypesOf
  • 如何使用构建中注入的密码作为 Active Choices 参数中的环境变量

    我在标题为 将密码作为环境变量注入到构建中 的构建配置部分中定义了密码 我想在我的 Active Choices 中使用 MYVAR 未加密值 不幸的是 它不起作用 对 MYVAR 的引用失败 在下面的示例中 为了测试 我只是尝试显示 MY
  • 通过参数推导多参数模板中的第一个模板参数

    首先是我的问题 然后解释我正在尝试做什么 因为我可能会错误地处理问题 是否可以在指定其他参数的同时从参数中推导出多参数模板中的第一个模板参数 例子 template
  • 在自定义模块中使用时,Import-Pssession 不会导入 cmdlet

    我有一个 PowerShell 脚本 函数 当我在 PowerShell 配置文件中使用它或在 PowerShell 窗口中手动复制 粘贴该函数时 效果非常好 我正在尝试使该功能作为模块可供团队的其他成员访问 我希望将模块存储在一个中心位置
  • 对 C# 中 UDP 协议的套接字感到困惑

    我刚刚开始通过各种 Google 搜索学习套接字 但在弄清楚如何在 C 中正确使用套接字时遇到一些问题 我需要一些帮助 我有一个测试应用程序 Windows 窗体 和一个不同的类 实际上在它自己的 dll 中 但这无关紧要 我有我的套接字代