使用netsh在v4/v6网络和应用程序之间实现互访

2009年7月6日

在v4/v6互通转换方面,一些简单有效的东西却往往被忽视。

使用netsh,在不对应用本身做改动的前提下,可以实现几乎所有v4、v6应用的快速互访。

以下内容来源于:http://technet.microsoft.com/zh-cn/library/cc776297(WS.10).aspx

Netsh 接口 Portproxy 命令

用于接口 Portproxy 的 Netsh 命令

对于在 IPv4 和 IPv6 网络和应用程序之间充当代理的管理服务器,Netsh Interface Portproxy 命令为它们提供了可在其中使用的命令行工具。可以按以下方式使用这些命令来建立代理服务:

  • 将配置了 IPv4 的计算机和应用程序消息发送到其他配置了 IPv4 的计算机和应用程序。
  • 将配置了 IPv4 的计算机和应用程序消息发送到配置了 IPv6 的计算机和应用程序。
  • 将配置了 IPv6 的计算机和应用程序消息发送到配置了 IPv4 的计算机和应用程序。
  • 将配置了 IPv6 的计算机和应用程序消息发送到其他配置了 IPv6 的计算机和应用程序。

当使用这些命令编写批处理文件或脚本时,每个命令必须以 netsh interface portproxy 开头。例如,使用 delete v4tov6 命令来指定 portproxy 服务器从该服务器所侦听的 IPv4 地址列表中删除 IPv4 端口和地址时,该批处理文件或脚本必须使用以下语法:

netsh interface portproxy delete v4tov6listenport= {Integer | ServiceName} [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

可以从 Windows Server 2003 家族产品的命令提示符下,或从 Netsh interface portproxy 上下文的命令提示符下运行这些命令。对于在 Windows Server 2003 家族产品的命令提示符下运行的这些命令,必须在按照下面的语法键入命令和参数之前键入 netsh interface portproxy。Windows 2000 和 Windows Server 2003 家族中的 Netsh 上下文命令之间可能存在功能性差异。

有关 Netsh 的详细信息,请参阅Netsh 概述输入 netsh 上下文

若要查看该命令语法,请单击以下命令:

add v4tov4
add v4tov6
add v6tov4
add v6tov6
delete v4tov4
delete v4tov6
delete v6tov4
delete v6tov6
reset
set v4tov4
set v4tov6
set v6tov4
set v6tov6
show all
show v4tov4
show v4tov6
show v6tov4
show v6tov6
add v4tov4

指定 portproxy 服务器侦听发送到指定端口和 IPv4 地址的消息,并映射一个端口和 IPv4 地址,以便向该端口和地址发送在建立独立的 TCP 连接之后所收到的消息。

语法

add v4tov4listenport= {Integer | ServiceName} [[connectaddress=] {IPv4Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv4 端口。
connectaddress
指定要连接的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv4 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持传输控制协议 (TCP)。
/?
在命令提示符下显示帮助。

add v4tov6

指定 portproxy 服务器侦听发送到指定端口和 IPv4 地址的消息,并映射一个端口和 IPv6 地址,以便向该端口和地址发送在建立独立的 TCP 连接之后所收到的消息。

语法

add v4tov6listenport= {Integer | ServiceName} [[connectaddress=] {IPv6Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv4 端口。
connectaddress
指定要连接的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv6 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

add v6tov4

指定 portproxy 服务器侦听发送到指定端口和 IPv6 地址的消息,并映射一个端口和 IPv4 地址,以便向该端口和地址发送在建立独立的 TCP 连接之后所收到的消息。

语法

add v6tov4listenport= {Integer | ServiceName} [[connectaddress=] {IPv4Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv6 端口。
connectaddress
指定要连接的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv4 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

add v6tov6

指定 portproxy 服务器侦听发送到指定端口和 IPv6 地址的消息,并映射一个端口和 IPv6 地址,以便向该端口和地址发送在建立独立的 TCP 连接之后所收到的消息。

语法

add v6tov6listenport= {Integer | ServiceName} [[connectaddress=] {IPv6Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv6 端口。
connectaddress
指定要连接的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv6 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

delete v4tov4

指定 portproxy 服务器从它侦听的 IPv4 端口和地址列表中删除 IPv4 地址。

语法

delete v4tov4listenport= {Integer | ServiceName} [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。指定要删除的 IPv4 端口。
listenaddress
指定要删除的 IPv4 地址。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

delete v4tov6

指定 portproxy 服务器从它侦听的 IPv4 地址列表中删除 IPv4 端口和地址。

语法

delete v4tov6listenport= {Integer | ServiceName} [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。指定要删除的 IPv4 端口。
listenaddress
指定要删除的 IPv4 地址。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

delete v6tov4

指定 portproxy 服务器从它侦听的 IPv6 地址列表中删除 IPv6 端口和地址。

语法

delete v6tov4listenport= {Integer | ServiceName} [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。指定要删除的 IPv6 端口。
listenaddress
指定要删除的 IPv6 地址。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

delete v6tov6

指定 portproxy 服务器从它侦听的 IPv6 地址列表中删除 IPv6 地址。

语法

delete v6tov6listenport= {Integer | ServiceName} [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。指定要删除的 IPv6 端口。
listenaddress
指定要删除的 IPv6 地址。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

reset

重设 IPv6 配置状态。

语法

reset

set v4tov4

修改使用 add v4tov4 命令创建的 portproxy 服务器上的现有项的参数值,或将新项添加到映射端口/地址对的列表中。

语法

set v4tov4listenport= {Integer | ServiceName} [[connectaddress=] {IPv4Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv4 端口。
connectaddress
指定要连接的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv4 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持传输控制协议 (TCP)。
/?
在命令提示符下显示帮助。

注释

  • 您可以更改现有的端口代理服务器条目的任何参数值。如果未提供值,则不作任何更改。

set v4tov6

修改使用 add v6tov6 命令创建的 portproxy 服务器上的现有项的参数值,或将新项添加到映射端口/地址对的列表中。

语法

set v4tov6listenport= {Integer | ServiceName} [[connectaddress=] {IPv6Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv4Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv4 端口。
connectaddress
指定要连接的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv6 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

注释

  • 您可以更改现有的端口代理服务器条目的任何参数值。如果未提供值,则不作任何更改。

set v6tov4

修改使用 add v6tov4 命令创建的 portproxy 服务器上的现有项的参数值,或将新项添加到映射端口/地址对的列表中。

语法

set v6tov4listenport= {Integer | ServiceName} [[connectaddress=] {IPv4Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv6 端口。
connectaddress
指定要连接的 IPv4 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv4 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

注释

  • 您可以更改现有的端口代理服务器条目的任何参数值。如果未提供值,则不作任何更改。

set v6tov6

修改使用 add v6tov6 命令创建的 portproxy 服务器上的现有项的参数值,或将新项添加到映射端口/地址对的列表中。

语法

set v6tov6listenport= {Integer | ServiceName} [[connectaddress=] {IPv6Address | HostName}] [[connectport=] {Integer | ServiceName}] [[listenaddress=] {IPv6Address| HostName}] [[protocol=]tcp]

参数

listenport
必需。按端口号或服务名指定要侦听的 IPv6 端口。
connectaddress
指定要连接的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果未指定地址,则默认设置为本地计算机。
connectport
按端口号或服务名指定要连接的 IPv6 端口。如果未指定 connectport,则默认设置为本地计算机上的 listenport 值。
listenaddress
指定要侦听的 IPv6 地址。可接受的值为 IP 地址、计算机 NetBIOS 名称或计算机 DNS 名称。如果不指定地址,则默认设置是本地计算机。
protocol
指定要使用的协议。当前仅支持 TCP 协议。
/?
在命令提示符下显示帮助。

注释

  • 您可以更改现有的端口代理服务器条目的任何参数值。如果未提供值,则不作任何更改。

show all

显示所有 portproxy 参数,包括 v4tov4、v4tov6、v6tov4 和 v6tov6 的端口/地址对。

语法

show all

show v4tov4

显示 v4tov4 portproxy 参数。

语法

show v4tov4

show v4tov6

显示 v4tov6 portproxy 参数。

语法

show v4tov6

show v6tov4

显示 v6tov4 portproxy 参数。

语法

show v6tov4

show v6tov6

显示 v6tov6 portproxy 参数。

语法

show v6tov6

格式图例

 

格式 意义
斜体 用户必须提供的信息
粗体 用户必须像显示的一样准确键入的元素
省略号 (…) 可在命令行中重复多次的参数
在括号 ([]) 之间 可选项目
在大括号 ({}) 之间;将选项用管线 (|) 隔开。例如:{even|odd} 用户必须从中只选择一个选项的选项组
Courier font 代码或程序输出

See Also

 

 

kaida Work 2,900 views

使用IPv6访问Youtube

2009年6月25日

1.修改 hosts 文件
C:\>cd \windows\system32\drivers\etc

C:\WINDOWS\system32\drivers\etc>notepad hosts

再增加几行
2001:4860:c004::68 www.google.com
2001:4860:c004::68 www.google.com.tw
2001:4860:c004::68 clients1.google.com
2001:4860:c004::68 ipv6.google.com
2001:4860:c004::68 mail.google.com
2001:4860:c004::68 www.youtube.com
2001:4860:c004::68 gdata.youtube.com
2001:4860:c004::68 upload.youtube.com
2001:4860:c004::68 insight.youtube.com
2001:4860:c004::68 help.youtube.com
2001:4860:c004::68 s.ytimg.com
2001:4860:c004::68 www.blogspot.com
2001:4860:c004::68 www.blogger.com
2001:4860:c004::68 blogspot.com
2001:4860:c004::68 blogger.com

保存此文件

2.刷新DNS缓存
C:\WINDOWS\system32\drivers\etc>ipconfig /flushdns

然后使用 www.youtube.com 即可访问

kaida Tips 8,800 views

(更新)使用IPv6访问google.com和Gmail

2009年6月24日

现在DNS已经不能正常解析 ipv6.google.com 了,唉,不过办法总是有的

1.修改 hosts 文件
C:\>cd \windows\system32\drivers\etc

C:\WINDOWS\system32\drivers\etc>notepad hosts

增加几行
2001:4860:c004::68 www.google.com
2001:4860:c004::68 www.google.com.tw
2001:4860:c004::68 clients1.google.com
2001:4860:c004::68 ipv6.google.com
2001:4860:c004::68 mail.google.com

保存此文件

2.刷新DNS缓存
C:\WINDOWS\system32\drivers\etc>ipconfig /flushdns

然后使用 ipv6.google.com 即可访问 google.com

使用 mail.google.com 即可访问 Gmail

不过Gmail已经意义不大了…

kaida Tips 6,676 views

Google IPv6 网址

2009年6月20日

IPv6 only website

http://ipv6.google.com/

http://ipv6.google.co.jp/

还是喜欢这种更少人工干预的 Google 。

kaida Tips 1,409 views

FreeNAS的校园网应用.

2009年5月28日

数年前接触过iSCSI,就一直很欣赏这种灵活的远程文件使用方式.
用户体验很好,简单的iSCSI Initiator配置后,远程服务器目录映射到本地,相当于多了块本地硬盘.

昨天和兰州大学的老师聊天,他们在使用FreeNAS给校内一些用户提供iSCSI方式文件服务,总算找到知音了.

FreeNAS支持 LDAP 和 Active Directory 认证,方便集成统一身份认证,
用户可以通过

  • SMB/CIFS (Common Internet File System)
  • Webserver (using LigHTTPD) and FTP
  • NFS
  • RSYNC
  • iSCSI
  • ……
    等方式调用存储文件.
  • 今日硬盘报价:
    Seagate希捷 Barracuda 7200.11 ST31500341AS SATAII接口台式机硬盘(1.5TB/7200转/32M)  价格:¥869.00

    花2万多,就可以搭一个10T的SATA阵列(至少做个RAID5)服务器出来,每个用户按10G空间计算,就可以满足1k用户了.

    我个人比较推崇这种花钱少,效果好的模式,但是没有亲自做过,有兴趣的老师可以考虑一下,也许可以提供校园网个人用户文件存储服务.

    kaida Work 2,030 views

    IPv6使用中RA 干扰的分析

    2009年5月28日

    IPv6使用中RA 干扰是个各地网络管理人员都普遍遇到的常见问题,也是IPv6的一大安全问题,值得总结分析一下.

    1.客户端配置策略
        XP/Vista/Linux
        之前我有文章简单提到过部分思路.

    2.交换机配置策略(ACL…)

    3.如何发现并定位异常RA源,    深入分析 Rogue IPv6 RA 
        网管人员配置错误?用户操作系统默认配置或不当设定?来自恶意攻击?

    有兴趣可以找我同事   sjtu.edu.cn 约稿,他这方面很有研究.

    附参考文档:
    http://tools.ietf.org/html/draft-chown-v6ops-rogue-ra-03

    ACL举例:
    下面是在某一台二层交换机上使用ACL来解决用户端的RA配置示例.
    mac access-list extended DenyV6RA
      10 deny any host 3333.0000.0001 0×86DD
      20 permit any any etype-any
    interface FastEthernet 0/1
      mac access-group DenyV6RA in

    Fe 0/1 做个检查就可以拒绝非法RA.

    多说两句,科研和实际要结合. 对于网络中心来说,对第一线,对实际的了解是其天然优势,从中抽取实际问题,带着问题进行科研,透彻分析并提出可能的解决方案,这才是实实在在的科研.

    kaida Work 2,116 views

    请避免在WinXP/2003系统传送IPv6流量时调整网络

    2009年5月11日

    我同事发现的,也已经被微软确认的bug

    发信人: colin (БРАТЬЯ), 信区: SJTUnet
    标  题: 请避免在WinXP/2003系统传送IPv6流量时调整网络
    发信站: 饮水思源 (2009年05月11日18:36:45 星期一), 站内信件

    调整包括网络连接中断、连接/中断VPN。
    在IPv6网络(isatap隧道)流量传输时,
    网络连接调整可能导致tcpip6.sys出错蓝屏,
    该问题已得到确认,但目前状态为不予修复。大概是太少人报告该问题。
    以及该问题难以被利用吧。
    问题号是 幺⑧伍幺陆洞

    在Windows XP中也有该问题,但支持周期已过,又不属于安全问题,定无补丁。
    2K3系统中也没什么希望,大家使用IPv6时请小心。

    KB968597 并未解决该问题,请不必花时间尝试
    另:Win7中未发现该问题。


    请认准蓝瓶的
    ※ 来源:·饮水思源 bbs.sjtu.edu.cn·[FROM: 2001:da8:8000:d010:0:5efe:ca78:319]

    kaida Work 1,734 views

    Windows Media 网络直播 HOWTO

    2009年5月3日

    上个月去山东,一位石油大学的老师对网络电视直播很感兴趣。

    这几天抽空整理了一下,放在

    http://ipv6.sjtu.edu.cn/doc/20090501_WindowsMedia_HOWTO.ppt

    给各位老师参考.

    这种技术并不复杂,比较成熟,大规模应用投入也很少,比较适合校园网环境.
    但是从未来的发展趋势来看,考虑到万M校园网的普及,

    我更推荐另外一种模式,配合组播+IPv6在校园网应用.

    http://ipv6.sjtu.edu.cn/doc/20081016_SDTVHDTVHowTo.doc

    这里大致描述了一下,有兴趣的可以去玩玩.

    kaida Work, 未分类 1,149 views

    IPv6与IPv4的UDP组播地址转换

    2009年3月20日

    这个东西可能对某些老师有用处,作者
    交大饮水水源BBS ID:
    rogerfd (Roger·璇) 共上站 1344 次 网龄792天 [巨蟹座]
    上 次 在: [2009年03月20日08:59:33 星期五] 从 [211.144.112.64] 到本站一游。
    目前在线:[讯息器:(打开) 呼叫器:(打开)] 生命力:[364] 文章:[297] 信箱:[ ]

    转载自:
    http://rogerfd.cn/?p=184

    Roger的小程序系列(19)IPv6与IPv4的UDP组播地址转换

        工作中有时候需要把一路或者多路IPv6的UDP组播转换为IPv4的组播;有时候则相反,要把IPv4的转换为IPv6,于是写了一个小工具来统一完成这类的事情,Roger把它叫做IPv5,哈哈。

        IPv6的组播接收可以参考Roger之前的文章《Roger的小程序系列(2)IPv6组播工具》,发送也是比较简单的,每收到一个包就用sendto发出去就可以了。需要注意的事情是,这类的转发通常都是使用不同的网卡,一收一发,所以接收和发送都必须指明网络接口和IP地址。IPv6的接收和发送必须绑定IPv6的地址,IPv4的接受和发送则必须绑定IPv4的地址,不能混用。

        所以首先就是要遍历本机的所有网络接口和网络地址,这事情依赖API GetAdaptersAddresses,大致的代码是这样的

        ULONG uLen = 0;
        m_pInfo = NULL;
        //得到该结构的大小
        GetAdaptersAddresses (AF_UNSPEC, 0, 0, m_pInfo, &uLen);
        if (uLen <= 0)
        {
          return FALSE;
        }
        m_pInfo = (IP_ADAPTER_ADDRESSES*) malloc (uLen);
        if (!m_pInfo)
        {
          return FALSE;
        }
        if(ERROR_SUCCESS != GetAdaptersAddresses (AF_UNSPEC, 0, 0, m_pInfo, &uLen))
        {
          free(m_pInfo);
          return FALSE;
        }

        m_pInfo是 IP_ADAPTER_ADDRESSES 类型的指针,所有的网卡信息构成一个链表,下面这段代码来获取所有网卡的描述信息

        void CNewDlg::FillInf(CComboBox* pCombo)
        {
          IP_ADAPTER_ADDRESSES *q = NULL;
          pCombo->ResetContent ();
          for(q = m_pInfo; q ; q = q->Next)
          {
            CString str = q->Description;
            pCombo->AddString (str);
          }
          return;
        }

        以下的代码来遍历一个网络接口的所有地址,我们只关心单播的UnicastAddress

        void CNewDlg::FillAddr(int nIndex, CComboBox* pCombo)
        {
          IP_ADAPTER_ADDRESSES *q = NULL;
          int i = 0;
          pCombo->ResetContent ();
          char addr[256];
          for(q = m_pInfo; q; q = q->Next, ++i)
          {
            if (i == nIndex)
            {
              for (PIP_ADAPTER_UNICAST_ADDRESS pip = q->FirstUnicastAddress; pip ;
                pip = pip->Next) 
              {
                if(!getnameinfo(pip->Address.lpSockaddr,pip->Address.iSockaddrLength,
                      addr, sizeof addr,
                      0,0,NI_NUMERICHOST ))
                {
                  pCombo->AddString (addr);
                }
              }
              break;
            }
          }
          return;
        }

        转换使用后台线程来干活,每个转换搞一个线程,转换的参数和状态信息放在一个全局变量里边。
        /* stdafx.h */

        enum ipv5_status
        {
          status_stop = 0,
          status_starting,
          status_running,
          status_error,
          status_stopping,
        };

        typedef struct _Convert_Info
        {
          char src_mc_addr [64];
          char src_mc_port [8];
          char src_inf_name[256];
          char src_inf_addr[64];
          char dst_mc_addr [64];
          char dst_mc_port [8];
          char dst_inf_name[256];
          char dst_inf_addr[64];
          bool cut_rtp_header;
          bool is_rtp;
          int  send_ttl;
          ipv5_status  status;
          SOCKET recv_socket;
          SOCKET send_socket;
          HANDLE hThread;
          double recvd_packets;
          double recvd_bytes;
          double err_packets;
          double packet_rate;
          double bit_rate;
          double err_rate;
        }Convert_Info;

        #define MAX_THREAD 16

        /* ipv5.cpp */
        Convert_Info g_arryInfo[MAX_THREAD];

        /* WorkTHread.cpp */

        #include “StdAfx.h”
        #include “ipv5.h”

        bool IsV6 (const char* addr)
        {
            return (strstr (addr, “::”) != NULL);
        }

        DWORD WINAPI ThreadProc (LPVOID Index)
        {
            ADDRINFO s1,*s2,s3,*s4;
            ADDRINFO s5,*s6,s7,*s8;
            WSABUF stWSABuf;                               
            SOCKADDR_IN6 addrFrom;
            DWORD dwIndex, dwTime1, dwTime2, nRet, dwParam, cbRet, iLen, iLost;
            USHORT index, oldindex = 0;
            char  buf[64*1024];
            double last_second_packets = 0, last_second_err_packets = 0, last_second_bytes = 0;
            dwIndex = (DWORD) Index;
            g_arryInfo[dwIndex].status = status_starting;
            bool bFirstPkt;

            int ttl = g_arryInfo[dwIndex].send_ttl;
            bool SrcV6 = IsV6 (g_arryInfo[dwIndex].src_inf_addr);
            bool DstV6 = IsV6 (g_arryInfo[dwIndex].dst_inf_addr);

            memset (&s1, 0, sizeof(s1));
            s1.ai_family   = SrcV6 ? AF_INET6 : AF_INET;
            s1.ai_socktype = SOCK_DGRAM;
            s1.ai_protocol = IPPROTO_UDP;
            s1.ai_flags    = AI_NUMERICHOST;
            nRet = getaddrinfo (g_arryInfo[dwIndex].src_mc_addr,
                                g_arryInfo[dwIndex].src_mc_port,
                                &s1,
                                &s2);
            if (nRet != 0)
            {
                goto end;
            }

            memset (&s3, 0, sizeof(s3));
            s3.ai_family   = SrcV6 ? AF_INET6 : AF_INET;
            s3.ai_socktype = SOCK_DGRAM;
            s3.ai_protocol = IPPROTO_UDP;
            s3.ai_flags    = AI_PASSIVE;
            nRet = getaddrinfo (g_arryInfo[dwIndex].src_inf_addr,
                                g_arryInfo[dwIndex].src_mc_port,
                                &s3,
                                &s4);
            if (nRet != 0)
            {
                goto end;
            }

            g_arryInfo[dwIndex].recv_socket =
                WSASocket ( SrcV6 ? AF_INET6 : AF_INET,
                            SOCK_DGRAM,
                            IPPROTO_UDP,
                            (LPWSAPROTOCOL_INFO)NULL,
                            0,
                            WSA_FLAG_OVERLAPPED |
                            WSA_FLAG_MULTIPOINT_C_LEAF |
                            WSA_FLAG_MULTIPOINT_D_LEAF);
            if (g_arryInfo[dwIndex].recv_socket == INVALID_SOCKET)
            {
                goto end;
            }

            dwParam = TRUE;
            nRet = setsockopt (
                                g_arryInfo[dwIndex].recv_socket,
                                SOL_SOCKET,
                                SO_REUSEADDR,
                                (char *)&dwParam,
                                sizeof (dwParam));
            if (nRet == SOCKET_ERROR)
            {
                goto end;
            }

            if (SOCKET_ERROR == bind (g_arryInfo[dwIndex].recv_socket,
                                        s4->ai_addr,
                                        s4->ai_addrlen))
            {
                goto end;  
            }

            dwParam = TRUE;
            nRet = WSAIoctl (g_arryInfo[dwIndex].recv_socket,
                            SIO_MULTIPOINT_LOOPBACK,
                            &dwParam,
                            sizeof (dwParam),
                            NULL,
                            0,
                            &cbRet,
                            NULL,
                            NULL);                                   
            if (nRet)
            {
                goto end;
            }

            g_arryInfo[dwIndex].recv_socket =
                WSAJoinLeaf (g_arryInfo[dwIndex].recv_socket, s2->ai_addr,
                            s2->ai_addrlen,
                            NULL,
                            NULL,
                            NULL,
                            NULL,
                            JL_RECEIVER_ONLY);             
            if (g_arryInfo[dwIndex].recv_socket == INVALID_SOCKET)
            {
                goto end;
            }
           
            dwParam = 2000;
            if(SOCKET_ERROR == setsockopt (g_arryInfo[dwIndex].recv_socket,
                SOL_SOCKET, SO_RCVTIMEO, (const char*)&dwParam,sizeof(dwParam)))
            {
                goto end;
            }

            dwParam = FALSE; //TRUE is Non-Blocking
            nRet = WSAIoctl (g_arryInfo[dwIndex].recv_socket,
                            FIONBIO,
                            &dwParam,
                            sizeof dwParam,
                            NULL,
                            0,
                            &cbRet,
                            0,
                            0);
            dwParam = 256*1024;
            nRet = setsockopt (g_arryInfo[dwIndex].recv_socket,
                                SOL_SOCKET,
                                SO_RCVBUF,
                                (char *)&dwParam,  
                                sizeof (dwParam));
            if (nRet == SOCKET_ERROR)
            {
                goto end;
            }

            memset (&s5, 0, sizeof(s5));
            s5.ai_family   = DstV6 ? AF_INET6 : AF_INET;
            s5.ai_socktype = SOCK_DGRAM;
            s5.ai_protocol = IPPROTO_UDP;
            s5.ai_flags    = AI_NUMERICHOST;
            nRet = getaddrinfo (g_arryInfo[dwIndex].dst_mc_addr,
                                g_arryInfo[dwIndex].dst_mc_port,
                                &s5,
                                &s6);
            if (nRet != 0)
            {
                goto end;
            }

            memset (&s7, 0, sizeof(s7));
            s7.ai_family   = DstV6 ? AF_INET6 : AF_INET;
            s7.ai_socktype = SOCK_DGRAM;
            s7.ai_protocol = IPPROTO_UDP;
            s7.ai_flags    = AI_PASSIVE;
            nRet = getaddrinfo (g_arryInfo[dwIndex].dst_inf_addr,
                                g_arryInfo[dwIndex].dst_mc_port,
                                &s7,
                                &s8);
            if (nRet != 0)
            {
                goto end;
            }

            g_arryInfo[dwIndex].send_socket = socket (DstV6 ? AF_INET6 : AF_INET,
                                                        SOCK_DGRAM,
                                                        IPPROTO_UDP);
            if (g_arryInfo[dwIndex].send_socket == INVALID_SOCKET)
            {
                goto end;
            }
               

            if (SOCKET_ERROR == setsockopt (g_arryInfo[dwIndex].send_socket,
                                            DstV6 ? IPPROTO_IPV6 : IPPROTO_IP,
                                            IP_MULTICAST_TTL,
                                            (const char*)&ttl,
                                            sizeof(int) ) )
            {
                int i = WSAGetLastError();
                goto end;
            }

            if (SOCKET_ERROR == bind (g_arryInfo[dwIndex].send_socket,
                                        s8->ai_addr,
                                        s8->ai_addrlen))
            {
                goto end;
            }

            dwTime1    = GetTickCount();
            bFirstPkt  = TRUE;
            iLost = 0;
            g_arryInfo[dwIndex].is_rtp = false;
            g_arryInfo[dwIndex].status = status_running;
            g_arryInfo[dwIndex].err_packets = g_arryInfo[dwIndex].recvd_packets = g_arryInfo[dwIndex].recvd_bytes = 0;
            g_arryInfo[dwIndex].bit_rate = g_arryInfo[dwIndex].err_rate = g_arryInfo[dwIndex].packet_rate = 0;
            while (g_arryInfo[dwIndex].status == status_running)
            {
                stWSABuf.buf = buf;
                stWSABuf.len = sizeof buf;
                cbRet        = 0;
                dwParam      = 0;
                iLen         = sizeof (addrFrom);
                nRet         = WSARecvFrom (g_arryInfo[dwIndex].recv_socket,
                                            &stWSABuf,
                                            1,
                                            &cbRet,
                                            &dwParam,
                                            (SOCKADDR*)&addrFrom,
                                            (int*)&iLen,
                                            NULL,
                                            NULL);
                if (nRet == SOCKET_ERROR )
                {
                    if (WSAGetLastError() == WSAETIMEDOUT)
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                   
                }

                if (bFirstPkt)
                {
                    if (cbRet >= 188*3 &&
                        stWSABuf.buf[0] == 0×47 &&
                        stWSABuf.buf[188] == 0×47 &&
                        stWSABuf.buf[188*2] == 0×47)
                    {
                        g_arryInfo[dwIndex].is_rtp = false;
                    }
                    else
                    {
                        g_arryInfo[dwIndex].is_rtp = true;
                    }
                }

                g_arryInfo[dwIndex].recvd_packets += 1;
                if(g_arryInfo[dwIndex].is_rtp && cbRet < 12)
                {
                    g_arryInfo[dwIndex].err_packets += 1;
                    continue;
                }

                if (g_arryInfo[dwIndex].is_rtp)
                {
                    //统计丢包
                    index = ntohs (*((USHORT*)(stWSABuf.buf+2)));
                    if (++oldindex != index)
                    {
                        TRACE (”RTP Error! Excepet %d but got %d\n”, oldindex, index);
                        if (!bFirstPkt)
                        {
                            iLost = (index-oldindex) > 0 ? index-oldindex : oldindex-index;
                            g_arryInfo[dwIndex].err_packets += iLost;  
                        }
                        oldindex = index;
                    }  
                }

                if (g_arryInfo[dwIndex].cut_rtp_header && g_arryInfo[dwIndex].is_rtp)
                {
                    if (SOCKET_ERROR ==
                            sendto (g_arryInfo[dwIndex].send_socket,
                                    buf + 12,
                                    cbRet - 12,
                                    0,
                                    (const struct sockaddr FAR *)s6->ai_addr,
                                    s6->ai_addrlen))
                    {
                        goto end;
                    }
                }
                else
                {
                    if (SOCKET_ERROR ==
                            sendto (g_arryInfo[dwIndex].send_socket,
                                    buf,
                                    cbRet,
                                    0,
                                    (const struct sockaddr FAR *)s6->ai_addr,
                                    s6->ai_addrlen))
                    {
                        goto end;
                    }
                }
                if(bFirstPkt)
                {
                    bFirstPkt = FALSE;
                }

                g_arryInfo[dwIndex].recvd_bytes += cbRet;
                dwTime2 = GetTickCount();
                if(dwTime2 - dwTime1 >= 1000)
                {  
                    dwTime1 = dwTime2;
                    g_arryInfo[dwIndex].bit_rate = (g_arryInfo[dwIndex].recvd_bytes -
                        last_second_bytes) / 128;
                    last_second_bytes = g_arryInfo[dwIndex].recvd_bytes;

                    g_arryInfo[dwIndex].packet_rate = g_arryInfo[dwIndex].recvd_packets -
                        last_second_packets;
                    last_second_packets = g_arryInfo[dwIndex].recvd_packets;

                    if (g_arryInfo[dwIndex].packet_rate > 1)
                    {
                        g_arryInfo[dwIndex].err_rate = 100.0* (g_arryInfo[dwIndex].err_packets -
                        last_second_err_packets) / g_arryInfo[dwIndex].packet_rate;
                    }
                    else
                    {
                        g_arryInfo[dwIndex].err_rate = 0.0;
                    }
                    last_second_err_packets = g_arryInfo[dwIndex].err_packets;
                   
                }

            }

        end:
            if (g_arryInfo[dwIndex].status != status_stopping)
            {
                // error exit
                g_arryInfo[dwIndex].status = status_error;
            }
            else
            {
                g_arryInfo[dwIndex].status = status_stop;
            }
            g_arryInfo[dwIndex].err_packets = g_arryInfo[dwIndex].recvd_packets = g_arryInfo[dwIndex].recvd_bytes = 0;
            g_arryInfo[dwIndex].bit_rate = g_arryInfo[dwIndex].err_rate = g_arryInfo[dwIndex].packet_rate = 0;
            closesocket (g_arryInfo[dwIndex].recv_socket);
            closesocket (g_arryInfo[dwIndex].send_socket);
            return 0;
        }

        运行的样子

        完整代码就不给出来了,这里有可执行程序的下载:  ipv5

    ————————————————————————
    作者: roger
    Blog: http://rogerfd.cn
    Email:roger99707@163.com
    本文欢迎转载和引用,请保留本说明并注明出处
    ————————————————————————

    kaida Work 1,125 views

    Joke一则:取经

    2009年3月17日

    唐僧师徒历经九九八十一难,终于见到了如来佛求取真经.

    如来问:“你们带U盘了么?”

    唐僧师徒: no

    如来又问:“移动硬盘呢?”

    唐僧师徒: no

    如来继续问:“ IPOD也可以哇”

    唐僧师徒: no

    如来叹了口气:“那你们就原路回去吧,我用QQ传给你们

    唐僧: ,早知道加你QQ就完了,老子还走这么远干嘛啊.

    如来的回应道:“你们以为要加就加啊,我经常隐身滴! 最后,如来还来句:你们有没
    psp啊?

    唐僧:…….

    如来: 那这么远的路,你们是怎么娱乐的?

    唐僧师徒:打怪升级

    后续:

    唐僧回去加了如来QQ

    传数据中..

    如来:怎么这么慢呢,你什么网啊?

    唐僧:校园网。。。

    如来: 。。。你再来一趟吧

    kaida 未分类 779 views