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 是第一个内置对多线程支持的主流编程语言.在 ...
随机推荐
- 注解框架ButterKnife
将插件升级到1.3后支持Android Studio1.3 + ButterKnife7 如何使用 有所使用的布局 ID 上点击右键 (例如上图中的 R.layout.activity_setting ...
- VS2008+ffmpeg SDK3.2调试tutorial01
最近研究ffmpeg,在ubuntu下感觉不太好调试,老是找不到函数的声明.所以我就把他移到windows下用vs2008分析 关于环境的搭建,我参考了 http://hi.baidu.com/for ...
- 【转】iOS类似Android上toast效果
原文网址:http://m.blog.csdn.net/article/details?id=50478737 做过Android开发的人都知道toast,它会在界面上显示一排黑色背景的文字,用于提示 ...
- TCP/IP详解学习笔记(7)-广播和多播,IGMP协议
1.单播,多播,广播的介绍 1.1.单播(unicast) 单播是说,对特定的主机进行数据传送.例如给某一个主机发送IP数据包.这时候,数据链路层给出的数据头里面是非常具体的目的地址,对于以太网来 说 ...
- MySQL auto_increment的坑
背景: Innodb引擎使用B_tree结构保存表数据,这样就需要一个唯一键表示每一行记录(比如二级索引记录引用). Innodb表定义中处理主键的逻辑是: 1.如果表定义了主键,就使用主键唯一定位一 ...
- [Everyday Mathematics]20150120
设 $f:\bbR\to\bbR$ 二阶可微, 且 $$\bex f(0)=2,\quad f'(0)=-2,\quad f(1)=1. \eex$$ 试证: $$\bex \exists\ \xi\ ...
- Windows7 64位系统下无法安装网络打印机的解决方法
背景: 公司一台HP LaserJet 1010 打印机连在一台Windows XP的电脑上,而我的是windows7 64位系统,无法安装驱动解决办法:1:去惠普官网上下载对应的64位驱动(什么Vi ...
- JDBC连接工厂类
看到有些书上数据库连接提供两个工厂类,一个连接工厂类一个关闭工厂类,并且关闭工厂类写了多种重载形式,感觉没有必要,这样写比较简洁一些. /** * 抽象出的连接工厂类,提供连接数据库和关闭连接的 ...
- (转)我是如何在SQLServer中处理每天四亿三千万记录的
首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...
- Install_pygments
安装Pygments语法高亮 On OS X Leopard, Snow Leopard 1 $ sudo easy_install Pygments Alternatively on OS X wi ...