Socket的双网卡收发(C#)

最近的一个项目中需要同时使用两块网卡收发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();
}
时间: 2024-11-05 02:40:10

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

linux 服务器双网卡绑定

1.首先关闭NetworkManager服务 [[email protected] ~]# service NetworkManager stop [[email protected] ~]# chkconfig NetworkManager off 2.配置网卡一 [[email protected] ~]# vi ifcfg-eth0  DEVICE=eth0  ONBOOT=yes  BOOTPROTO=none  USERCTL=no  MASTER=bond0  SLAVE=yes 3

Centos 6.5 64位双网卡绑定

1.环境描述      我的Vmware workstation 10 安装Centos 6.5 64位加上双口的Intel千兆网卡,通过ifconfig -a|grep eth命令看到eth2和eth3两张网卡. 2.双网卡绑定步骤: 2.1 修改/etc/sysconfig/network-scripts/ifcfg-eth2配置文档,修改后的内容如下:    DEVICE=eth2       ONBOOT=yes              #系统启动时自动启用该设备    BOOTPRO

Linux 双网卡(内外网) 同时使用路由设置

好久没有更新博客了,罪过罪过,另外发现最近有些网站老是盗用我开源中国博客内容,鄙视! 正题: 公司业务需求,一台服务器,双网卡,需要同时访问外网和内网.在设置过程中,同事反映原本好用的内网地址(192.168.1.100)在设置上外网地址后变的不好用,只要停止外网那个网卡内网就可以正常访问了. 其实是因为,你先设置了内网之后,又设置外网,在给外网设置了网关之后,由于没有设置默认网关,导致,内网的IP也会走外网的网关,肯定是不可以的.我们要做的仅仅是让内网走自己的网卡 内网网卡:eth0 192.

LINUX 双网卡绑定

cd /etc/sysconfig/network-scripts cp ifcfg-eth0  bak.ifcfg-eth0 cp ifcfg-eth1  bak.ifcfg-eth1 vi ifcfg-bond0 DEVICE=bond0 BROADCAST=192.168.190.255 IPADDR=192.168.190.11 NETMASK=255.255.255.0 GATEWAY=192.168.190.1 ONBOOT=yes USERCTL=no BOOTPROTO=none

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

本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 前几天给一个客户做远程项目实施,客户那边的服务器是Windows OS的,我们这边的业务运行需要linux OS,所以就在Windows OS下安装VMWare. 但是在配置VM的IP地址时,遇到了双网卡配置IP地址的问题.宿主机是双网卡,一块网卡连接内网,一块网卡连接外网. 经过摸索终于把在VMWare上VM双网卡配置IP地址的事情搞定了,下面记录大致的配置过程. PS:VM的两块网

微软Azure公有云之企业Exchange 2016部署6—创建双网卡VM

本节我们来创建第一台邮件服务器,如下图所示: 为了使DAG复制数据和邮箱MAPI数据分开,我们这里配置双网卡.虽然在Exchange2016. 2013版本中,双网卡并不是微软所建议必须配备的. 但复制数据和MAPI数据分开有以下好处: a. 这可以提供网络和网络路径的冗余,使系统能够区分服务器故障和网络故障.使用单个网络适配器会阻碍系统区分这两种类型的故障. b. 如果故障影响 MAPI 网络,将发生服务器故障转移(假定可以激活健康的邮箱数据库副本). c. 在故障影响复制网络时,如果 MAP

Linux双网卡绑定和解除绑定的实现

? 双网卡绑定实现就是使用两块网卡虚拟成为一块网卡,这个聚合起来的设备看起来是一个单独的以太网接口设备,通俗点讲就是两块网卡具有相同的IP地址而并行链接聚合成一个逻辑链路工作.根据交换机可支持的功能不同,最常见的是设定为主备方式的双网卡绑定.Linux双网卡绑定和解除绑定的实现

双网卡绑定

双网卡绑定好处: 1:实现网络容错(主备模式 , 主主模式) 2:  带宽绑定 在windows   server  2012之前系统必须利用服务器商家提供的软件,windows   server  2012之后,操作系统自身可以实现双网卡绑定 准备条件:2块网卡 步骤: 1:打开服务器管理器-本地服务器-NIC组合 点击任务-新建组 选中要绑定的网卡-其他属性的成组模式改成静态成组 打开网络连接,出现新的虚拟网卡,点击右键-配置ip地址,首选dns指向server01ip地址 3:测试 (测试

双网卡,内网,外网同时上网的设置

网卡配置: ======== Wan: IP: 自动获取IP地址 LAN: IP: 10.203.168.222子网掩码:255.255.225.0默认网关: 空 注意:   内部网的网卡IP配好后,设网关设置为空(即不设网关)   只设IP地址和子网掩码 --------------------------------- 1. route delete 0.0.0.0 删除0.0.0.0这条路由,因为接了两个网段有那个0.0.0.0的路由, 会发生冲突,数据包不知道该往哪边发,即使偶尔能上网,