UdpClient的Connect究竟做了什么(转)
最近在写一个音频通信的系统,因为需要还要处理其他事件,所以就自己设计底层的通信协议,用了不少底层的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究竟做了什么(转)的更多相关文章
- 异步编程系列第05章 Await究竟做了什么?
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- 一个请求中,ADF、JSF究竟做了哪些工作
在Oracle ADF开发中,一个请求发生后,经过ADF处理后,我们可以很快得到响应页面,但在请求过程中ADF框架在背后究竟做了什么东西呢?今天让我们一起来了解下,ADF.JSF是基于组件模型的,不同 ...
- [源码解析] Flink的groupBy和reduce究竟做了什么
[源码解析] Flink的groupBy和reduce究竟做了什么 目录 [源码解析] Flink的groupBy和reduce究竟做了什么 0x00 摘要 0x01 问题和概括 1.1 问题 1.2 ...
- 《大话数据库》-SQL语句执行时,底层究竟做了什么小动作?
<大话数据库>-SQL语句执行时,底层究竟做了什么小动作? 前言 大家好,我是Taoye,试图用玩世不恭过的态度对待生活的Coder. 现如今我们已然进入了大数据时代,无论是业内还是业外的 ...
- 当我们按下电源键,Android 究竟做了些什么?
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由goo发表于云+社区专栏 相信我们对Android系统都不陌生,而Android系统博大精深,被各种各样的智能设备承载的同时,我们会否 ...
- PeekMessage究竟做了什么?
1.UI线程 2.工作线程 把Delphi里TThread的WaitFor函数转化成C++代码,就会是下面这个样子. BOOL TThread::WaitFor(HANDLE hThread) { M ...
- 一张图带你看懂SpriteKit中Update Loop究竟做了神马!
1首先Scene中只有开始一点时间用来回调其中的update方法 ;] 2然后是Scene中所有动作的模拟 3接下来是上一步完成之后,给你一个机会执行一些代码 4然后是Scene模拟其中的物理世界 5 ...
- select count(*) 底层究竟做了什么?
阅读本文大概需要 6.6 分钟. SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表 ...
- 为什么 java wait/notify 必须与 synchronized 一起使用,jvm究竟做了些什么
这个课题提出来的是原先的线程并发解决的思路.目前解决线程并发,可以是lock接口结合condition 并发问题一直以来就是线程必不可少的话题. java 是第一个内置对多线程支持的主流编程语言.在 ...
随机推荐
- C#开发COM+组件和ActiveX控件
using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices ...
- django - request.raw_post_data 与 request.body
request.raw_post_data 重命名成了 request.body - 在1.3版本之后. 这是当时 起票 的讨论内容:https://code.djangoproject.com/ti ...
- hdu 2155 小黑的镇魂曲(dp) 2008信息工程学院集训队——选拔赛
感觉蛮坑的一道题. 题意很像一个叫“是男人下100层”的游戏.不过多了个时间限制,要求在限定时间内从某一点下落到地面.还多了个最大下落高度,一次最多下落这么高,要不然会摔死. 一开始想dp的,然后想了 ...
- [Everyday Mathematics]20150122
设 $f:[0,1]\to [0,1]$. (1). 若 $f$ 连续, 试证: $\exists\ \xi\in [0,1],\st f(\xi)=\xi$. (2). 若 $f$ 单调递增, 试证 ...
- Storm实战常见问题及解决方案
该文档为实实在在的原创文档,转载请注明: http://blog.sina.com.cn/s/blog_8c243ea30101k0k1.html 类型 详细 备注 该文档是群里几个朋友在storm实 ...
- 【windows核心编程】DLL相关(3)
DLL重定向 因为DLL的搜索路径有先后次序,假设有这样的场景:App1.exe使用MyDll1.0.dll, App2.exe使用MyDll2.0.dll, MyDll1.0 和 MyDll2.0是 ...
- 为cocos2d-x项目增加Lua支持
开始为游戏增加Lua脚本支持,今天主要配置了一下开发环境:cocos2d-x 2.2.1,xcode5. 1. 创建cocos2d-x-lua项目 类似于创建C++项目,用以下命令即可: python ...
- Python学习之eventlet.greenpool
该模块提供对 greenthread 池的支持. greenthread 池提供了一定数量的备用 greenthread ,有效限制了孵化 greenthread 过多导致的内存不足,当池子中没有足够 ...
- bzoj 1009 [HNOI2008]GT考试(DP+KMP+矩阵乘法)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1009 [题意] 给定一个字符串T,问长度为n且不包含串T的字符串有多少种. [思路] ...
- [apkAnalyzer] 查看APK包名
最近项目中要用到APK的包名,必应到apkAnalyzer这个软件可以用,下载解压后,看到这么些jar,bat文件不知道怎么用. 参考了这篇文章,看的也不甚明白,最后还是试出来了,这里记录一下. 首先 ...