最近的一个项目中需要同时使用两块网卡收发UDP组播数据包,并且要求使用Socket的方式接收和发送网络数据包(我不会告诉你们我之前是直接使用SharpPcap来实现的)。在C#中Socket接触的比较早,但是用的不多,特别是在实现本次上网卡的收发过程中也是遇到了不少麻烦。其中最最头疼的就是不能同时接收两张网卡的数据,虽然这个问题不是致命的(大不了用SharpPcap呗!!),但是最为一个21世纪有志青年,怎么能干出这种半吊子的事情呢!于是,这两天我陷入了这个问题无法自拔,当然,最后还是解决了!哈~哈~哈哈哈~~

就在解决问题的那瞬间,眼前忽然出现了一个身影——“啊~~勤劳的(码)农夫啊~~,请问你丢的是这把金斧头呢,还是这…….”,“金斧头!金斧头!”(嘿嘿,把它卖了就能炒股票!赚大钱!出任CEO!迎娶白富美!走向人生巅峰!)

啊~~~呸!呸!呸!其实我想说,良心发现的我还是觉得如果有那么一群人还在纠结这个问题的,那么看看这里,也许能有帮助。(真的!绝对不是来装X的)

问题概述

言归正传,在我的应用中,我主要是想利用C#的Socket来接收组播的UDP数据包。当然,发送也需要,但不是我最关心的问题。因此,我首先想到的就是UdpClient这个类。这个类对Socket进行了很好的封装,用起来更加简单。那么问题来了,我始终只能收到一个网卡上的数据,这是很头疼的。我检查了网络,检查了数据包发现都没问题,但就是只能收到其中一个网卡的数据。

下面是我初始化Socket的代码,该代码为CapDevice类中的一段:

// 定义IPEndPoint
private IPEndPoint localEP = null;
private IPEndPoint remoteEP = null; // 定义UDP发送和接收Socket
//private Socket udpReceive = null;
private UdpClient udpReceive = null;
private UdpClient udpSend = null; // 本机节点
localEP = new IPEndPoint(device, LOCAL_PORT); // 远程节点
remoteEP = new IPEndPoint(IPAddress.Parse(MASTER_IP), DES_PORT); // 实例化
udpReceive = new UdpClient(AddressFamily.InterNetwork);
udpReceive.Client.ReceiveBufferSize = 320000;
udpReceive.Client.Bind(localEP);
udpReceive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpSend = new UdpClient(); // 发送和接收加入组播组
udpReceive.JoinMulticastGroup(IPAddress.Parse(MASTER_TX_GROUP));
udpSend.JoinMulticastGroup(IPAddress.Parse(MASTER_RX_GROUP));

// 打开发送标志位
isOpen = true; // 打开接收线程
cap_thread = new Thread(new ThreadStart(ReceiveLoop));
cap_thread.Start();
cap_thread.Priority = ThreadPriority.Highest;
cap_thread.IsBackground = true;

在使用过程中,我分别实例化了两个CapDevice对象,并且将所需IP和端口信息通过参数传入。

device为本机网卡的IP地址;

LOCAL_PORT为本机侦听端口;

MASTER_IP为待接收的远程设备的IP地址;

DES_PORT为待接收的远程设备的端口;

MASTER_TX_GROUP为接收数据绑定的组;

MASTER_RX_GROUP为发送数据绑定的组;

本人使用台式机开发,主板自带一张千兆网卡,然后外接了一张PCI接口的千兆网卡。在我调试和寻找问题的过程中遇到这样的情况:

1. 两张网卡的IP分别为192.168.30.33和192.168.30.34,33的为主板上的网卡,34的是外接的网卡。按照上述方式进行配置后我发现我永远只能收到33的网卡上的数据,除非我拔掉33的网卡上的网线,并且重新打开接收,此时34的网卡上才会有数据。

2. 我尝试使用同步、异步的方法,并且尝试使用Socket类而不是UdpClient类,但是都没有成功。

因此,我怀疑,即使我的Socket侦听的IP是192.168.30.34,实际Windows还是没有对34这张网卡的数据进行侦听。

问题解决

我花了很多时间去寻找答案,但是结果还是不太对。最终我找到一个讲述跟我一样问题的网站:

http://stackoverflow.com/questions/15265620/udp-read-data-from-all-network-interfaces

提出问题的人也遇到了同样的问题,并且进行了很多尝试。最终他得到的结论是:“把同步接收改成异步接收就行啦!”

我试了一下,发现问题不在那里,还是没有。但是我发现一个地方,那就是加入组的时候他们使用的JoinMulticastGroup函数有两个参数,然后我这么改了:

udpReceive.JoinMulticastGroup(IPAddress.Parse(MASTER_TX_GROUP), localEP.Address);

恩,其实看了这么多,我就想说这个,真不好意思,浪费大家这么多时间看废话,嘻嘻!!

第二个参数是本地地址,真正能够让我的第二张网卡也能够接收数据的也是这个参数,看来第二个参数才是通知系统将IP与本地网卡建立联系。测试了一下,异步接收和同步接收都没有问题。

总结

问题总结一句话,加入组播组需要使用带本地IP地址的重载函数。当然,写这么多就是想把问题描述清楚一点,同样的问题按照这里所述就能得到解决。如果是其它原因导致Socket通信失败,按照本文所述就不一定能解决咯。

下面是初始化代码(区别就在高亮部分代码):

// 定义IPEndPoint
private IPEndPoint localEP = null;
private IPEndPoint remoteEP = null; // 定义UDP发送和接收Socket
//private Socket udpReceive = null;
private UdpClient udpReceive = null;
private UdpClient udpSend = null; // 本机节点
localEP = new IPEndPoint(device, LOCAL_PORT); // 远程节点
remoteEP = new IPEndPoint(IPAddress.Parse(MASTER_IP), DES_PORT); // 实例化
udpReceive = new UdpClient(AddressFamily.InterNetwork);
udpReceive.Client.ReceiveBufferSize = 320000;
udpReceive.Client.Bind(localEP);
udpReceive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpSend = new UdpClient(); // 发送和接收加入组播组
udpReceive.JoinMulticastGroup(IPAddress.Parse(MASTER_TX_GROUP), localEP.Address);
udpSend.JoinMulticastGroup(IPAddress.Parse(MASTER_RX_GROUP));

// 打开发送标志位
isOpen = true; // 打开接收线程
cap_thread = new Thread(new ThreadStart(ReceiveLoop));
cap_thread.Start();
cap_thread.Priority = ThreadPriority.Highest;
cap_thread.IsBackground = true;

这里顺便把我同步接收线程函数也贴出来吧:

private void ReceiveLoop()
{ byte[] rcvData; while (isOpen)
{
rcvData = udpReceive.Receive(ref remoteEP);
// 解析数据
UploadEndecoder.CapturePkgM(rcvData);
} udpReceive.Close();
udpSend.Close();
}

Socket的双网卡收发(C#)的更多相关文章

  1. CentOS工作内容(六)双网卡带宽绑定bind teaming

    CentOS工作内容(六)双网卡带宽绑定bind  teaming Teaming功能是什么功能http://zhidao.baidu.com/link?url=cpcwl9LH4FSHJBaTW-e ...

  2. 烂泥:VMWare Workation双网卡配置IP地址

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 前几天给一个客户做远程项目实施,客户那边的服务器是Windows OS的,我们这边的业务 ...

  3. Linux下双网卡绑定bond0

    一:原理: linux操作系统下双网卡绑定有七种模式.现在一般的企业都会使用双网卡接入,这样既能添加网络带宽,同时又能做相应的冗余,可以说是好处多多.而一般企业都会使用linux操作系统下自带的网卡绑 ...

  4. Linux 双网卡绑定

    Linux 双网卡绑定 Linux 双网卡绑定双网卡绑定的常用模式:mode1:active-backup 模式,即主备模式.mode0:round-broin 模式,即负载均衡模式(需要交换机配置聚 ...

  5. Windows Server 2008 双网卡同时上内外网 不能正常使用

    Windows server 2008 32位下,双网卡同时上内外网,并提供VPN服务,遇见的奇怪问题 1.服务器配置 2.网络配置 以太网适配器 内部连接: 连接特定的 DNS 后缀 . . . . ...

  6. CentOS 7使用nmcli配置双网卡聚合

    进入CentOS 7以后,网络方面变化比较大,例如eth0不见了,ifconfig不见了,其原因是网络服务全部都由NetworkManager管理了,下面记录下今天下午用nmcli配置的网卡聚合,网络 ...

  7. VirtualBox双网卡搭建Linux虚拟实验环境

    VirtualBox中有如下几种网络连接方式: NAT(NAT到宿主机IP地址) NAT Network (NAT到宿主机所在的网段,即使用相同的网关和掩码) Bridged Adapter Inte ...

  8. ubuntu 双线双网卡双IP实现方式

    昨天金桥机房上架了一台多玩的测试机,系统是ubuntu9.04 X64的系统,母机IBM X336机器.用户需求是双线,故采用一个网卡配置电信地址,另一个网卡配置联通地址,安装好系统后配置好IP发现联 ...

  9. (转)深度分析Linux下双网卡绑定七种模式

    现在一般的企业都会 使用双网卡接入,这样既能添加网络带宽,同时又能做相应的冗余,可以说是好处多多.而一般企业都会使用linux操作系统下自带的网卡绑定模式,当然现在 网卡产商也会出一些针对window ...

随机推荐

  1. 一步一图:从SQLSERVER2005中导出insert语句

    1.为什么要导出insert语句,我电脑装的是SQL Server Express免费版的,服务器上装的是正式版,在服务器上备份的数据库文件在本机上还原的时候 因为版本不一样,总是不成功.如果能直接使 ...

  2. Linux下CPU占用率高分析方法

    一般解决方法是通过top命令找出消耗资源高的线程id,利用strace命令查看该线程所有系统调用1. 通过top命令找到可疑进程PID top - 09:37:18 up 70 days, 16:29 ...

  3. c# 数据库操作学习

    一. 如何处理数据库连接 1. 数据库连接可以分为“物理连接”和“逻辑连接”(默认使用连接池的情况下Pooling=true): 物理连接:创建数据库连接时,默认会有一定数量的物理连接(默认Min P ...

  4. SQL中删除某数据库所有trigger及sp

    SQL中删除某数据库所有trigger及sp   编写人:CC阿爸 2014-6-14 在日常SQL数据库的操作中,如何快速的删除所有trigger及sp呢 以下有三种方式可快速处理. --第一种 - ...

  5. 在 PHP 中结合 Ajax 技术进行图片上传

    前面几则日志中讲述了在 PHP 中上传文件,相信大家对 PHP 中如何进行文件上传已经初步掌握.本文来继续探讨在 PHP 中上传文件的技术,不同的是,本次上传将仅限于图片文件的上传,并且将采用 Aja ...

  6. 怎样使android的view动画循环弹动

    在res中建立文件夹anim,分别写下cycles.xml,shake1.xml,shake2.xml cycles.xml: <?xml version="1.0" enc ...

  7. 【转】资源文件在Delphi编程中的应用

    段东宁 计亚南 (郴州职业技术学院, 湖南 郴州  423000) 摘要: 资源文件是一种能有效地组织.管理和使用资源的文件形式,在软件开发中有着广泛的应用.本文详细介绍了在Delphi编程中资源文件 ...

  8. 使用WIF实现单点登录Part I——Windows Identity Foundation介绍及环境搭建

    首先先说一下什么是WIF(Windows Identity Foundation).由于各种历史原因,身份验证和标识的管理一般都比较无规律可循.在软件里加入“身份验证”功能意味着要在你的代码里混进处理 ...

  9. web开发中,前端javascript代码的组织结构

    网页包含三个层次: 结构(HTML) 表现(CSS) 行为(javascript) web标准中,三者要分离,网页源代码由三部分组成:.html文件..css文件和.js文件.就是说html文件中不应 ...

  10. char const*, char*const, const char *const的区别

    C++标准规定,const关键字放在类型或变量名之前等价的.所以,const char*和 char const*是一样的. const char*   //常量指针---指向常量的指针----指针指 ...