最近的一个项目中需要同时使用两块网卡收发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. Android WebRTC 音视频开发总结(四)-- webrtc传输模块

    在介绍WebRTC通讯之前我们先来看一个P2P视频聊天包括的主要过程,转载请说明出处(博客园RTC.Blacker): 音视频数据采集->编码->发送->接收->解码-> ...

  2. Unable to add App ID because the '10' App ID limit in '7' days has been exceeded.

    Unable to add App ID because the '10' App ID limit in '7' days has been exceeded. 官方的原因是对bundle iden ...

  3. 移植u-boot-1.1.6(原创)

    #u-boot:u-boot-1.1.6#server:ubuntu 12.04#gcc: arm-linux-gcc -4.3.2# 一.建立单板1> /board/smdk2410 : cp ...

  4. Linux 64位编译\链接32位程序

    测试机器:Ubuntu14.04 64位 gcc编译32位程序,添加参数-m32: $ gcc -c -fno-builtin -m32 TinyHelloWorld.c ld链接32位代码,添加参数 ...

  5. GitHub 里面有大量优秀的第三方框架

    写iOS 程序的时候往往需要很多第三方框架的支持,可以大大减少工作量,讲重点放在软件本身的逻辑实现上. GitHub 里面有大量优秀的第三方框架,而且 License 对商业很友好.一下摘录一下几乎每 ...

  6. 使用DBCP时发生AbstractMethodError异常

    使用DBCP时发生AbstractMethodError异常,错误描述: Exception in thread "main" java.lang.AbstractMethodEr ...

  7. PHP 文件上传服务端及客户端配置参数说明

    文件上传服务器端配置: ·file_uploads = On, 支持HTTP上传 ·upload_tmp_dir = , 临时文件保存的目录 ·upload_max_filesize=2M, 允许上传 ...

  8. php中iconv函数使用方法

    最近在做一个程序,需要用到iconv函数把抓取来过的utf-8编码的页面转成gb2312, 发现只有用iconv函数把抓取过来的数据一转码数据就会无缘无故的少一些. iconv函数库能够完成各种字符集 ...

  9. map与set的遍历

    map有四种方式: 1.直接遍历 keySet 2.使用Iterator //注意next放回的对象是map.Entry<K,V>,而使用的iterator是通过entrySet返回的一个 ...

  10. Ksoap2 获取webservice返回值的getResponse() 出现的问题

    今天写了一个判断记录重复的webservcie 返回布尔类型 // 判断序列号在数据库是否重复 public static boolean isSerialNumExist(String serial ...