C#UDP点对多通信不能同时收到数据,点对点时运行没问题。

ygb1103 2015-05-22 04:00:38
之前我做的是点对点的电脑和设备通信可以通信(每个点收到我发的数据就会立即回复它的数据),UDP通信参照的方法是http://my.oschina.net/Tsybius2014/blog/351974。现在需要让电脑和多个这样的设备通信,于是我按照原来的方法增加了一个UDP通信,代码如下。
现在的问题是我定时器发送数据到两个点(这时候我一直监听两个接收端口),用两个线程接收,不能保证能收到两个的数据,有时候一直接收到1号的,2号的一直没有(偶尔一起接收到),后来有可能是一直接收到2号的,1号的不来了(偶尔一起接收到)。但是我只监听一个的话,就很正常,感觉就是两个一起监听,数据一起来接收的时候就出现上述情况。(我的发送没有问题,测试都能发出去。我把发送和接收端口都分开的


//********************发送数据用定时器实现,每5秒触发一次。

/// <summary>
/// 自动发送计时器
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void autoSendTimer1_Tick(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtSendMssg.Text))
{
MessageBox.Show("请先输入待发送内容");
return;
}
string message = txtSendMssg.Text;
byte[] sendbytes = Encoding.ASCII.GetBytes(message);

IPEndPoint remoteIpep1 = new IPEndPoint(
IPAddress.Parse("192.168.1.241"), 60001); // 发送到的IP地址和端口号****************************************
try
{
udpcSend1.Send(sendbytes, sendbytes.Length, remoteIpep1);
}
catch
{ }
}
int count = 0;
private void autoSendTimer2_Tick(object sender, EventArgs e)
{
string message = txtSendMssg.Text;
byte[] sendbytes = Encoding.ASCII.GetBytes(message);

IPEndPoint remoteIpep2 = new IPEndPoint(
IPAddress.Parse("192.168.1.242"), 60002);// 发送到的IP地址和端口号****************************************
try
{
udpcSend2.Send(sendbytes, sendbytes.Length, remoteIpep2);
count = count + 1;//计数用于检验接收到数据的次数
textBox10.Text = Convert.ToString(count);
}
catch
{ }
}
//***************************************接收数据,用两个线程分别接受
/// <summary>
/// 开关:在监听UDP报文阶段为true,否则为false
/// </summary>
bool IsUdpcRecvStart = false;
bool IsUdpcRecvStart2 = false;
/// <summary>
/// 线程:不断监听UDP报文
/// </summary>
Thread thrRecv1;
Thread thrRecv2;

/// <summary>
/// 按钮:接收数据开关
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRecv1_Click(object sender, EventArgs e)
{
if (!IsUdpcRecvStart) // 未监听的情况,开始监听
{
try
{
IPEndPoint localIpep1 = new IPEndPoint(
IPAddress.Parse(textBox11.Text), 10001); // 本机IP和监听端口号*****************************
//设置接收UDP监听
if (udpcRecv1 == null)
udpcRecv1 = new UdpClient(localIpep1);

IPEndPoint localIpep2 = new IPEndPoint(
IPAddress.Parse(textBox11.Text), 10100); // 本机IP,指定的发送端口号***********************************

//设置发送udp套接字
if (udpcSend1 == null)
{
udpcSend1 = new UdpClient(localIpep2);
}

}
catch{}
thrRecv1 = new Thread(ReceiveMessage1);
thrRecv1.Start();
IsUdpcRecvStart = true;
}
else // 正在监听的情况,终止监听
{
if (thrRecv1 != null)
thrRecv1.Abort(); // 必须先关闭这个线程,否则会异常

udpcRecv1.Close();
udpcRecv1 = null;
udpcSend1.Close();
udpcSend1 = null;

IsUdpcRecvStart = false;
}
}

private void btnRecv2_Click(object sender, EventArgs e)
{
if (!IsUdpcRecvStart2) // 未监听的情况,开始监听
{
try
{

IPEndPoint localIpep3 = new IPEndPoint(
IPAddress.Parse(textBox11.Text), 10002); // 本机IP和监听端口号*****************************
//设置接收UDP监听
if (udpcRecv2 == null)
udpcRecv2 = new UdpClient(localIpep3);

IPEndPoint localIpep4 = new IPEndPoint(
IPAddress.Parse(textBox11.Text), 10101);
//设置发送udp套接字

if (udpcSend2 == null)
{
udpcSend2 = new UdpClient(localIpep4);
}
}
catch{}
thrRecv2 = new Thread(ReceiveMessage2);
thrRecv2.Start();
IsUdpcRecvStart2 = true;
}
else // 正在监听的情况,终止监听
{

if (thrRecv2 != null)
thrRecv2.Abort();

udpcRecv2.Close();
udpcRecv2 = null;
udpcSend2.Close();
udpcSend2 = null;
IsUdpcRecvStart2 = false;
}
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="obj"></param>
private void ReceiveMessage1(object obj)
{
IPEndPoint remoteIpep1 = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] bytRecv1 = udpcRecv1.Receive(ref remoteIpep1);
//后面就是数据处理绘图了
}
}
private void ReceiveMessage2(object obj)
{
IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
byte[] bytRecv = udpcRecv.Receive(ref remoteIpep);
//后面就是数据处理绘图了
}
}
...全文
363 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
ygb1103 2015-05-24
  • 打赏
  • 举报
回复
引用 9 楼 xuzuning 的回复:
首先,同时发送,也不会同时到达 网卡在发送数据报的时候是将报自己的包放在线路中有报的间隔中的 就好比你的汽车要上路,必须等待能容纳你的车空隙出现时,才能加入整个车流 而每辆车都是可以唯一识别的,不会张冠李戴 所以程序在收到数据包时,是有函数获取来源ip的。不可能混淆 实在不放心,你也可以显式的在数据中加入标识宿主的关键字
嗯嗯,谢谢版主,讲得很形象,也很容易理解。我后面再试一试在同一个端口接收,如果可以的话,接可以不用开那么多端口和线程了。
ygb1103 2015-05-23
  • 打赏
  • 举报
回复
引用 7 楼 xuzuning 的回复:
TCP/IP 是点对点通讯协议,发送方在发出一个包以后会等待接收方的信息返回,以确定本次发送是否成功。如不成功则会重发 UDP 是无连接通讯协议,发送时并不去验证接收方是否存在,更无从知道接收方是否正确的接收到数据了 你只有一块网卡,所以任何瞬间都只能处理一个来源地发送的数据。只不过当有多个来源地同时发送时,用于数据包很小,处理起来非常快。使串行的数据传输让人感觉是并行的而已 对一个端口,只需要有一个监听就可以了 如果你要构建多个监听,那应该是监听不同的端口 在你的程序里,依然是两对点对点通讯了,那为何不采用可靠性更高的 TCP/IP 呢?
如果我只侦听一个端口,2个点的数据都发到该端口,对数据处理不是很方便(也担心同时到达时会不会在端口上出错),于是我就用不同端口来区分数据。我到后面要实现一个电脑对9个点收发数据,预计也是要侦听9个端口,你有什么建议优化吗?希望指导指导。 至于用UDP,是因为我要通信的设备用的是UDP,而且UDP不用建立连接,实现起来比较方便。
xuzuning 2015-05-23
  • 打赏
  • 举报
回复
TCP/IP 是点对点通讯协议,发送方在发出一个包以后会等待接收方的信息返回,以确定本次发送是否成功。如不成功则会重发 UDP 是无连接通讯协议,发送时并不去验证接收方是否存在,更无从知道接收方是否正确的接收到数据了 你只有一块网卡,所以任何瞬间都只能处理一个来源地发送的数据。只不过当有多个来源地同时发送时,用于数据包很小,处理起来非常快。使串行的数据传输让人感觉是并行的而已 对一个端口,只需要有一个监听就可以了 如果你要构建多个监听,那应该是监听不同的端口 在你的程序里,依然是两对点对点通讯了,那为何不采用可靠性更高的 TCP/IP 呢?
xuzuning 2015-05-23
  • 打赏
  • 举报
回复
首先,同时发送,也不会同时到达 网卡在发送数据报的时候是将报自己的包放在线路中有报的间隔中的 就好比你的汽车要上路,必须等待能容纳你的车空隙出现时,才能加入整个车流 而每辆车都是可以唯一识别的,不会张冠李戴 所以程序在收到数据包时,是有函数获取来源ip的。不可能混淆 实在不放心,你也可以显式的在数据中加入标识宿主的关键字
ygb1103 2015-05-22
  • 打赏
  • 举报
回复
引用 2 楼 sp1234 的回复:
其它方面,你描述的比较少,就很难判断了。比如说,虽然你将 bytRecv1 和 bytRecv分开了,但是后边的”数据处理绘图“才做有没有什么冲突就不知道了,也不知道你是根据什么来跟踪记录”是否收到消息“的(记录位置的准确性也会影响你的判断)。这是影响之一。 你的程序的要监听两个客户,就要占用两个线程在那里死循环,那么要是监听1万个客户连接可怎么办呢?难道要1万个线程死循环?这种滥用线程的结果也会影响通讯程序程序的资源、并发性和可靠性。
我也试过只在一个接收里面绘图,另外一个的绘图屏蔽了,感觉也会出现很大的丢包。至于记录丢包情况(只跟踪了2号设备的):我是在38行发送定时器2里面用count1记录发送个数,在接收2里面161行后面用count2记录收到的(这个没贴出来)。 对UDP通信了解的不多,用了两个线程完全是根据网页链接参考程序改写的,没考虑到会有什么影响,但我要怎么判断是不是问题出在用了两个线程上呢?还希望指导指导。
ygb1103 2015-05-22
  • 打赏
  • 举报
回复
引用 1 楼 sp1234 的回复:
用一个端口、两个端口、10万个端口收发消息,这没有什么差别。实际上你是用一个端口就可以了,没有必要用多个端口。 主要是你在”并发“发送。而udp本来就是不可靠的,可以随时丢掉消息。你在个人的、只有一个人的、慢速的、顺序的,总之是比较”理想化“的情况下的所谓”都很正常“,这是不可靠的说法,因为的代码本身就没有额外写上一大堆可靠性的逻辑(例如不断重发、二次验证等等)。udp经常丢包才是正常的。
我才开始是一个端口发送,一个接收。但是在接收的时候没有区分开两个设备的数据,也没想其他方法了,就直接分开接收。后来出现我帖子所说的问题,我以为在一个函数里面先后发 没有发出去,我又把发送分开了。现在的情况是这个丢包率太大了,有点影响数据的处理,怎么能够有效避免这个问题呢。
ygb1103 2015-05-22
  • 打赏
  • 举报
回复
引用 3 楼 Z65443344 的回复:
IPAddress.Parse("192.168.1.241"), 60001) 不要这样写 你应该用IPAddress.Any,接收来自任何IP的数据包,而不是2个UDP对象各只接收来自其中1个IP的数据包 你接收到数据包之后,是有属性标明哪个IP哪个端口发送来的.
在代码148行我接收是用IPEndPoint remoteIpep1 = new IPEndPoint(IPAddress.Any, 0); 我想确认下我两个接收都是这样写应该没问题吧,会不会对接收带来干扰。
於黾 2015-05-22
  • 打赏
  • 举报
回复
IPAddress.Parse("192.168.1.241"), 60001) 不要这样写 你应该用IPAddress.Any,接收来自任何IP的数据包,而不是2个UDP对象各只接收来自其中1个IP的数据包 你接收到数据包之后,是有属性标明哪个IP哪个端口发送来的.
  • 打赏
  • 举报
回复
其它方面,你描述的比较少,就很难判断了。比如说,虽然你将 bytRecv1 和 bytRecv分开了,但是后边的”数据处理绘图“才做有没有什么冲突就不知道了,也不知道你是根据什么来跟踪记录”是否收到消息“的(记录位置的准确性也会影响你的判断)。这是影响之一。 你的程序的要监听两个客户,就要占用两个线程在那里死循环,那么要是监听1万个客户连接可怎么办呢?难道要1万个线程死循环?这种滥用线程的结果也会影响通讯程序程序的资源、并发性和可靠性。
  • 打赏
  • 举报
回复
用一个端口、两个端口、10万个端口收发消息,这没有什么差别。实际上你是用一个端口就可以了,没有必要用多个端口。 主要是你在”并发“发送。而udp本来就是不可靠的,可以随时丢掉消息。你在个人的、只有一个人的、慢速的、顺序的,总之是比较”理想化“的情况下的所谓”都很正常“,这是不可靠的说法,因为的代码本身就没有额外写上一大堆可靠性的逻辑(例如不断重发、二次验证等等)。udp经常丢包才是正常的。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧