最近在写一个音频通信的系统,因为需要还要处理其他事件,所以就自己设计底层的通信协议,用了不少底层的Socket编程(.Net Framework),搞清楚了不少细节问题。

先做一些铺垫工作。音频系统服务器需要给所有的客户端发送音频。服务器端要记录下连接的客户端的IPEndPoint(也就是IP+端口号),然后会对所有连接的客户端群发。因为客户端很可能是在NAT后的,所以不可能直接用向某个地址的Udp客户端发送连接。所以客户端需要把第一条消息发送给服务器端,NAT服务器就会打开一个口,允许服务器端向这个客户端发送包(这就是最简单的所谓的“Udp打洞”技术)。当然这个端口不会一直保留,一般不用的话很快就会被关闭。不过传输实时音频一般都会连续使用的,所以不用太担心这个问题。

所以客户端先要向服务器发送一条消息,服务器端看到这是要求接受的消息后,就会把获得的IPEndPoint加到群发列表中。服务器端的监听UdpClient要Bind到一个端口,它只需要考虑接受消息。另一个UdpClient来发送消息,而这个不指定发送目标也没有绑定到端口的UdpClient,需要在发送时指定消息目标,或者用Connect方法,来指定某个默认目标。服务器端因为要向不同的目标发送,所以不用Connect。

但是客户端的UdpClient却需要首先作为发送端,然后再作为接受端。因为在发起第一个发送的时候,操作系统会自动选取一个端口号,因此我们就希望客户端能在此监听。但是客户端发送时只跟服务器的某个IPEndPoint通信,所以一开始我就用Connect连接到服务器的IPEndPoint。几乎所有的文档都说,Connect基本不做什么事情,它只是设置Send的默认接收端,免去每次发送都指定接收端的麻烦。但是Connect其实还做了一件事,导致客户端接收不到服务器发送过来的消息。是什么呢?

因为Connect把该UdpClient所能接受的消息来源限制为所连接的接受端。但是服务器端的发送却是另一个UdpClient执行的,它的端口号是由系统随机分配的,而不是监听消息的UdpClient。所以客户端的UdpClient就不能接受到这个消息。所以这种需要连接一个UdpClient,却需要接受另一个UdpClient消息的情况,就不能使用Connect了。解决的办法是直接使用SendTo(Socket方法)或者UdpClient指定目的的Send方法的重载。

但是能够用同一个正在Receive的UdpClient同时发送数据吗?按说应该可以,但是没有试验过,有经验的大牛直接告诉我得了。而且对于使用了线程的服务器来说(使用.Net的异步编程模型潜在使用了线程池),用一个UdpClient来做所有的工作,总是担心会出现并发访问问题,或者出现并发导致的效率损失。所以为了保险起见,还是各做各的事比较好。

如果在局域网,或者以后大家都用IPv6,就没有这些复杂的问题,直接客户端开一个端口监听就行了。服务器只要知道IP,就可以向默认的端口发送消息。多么美好的景象!

UdpClient的Connect究竟做了什么(转)的更多相关文章

  1. 异步编程系列第05章 Await究竟做了什么?

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

  2. 一个请求中,ADF、JSF究竟做了哪些工作

    在Oracle ADF开发中,一个请求发生后,经过ADF处理后,我们可以很快得到响应页面,但在请求过程中ADF框架在背后究竟做了什么东西呢?今天让我们一起来了解下,ADF.JSF是基于组件模型的,不同 ...

  3. [源码解析] Flink的groupBy和reduce究竟做了什么

    [源码解析] Flink的groupBy和reduce究竟做了什么 目录 [源码解析] Flink的groupBy和reduce究竟做了什么 0x00 摘要 0x01 问题和概括 1.1 问题 1.2 ...

  4. 《大话数据库》-SQL语句执行时,底层究竟做了什么小动作?

    <大话数据库>-SQL语句执行时,底层究竟做了什么小动作? 前言 大家好,我是Taoye,试图用玩世不恭过的态度对待生活的Coder. 现如今我们已然进入了大数据时代,无论是业内还是业外的 ...

  5. 当我们按下电源键,Android 究竟做了些什么?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由goo发表于云+社区专栏 相信我们对Android系统都不陌生,而Android系统博大精深,被各种各样的智能设备承载的同时,我们会否 ...

  6. PeekMessage究竟做了什么?

    1.UI线程 2.工作线程 把Delphi里TThread的WaitFor函数转化成C++代码,就会是下面这个样子. BOOL TThread::WaitFor(HANDLE hThread) { M ...

  7. 一张图带你看懂SpriteKit中Update Loop究竟做了神马!

    1首先Scene中只有开始一点时间用来回调其中的update方法 ;] 2然后是Scene中所有动作的模拟 3接下来是上一步完成之后,给你一个机会执行一些代码 4然后是Scene模拟其中的物理世界 5 ...

  8. select count(*) 底层究竟做了什么?

    阅读本文大概需要 6.6 分钟. SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表 ...

  9. 为什么 java wait/notify 必须与 synchronized 一起使用,jvm究竟做了些什么

    这个课题提出来的是原先的线程并发解决的思路.目前解决线程并发,可以是lock接口结合condition  并发问题一直以来就是线程必不可少的话题. java 是第一个内置对多线程支持的主流编程语言.在 ...

随机推荐

  1. Gulp使用指南

    Grunt靠边,全新的建构工具来了.Gulp的code-over-configuration不只让撰写任务(tasks)更加容易,也更好阅读及维护. Glup使用node.js串流(streams)让 ...

  2. django - 修改 request.POST的值

    # querydict改为mutable data = data.copy() data.update({'key_list': DATA_UPLOAD_PARAMETER}) 默认的request. ...

  3. LeetCode: Combination Sum I && II && III

    Title: https://leetcode.com/problems/combination-sum/ Given a set of candidate numbers (C) and a tar ...

  4. CCapture directshow 视频捕获类

    // Capture.h for class CCapture #include <dshow.h> #include <qedit.h> #include <atlba ...

  5. Control File (二)重建CONTROLFILE --- NORESETLOG

    create controlfile  --- noresetlog 由于丢失control01.ctl  alter_karl.log 中显示: -------------------------- ...

  6. 【转】匹配dll(exe)和pdb方法

    1. 静态检查windbg 调试工具包中有一个工具symchk.exe, 选项很多, 下面一个简单的用法可以检查一个 test.exe能不能找到与它匹配的PDB: 这是成功的情形. 下面来个失败的作为 ...

  7. oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序

    15511477451 原文 oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序? 环境:win7 64位系统.oracle11g数据库 问题描述:在win7 64位系统 ...

  8. 1048 图的宽度优先遍历序列 c语言

    描述 图(graph)是数据结构 G=(V,E),其中V是G中结点的有限非空集合,结点的偶对称为边(edge):E是G中边的有限集合.设V={0,1,2,……,n-1},图中的结点又称为顶点(vert ...

  9. 前言:关于nagios监控

    前言,关于nagios监控. 这段时间一直在做关于nagios监控,不停的做实验,从而也忽略了书写这方面,今天写一份安装文档花了四个多小时,看来写文档也是一件很麻烦的事情,不过,做过的事情还是需要留下 ...

  10. bzoj 3275 Number(最小割)

    [题意] 给定n个数,要求选出一些数满足 1.存在c,a*a+b*b=c*c 2.gcd(a,b)=1  使得和最大. [思路] 二分图的最大权独立集(可以这么叫么QAQ 先拆点,对于不满足条件的两个 ...