C# UDP编程 udpClient.Receive(ref remoteIpEndPoint)不能接收数据

风一样De少年 2017-02-19 10:03:46
我在学习UDP编程的时候遇到个奇葩问题,代码中使用udpClient.Receive(ref remoteIpEndPoint)接收数据,运行状态下不能接收数据,但是在调试状态下就能接收到数据,请问哪位朋友知道是什么问题呢?已经被这个问题困扰几天了,真心求助~
以下是主要代码:
 class Program
{
static void Main(string[] args)
{
UdpManager udpManager = new UdpManager();
udpManager.receiveMsg();
}
}
UdpManager类:
private UdpClient udpClient;
private IPAddress remoteIpAddress;
private string remoteIp;
private int localPort;
public UdpManager() : this(Config.REMOTE_IP, Config.LOCAL_PORT) { }
public UdpManager(string remoteIp, int localPort)
{
this.localPort = localPort;
this.remoteIp = remoteIp;
remoteIpAddress = IPAddress.Parse(remoteIp);
IPEndPoint localIpEndPoint = new IPEndPoint(IPAddress.Parse(Config.LOCAT_IP), localPort);
udpClient = new UdpClient(localIpEndPoint);
}
public void receiveMsg()
{
Console.WriteLine("1...");
IPEndPoint remoteIpEndPoint = new IPEndPoint(remoteIpAddress, 0);
while (true)
{
Console.WriteLine("2...");
try
{
byte[] receiveBytes = udpClient.Receive(ref remoteIpEndPoint);
interpretingData(receiveBytes);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("3...");
}
}
...全文
961 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
Alvin.Liang 2019-03-07
  • 打赏
  • 举报
回复
@风一样De少年,请问如何解决呢? 我也是遇到“调试的时候可以收到数据,运行的时候就收不到”。Wireshark显示电脑能收到正确的udp包,但是运行的时候程序一点反应都没有……
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
引用 5 楼 xuggzu 的回复:
很有可能是接收数据太快,造成输出界面假死。建议用线程接收数据,输出使用委托方式。
感谢您的回复,我之前也开过线程运行,然后将数据写入文件中,不过也是一样的情况,文件中也没有数据,然后调试的时候就没问题
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
引用 4 楼 sp1234 的回复:
正常情况下,要避免死循环。 你的代码只是刚学、用来demo语法,那么如果要死循环,就要放到子线程中去。主程序应该pending等待用户录入,不要卡死。
感谢您的回复,我之前也用过异步的方法,也开过线程单独运行,不过最后还是一样的情况。。。
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
引用 3 楼 Yokeqi 的回复:
看代码我能想到的是服务端跟客户端启动顺序的问题。就是服务端发消息过来的时候你客户端还没有开始ReceiveMessage。你可以往这个方向去尝试下看,写点日志什么的。Debug.Writeline写日志到输出窗口
感谢您的回答,顺序没有问题,服务器端一直在发送数据,而且我调试的时候是能获取数据的
xuggzu 2017-02-19
  • 打赏
  • 举报
回复
很有可能是接收数据太快,造成输出界面假死。建议用线程接收数据,输出使用委托方式。
  • 打赏
  • 举报
回复
正常情况下,要避免死循环。 你的代码只是刚学、用来demo语法,那么如果要死循环,就要放到子线程中去。主程序应该pending等待用户录入,不要卡死。
枫0子K 2017-02-19
  • 打赏
  • 举报
回复
看代码我能想到的是服务端跟客户端启动顺序的问题。就是服务端发消息过来的时候你客户端还没有开始ReceiveMessage。你可以往这个方向去尝试下看,写点日志什么的。Debug.Writeline写日志到输出窗口
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
求助。。。。
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
大神们,help!!!!!
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
问题已经解决了,谢谢大家!
风一样De少年 2017-02-19
  • 打赏
  • 举报
回复
引用 9 楼 shingoscar 的回复:
很常见的丢包了吧
不是这个原因,谢谢您的回复
Poopaye 2017-02-19
  • 打赏
  • 举报
回复
很常见的丢包了吧
写完单机版http://blog.csdn.net/xiaoxiao108/archive/2010/12/18/6084473.aspx游戏后 再写个网络版玩玩。 开发工具vs2008 网络版实现方法很简单 1.一个服务端,多个客户端 2.服务端开个端口监听,当一个客户端程序后连接到服务端后,服务端分配个编号给客户端作为他的坦克编号 3.当有新坦克创建,坦克移动,等操作时,客户端发送数据到服务端,服务端再把数据发送到所有的客户端来实现网络游戏的同步 具体实现代码 1.服务端开启服务代码 public void Start() { //开启udp线程 Thread t = new Thread(UDPThread); t.IsBackground = true; t.Start(); //开启tcp服务 TcpListener tl = new TcpListener(TCP_PORT); tl.Start(); while (true) { TcpClient tc = tl.AcceptTcpClient(); Stream ns = tc.GetStream(); BinaryReader br = new BinaryReader(ns); int udpPort = br.ReadInt32();//br.Close();不能关闭br BinaryWriter bw = new BinaryWriter(ns); bw.Write(ID++); IPEndPoint rep = (IPEndPoint)tc.Client.RemoteEndPoint; Client c = new Client(rep.Address.ToString(), udpPort); clients.Add(c); Console.WriteLine("A Client TCP Connect! Addr- " + rep.Address.ToString() + ":" + rep.Port); } } 2.服务端udp数据接收转发代码 private void UDPThread() { Console.WriteLine("UDP thread started at port :" + UDP_PORT); byte[] buf = new byte[1024]; UdpClient uc = new UdpClient(UDP_PORT);//// 跟java有区别 如果这句话放到while外面 就不能接受第二个坦克连入 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0); while (true) { buf = uc.Receive(ref ipep); Console.WriteLine("a udp packet received! from " + ipep.Address + ":" + ipep.Port); //把收到的数据转发给每一个客户端 for (int i = 0; i < clients.Count; i++) { Client c = clients[i]; UdpClient _uc = new UdpClient(); _uc.Connect(c.ip, c.udpPort); _uc.Send(buf, buf.Length); } } } 3.客户端连接代码 public void Connect(string ip, int port) { this.ip = ip; TcpClient client = new TcpClient(); client.Connect(ip, port); Stream ns = client.GetStream(); BinaryWriter bw = new BinaryWriter(ns); bw.Write(udpPort); BinaryReader br = new BinaryReader(ns); //bw.Close();不能关闭bw //从服务器端取到服务器分配的坦克编号 int id = br.ReadInt32(); tc.myTank.ID = id; //编号为偶数的设置为坏蛋 if (id % 2 == 0) tc.myTank.Good = false; else tc.myTank.Good = true; //可以在“输出窗口”看到下面的调试代码 Debug.WriteLine("Connected to server! and server give me a ID:" + id); br.Close(); ns.Close(); client.Close(); TankNewMsg msg = new TankNewMsg(tc.myTank); Send(msg); //开启接收线程 Thread t = new Thread(UDPRecvThread); t.IsBackground = true; t.Start(); } 4.坦克加入消息代码发送代码 public void Send(UdpClient uc, string ip, int udpPort) { uc.Connect(ip, udpPort); //程序中用 | 来分割发送的内容 string str = msgType + "|" + tank.ID + "|" + tank.x + "|" + tank.y + "|" + (int)tank.dir + "|" + tank.Good; uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length); } 5.坦克加入消息解析代码 public void Parse(byte[] b) { string str = Encoding.UTF32.GetString(b); string[] strs = str.Split('|'); int id = Convert.ToInt32(strs[1]); //如果数据包里是自己的坦克不处理 if (id == tc.myTank.ID) { return; } int x = Convert.ToInt32(strs[2]); int y = Convert.ToInt32(strs[3]); Direction dir = (Direction)Convert.ToInt32(strs[4]); bool good = Convert.ToBoolean(strs[5]); Boolean exist = false; for (int i = 0; i < tc.tanks.Count; i++) { Tank t = tc.tanks[i]; if (t.ID == id) { exist = true; break; } } //如果坦克不存在就创建出来 if (!exist) { TankNewMsg msg = new TankNewMsg(tc.myTank); tc.nc.Send(msg); //Tank t = new Tank(x, y, good, tc);//java中是这样写得Tank t = new Tank(x,y,good,dir,tc) Tank t = new Tank(x, y, good, dir, tc); //有可能是老坦克 给新坦克发包 所以要家dir参数 t.ID = id; tc.tanks.Add(t); } } 6.坦克移动消息 public void Send(UdpClient uc, string ip, int udpPort) { uc.Connect(ip, udpPort); //程序中用 | 来分割发送的内容 string str = msgType + "|" + id + "|" + x + "|" + y + "|" + Convert.ToInt32(dir); uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length); } public void Parse(byte[] b) { string str = Encoding.UTF32.GetString(b); string[] strs = str.Split('|'); int id = Convert.ToInt32(strs[1]); //如果数据包里是自己的坦克不处理 if (id == tc.myTank.ID) { return; } int x = Convert.ToInt32(strs[2]); int y = Convert.ToInt32(strs[3]); Direction dir = (Direction)Convert.ToInt32(strs[4]); for (int i = 0; i < tc.tanks.Count; i++) { Tank t = tc.tanks[i]; if (t.ID == id) { t.dir = dir; t.x = x; t.y = y; break; } } } 7.子弹消息处理代码 public void Send(UdpClient uc, string ip, int udpPort) { uc.Connect(ip, udpPort); //程序中用 | 来分割发送的内容 string str = msgType + "|" + m.tankID + "|" + m.x + "|" + m.y + "|" + (int)m.dir + "|" + m.good; uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length); } public void Parse(byte[] b) { string str = Encoding.UTF32.GetString(b); string[] strs = str.Split('|'); int tankID = Convert.ToInt32(strs[1]); if (tankID == tc.myTank.ID) { return; } int x = Convert.ToInt32(strs[2]); int y = Convert.ToInt32(strs[3]); Direction dir = (Direction)Convert.ToInt32(strs[4]); bool good = Convert.ToBoolean(strs[5]); Missile m = new Missile(tankID, x, y, good, dir, tc); tc.missiles.Add(m); } 单机测试时 先运行服务端 再运行多个客户端就ok 多机联网游戏时修改下 nc.Connect("127.0.0.1", 8888);中的ip地址就可以在局域网内玩了 如果连接不上 可以关了防火墙试试看 private void Form1_Load(object sender, EventArgs e) { myTank = new Tank(50, 20, true, this);//放到前面 this不能用 //y轴比java的减少了30 nc = new NetClient(this); nc.Connect("127.0.0.1", 8888); //nc.connect("192.168.1.168",8888); //nc.connect("10.10.10.1",8888); } 如果你发现有什么不合理的,需要改进的地方,联系328452421@qq.com 朱晓 (泰山学院)。相互交流 谢谢
实验三Socket通信实验报告 (1)实验目的和要求 1. 掌握VB、VC++、VS或JAVA等集成开发环境编写网络程序的方法; 2. 掌握客户/服务器(C/S)应用的工作方式; 3. 学习网络中进程之间通信的原理和实现方法; 4. 理解单播、组播和广播的原理并比较其不同之处; 5. 要求本机既是客户端又是服务器端; (2)实验内容 所编写的程序应具有如下功能: 1. 具有点对点通信功能,任意客户端之间能够发送消息; 2. 具有群组通信功能,客户端能够向组内成员同时发送消息,其他组成员不能收到; 3. 具有广播功能,客户端能够向所有其他成员广播消息; (3)编程语言和环境 1. 编程语言C/C++/C#/Java等均可; 2. 编程环境Windows(MS Visual系列,VC/VB/VS.Net;)和Linux(编辑器vi+编译器GCC)均可; (4)实验主要功能实现说明 以下为针对三个实验内容实现方法的简要说明,示例所用语言为C。 基于C的面向连接的socket编程模型 1. 点对点通信功能 实现网络点对点通讯程序的关键步骤就是实现信息在网络中的发送和接收。数据接收 使用的是Socket,数据发送使用的是NetworkStream。 1.1利用Socket来接收信息 TcpListener tlListen1 = new TcpListener ( 8889 ) ; //侦听端口号 tlListen1.Start ( ) ; Socket skSocket = tlListen1.AcceptSocket ( ) ; //接受远程计算机的连接请求,并获得用以接收数据的Socket实例 EndPoint tempRemoteEP = skSocket.RemoteEndPoint ; //获得远程计算机对应的网络远程终结点 while ( true ) { Byte [] byStream = new Byte[80] ; //定义从远程计算机接收到数据存放的数据缓冲区 int i = skSocket.ReceiveFrom ( byStream , ref tempRemoteEP ) ; //接收数据,并存放到定义的缓冲区中 string sMessage = System.Text.Encoding.UTF8.GetString ( byStream ) ; //以指定的编码,从缓冲区中解析出内容 MessageBox.Show ( sMessage ) ; //显示传送来的数据 } 1.2利用NetworkStream来传送信息 TcpClient tcpc = new TcpClient ( "10.138.198.213" , 8888 ) ; //对IP地址为"10.138.198.213"的计算机的8888端口提出连接申请 NetworkStream tcpStream = tcpc.GetStream ( ) ; //如果连接申请建立,则获得用以传送数据的数据流 string sMsg = "您好,见到您很高兴" ; StreamWriter reqStreamW = new StreamWriter ( tcpStream ) ; //以特定的编码往向数据流中写入数据 ,默认为UTF8编码 reqStreamW.Write ( sMsg ) ; //将字符串写入数据流中 reqStreamW.Flush ( ) ; //清理当前编写器的所有缓冲区,并使所有缓冲数据写入基础流 2. 群组通信功能 组播编程需要UDP,有两个类支持组播网络编程Socket和UdpClient.一台计算机要加 入某一个组,然后接收发往这个组的信息。Socket类要调用SetSocketOption函数加入和 离开某一个组。UdpClient类有直接的加入和离开某个组的成员函数可以调用。而向某个 组发信息,则没有什么特殊的,只需把发送数据的目的地址设为组播地址就可以了。 发送端: Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.0.0.1"), 3000); EndPoint ep = (EndPoint)iep; byte[] b = Encoding.ASCII.GetBytes("just a test!"); s.SendTo(b, ep); s.Close(); 接收端: Socket s = new Socket(AddressFamily.InterNetwork, SocketTyp

110,535

社区成员

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

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

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