C# UDP通信 外网回发数据包给内网问题

roy1989 2012-03-13 09:27:39
请教下各位大哥,昨天的问题已经解决了~今天的问题如下:
现在用C#开发了一个C/S架构的UDP通信程序,在内网IP:192.168.1.2放置了客户端,开启本地IP监听,经过路由器,向外网的服务器端发送消息。外网的服务器端具有公网IP:180.169.48.140,服务器端已经开启了监听。现在的情况是,内网客户端发出去的数据包,外网服务器端能够收到,但是要求服务器端收到数据之后给出一个回复,并返回至内网客户端。现在的问题就在于,内网的客户端收不到回来的数据,主要集中有以下几个疑惑,请各位大哥指导~
1、外网的服务器如何获取内网客户端发出去的数据包,在经过路由器中转之后,对外的IP地址和端口?
2、如何在服务器端开启多端口监听?
3、服务器端如何发送数据回来,到达路由器之后,回到客户端?

相关代码如下:
IPEndPoint address = new IPEndPoint(IPAddress.Any, int.Parse("4321"));//client
//窗体初始化的时候开始监听UDP端口,监听所有IP地址来的信息,这边有个问题就是如何监听所有端口,不知是否可行?
udp = new UdpClient(address);
Thread thread = new Thread(new ThreadStart(RecieveData));//开启线程接收数据
thread.Start();
MessageBox.Show("监听开启");
SendMessage("time" + "IP地址:" + IpArray[0]);//发送数据,这边原来的想法是把本地IP地址,例如192.168.1.2发出去,在服务器端做截取用于回发,但是外网发回数据的时候,需要知道内网的出口IP,所以就无效了……
以上为客户端开启监听部分的代码。


下面是客户端发送数据的代码:
private void SendMessage(string text)
{

IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(IpAdd.Text), int.Parse("1234"));//server ipadd.text 目的IP 1234端口
UdpClient udptmp = new UdpClient();
byte[] buffer = Encoding.UTF8.GetBytes(text);
//这里必须要将IP地址传过去,否则会报错(实例化的时候要IP地址反而会有麻烦)
udptmp.Send(buffer, buffer.Length, remoteEndPoint);

}

服务器端监听开启的代码如下:
IPEndPoint address = new IPEndPoint(IPAddress.Any, int.Parse("1234"));//server
//窗体初始化的时候开始监听UDP端口
udp = new UdpClient(address);
// 启动接收线程
Thread thread = new Thread(new ThreadStart(RecieveData));
thread.Start();
MessageBox.Show("服务器监听已经开启!");

当服务器端收到数据的时候 :

void RecieveDataIn()
{
while (true)
{
// 如果没有使用多线程这里一定要判断是否收到数据,
// 否则在Receive的时候线程会被挂起(直到接收到UDP请求,程序才会继续执行),造成卡死的现象
// 但是我们这是又开了一个线程,所以不需要判断,所以CPU占用率不会至少50%。
// 这里的udp.Available是对应的udp端口所获取的数据的总大小,与TCP方式不同(TCP是当前请求发送数据的大小)
if (udpIn.Available > 0)
{
IPEndPoint ipEndPoint = null;
byte[] buffer = udpIn.Receive(ref ipEndPoint);

string text = Encoding.UTF8.GetString(buffer);
SetTextIn(text);//显示数据
SendMessageAgain("消息收到了");//向内网客户端发送消息确认
}}}

服务器端向客户端回发消息代码:
private void SendMessageAgain(string text)
{


IPEndPoint remoteEndPoint2 = new IPEndPoint(IPAddress.Parse(fromip), int.Parse("4321"));//client 这边的问题就在于,如何获取来源数据包的外网IP和端口,以便回发?
UdpClient udp2 = new UdpClient();
byte[] buffer = Encoding.UTF8.GetBytes(text);
//这里必须要将IP地址传过去,否则会报错(实例化的时候要IP地址反而会有麻烦)
udp2.Send(buffer, buffer.Length, remoteEndPoint2);
udp2.Close();
}

客户端的监听一直在持续,收到消息之后,将消息打印……


...全文
1054 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
mjp1234airen4385 2014-07-25
  • 打赏
  • 举报
回复
如果你的数据是音频、视频类的文件,使用udp是可行的,但是udp不保证通讯可靠性,可能有丢包,顺序乱等问题。 如果是文本、压缩文件、xml等,还是老师使用tcp吧。
lihay2007 2014-07-23
  • 打赏
  • 举报
回复
引用 10 楼 dk385 的回复:
这个问题就是P2P通讯问题,楼主需要了解NAT的穿透技术。 解决的两个方法: 1.学习NAT的穿透技术,打洞穿墙。这个我就不说了,网上一大堆资料。 2.在路由器上设置下,把你客户端的监听端口给映射出去。(这个方法能快速解决问题,但实用性不强)
打洞是不在服务器转发的情况下才需要,楼主的问题跟打洞貌似没关系。
cheeks 2012-08-19
  • 打赏
  • 举报
回复
楼主 ,问题解决了没有,我是给 DTU 回发数据的时候 DTU 老是收不到
zmidl 2012-05-13
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]

也不一定非要穿透,tcp 长连接,来回自如
[/Quote]

这个长连接 可以突破 内网与公网互相连接吗
cnfixit 2012-05-12
  • 打赏
  • 举报
回复
也不一定非要穿透,tcp 长连接,来回自如
zmidl 2012-05-12
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

这个问题就是P2P通讯问题,楼主需要了解NAT的穿透技术。
解决的两个方法:
1.学习NAT的穿透技术,打洞穿墙。这个我就不说了,网上一大堆资料。
2.在路由器上设置下,把你客户端的监听端口给映射出去。(这个方法能快速解决问题,但实用性不强)
[/Quote]
俺网上也搜了都是错误的源代码!
朋友是否可以提供一套完整的穿墙参考呢?
家鸣 2012-03-13
  • 打赏
  • 举报
回复
不过按楼主所说,服务器是在公网上,也用不着打洞,具体做法是,服务端收到客户端的消息后,同时获取到客户端的IP和端口号(即IPEndPoint),往这个IPEndPoint回发数据包即可。因为这时客户端的路由器应该还保留着这个端口映射信息。
家鸣 2012-03-13
  • 打赏
  • 举报
回复
这个问题就是P2P通讯问题,楼主需要了解NAT的穿透技术。
解决的两个方法:
1.学习NAT的穿透技术,打洞穿墙。这个我就不说了,网上一大堆资料。
2.在路由器上设置下,把你客户端的监听端口给映射出去。(这个方法能快速解决问题,但实用性不强)
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 roy1989 的回复:]
嗯呐,关于端口,那就只开一个了,异步处理确实是有必要去实行的~我在网上看到,说这种情况,内网信息发送的端口和接收的端口要是同一个,不懂是否正确?那么服务器端发送的端口和接收的端口是否也需要是同一个端口呢?
[/Quote]

假设服务器端监听8081端口,然后以随机的方式(不特意制定的方式)发送返回消息,可能使用了54321端口,也没有关系。服务器端是“接收和发送的端口”,而不是“发送和接收的端口”。

但是假设按照你说的“内网信息发送”,以NAT方式访问外网,那么当然需要外网把返回消息发送到路由器所使用的外网地址和外网端口上,向别的端口发送返回消息那么路由器也不给转发到内网啊。
roy1989 2012-03-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 sp1234 的回复:]

引用 3 楼 roy1989 的回复:
这边首先把ipEndPoint置空了,所以没想清楚,原来内网发过来的数据包,经过路由器之后的IP和端口要如何获取?


晕!

“置空”之后下一条语句不是就用ref方式取回来值了嘛!
[/Quote]
哦 对……囧了 然后就可以从这个ipEndPoint中读取内网数据包的外网IP和端口 然后再根据这个IP和端口回发到路由器 路由器就会回发到客户端了……使用同一个连接的话 大致明白了 我要再写着试试看~
非常感谢您那么细致的回答 大赞~
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 roy1989 的回复:]
这边首先把ipEndPoint置空了,所以没想清楚,原来内网发过来的数据包,经过路由器之后的IP和端口要如何获取?
[/Quote]

晕!

“置空”之后下一条语句不是就用ref方式取回来值了嘛!
  • 打赏
  • 举报
回复
与tcp短连接不同的是,你需要有更多的协议上的设计。假设一个客户端(单线程或者多线程)先后以udp方式发送了10条消息到服务器,服务器收到它的先后次序并不保证与原来的一致,同时服务器处理之后返回消息的次序也是随机的。因此在设计信令协议时,你应该为每一个消息设计相关的序号,当客户端收到一个消息时假设是服务器的回应那么它就应该找到在发送消息是所挂起的(也就是在内存中保存的)委托来回调它。

udp比较麻烦的是你可能需要处理确认、重发等机制。而tcp则不需要,因为它可以保证这些。

对于tcp长连接与上面也很类似。(考虑基本的性能要求)同一个客户端可能异步发送多个消息,然后服务器可能异步处理,所以服务器发回来的消息一定是跟客户端的次序经常是不同的。设计tcp长连接的客户端,当然也要是异步回调的。

tcp短连接则非常简单,因为每一次访问服务器都是“一问一答”,然后就关闭连接;服务器端则不维系长连接,而是每一次客户端请求当作为一个独立的Accept连接处理。
shashengduguzhe 2012-03-13
  • 打赏
  • 举报
回复
QQ通讯传输就是UDP 呵呵。
roy1989 2012-03-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 sp1234 的回复:]

引用楼主 roy1989 的回复:
现在的情况是,内网客户端发出去的数据包,外网服务器端能够收到,但是要求服务器端收到数据之后给出一个回复,并返回至内网客户端。现在的问题就在于,内网的客户端收不到回来的数据,主要集中有以下几个疑惑,请各位大哥指导~
1、外网的服务器如何获取内网客户端发出去的数据包,在经过路由器中转之后,对外的IP地址和端口?
2、如何在服务器端开启多端口监听?
3、服务……
[/Quote]
感谢您的耐心解答~当服务器收到数据是,做的操作如下:
if (udpIn.Available > 0)
{
IPEndPoint ipEndPoint = null;
byte[] buffer = udpIn.Receive(ref ipEndPoint);

string text = Encoding.UTF8.GetString(buffer);
SetTextIn(text);//显示数据
SendMessageAgain("消息收到了");//向内网客户端发送消息确认
}
这边首先把ipEndPoint置空了,所以没想清楚,原来内网发过来的数据包,经过路由器之后的IP和端口要如何获取?麻烦您稍稍解释一下~
嗯呐,关于端口,那就只开一个了,异步处理确实是有必要去实行的~我在网上看到,说这种情况,内网信息发送的端口和接收的端口要是同一个,不懂是否正确?那么服务器端发送的端口和接收的端口是否也需要是同一个端口呢?
嗯呐 UDP和TCP的区别,这个我是清楚的,TCP的三次握手可以有效防止丢包~因为这次做的东西是根据需求要使用UDP协议的,所以才比较麻烦,再次感谢~
  • 打赏
  • 举报
回复
不要图省事而使用udp。udp通讯是不靠谱的、经常丢失通讯内容,这就像是一些人鼓吹说越是低级的编程方法越能代表你的技术,其实假设你还不靠谱的时候怎么能追求这种不靠谱的低级方法呢?当然要用经过千锤百炼方法。使用tcp可以保证通讯内容正确不丢失,所以至少在你还在学习的时候,应该使用tcp而不是udp。
  • 打赏
  • 举报
回复
[Quote=引用楼主 roy1989 的回复:]
现在的情况是,内网客户端发出去的数据包,外网服务器端能够收到,但是要求服务器端收到数据之后给出一个回复,并返回至内网客户端。现在的问题就在于,内网的客户端收不到回来的数据,主要集中有以下几个疑惑,请各位大哥指导~
1、外网的服务器如何获取内网客户端发出去的数据包,在经过路由器中转之后,对外的IP地址和端口?
2、如何在服务器端开启多端口监听?
3、服务器端如何发送数据回来,到达路由器之后,回到客户端?
[/Quote]

1. 你的ipEndPoint就是。
2. 服务器端没有必要开启多端口。只要一个端口,处理几千个客户端并发也是没有问题的。服务器端尽量使用异步处理,既受到一个消息时不用等处理,就可以开始并行接收下一个消息了。
3. 理论上来说,假设你的客户端也绑定发送端口,并且服务器立刻向ipEndPoint所在的位置返回消息,那么客户端就可以接收到。不过如果你使用tcp(而不是udp),则客户端编程就更加简单,而且可以保证接收到。

110,536

社区成员

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

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

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