关于 Socket UDP 问题(公网上UDP通讯)^^^^^^^(100分)

AA黄豆AA 2006-10-06 09:32:36
服务端如何像客户端发送消息(使用Socket UDP )????

服务端是接收的到客户端的消息,但是服务端如何回应客户端呢?

//看看我的代码(服务端)

public void sk()//这里是一个线程的执行过程
{
while(true)
{
s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

//主要在这里,由于这里是服务端(知道固定的IP,和发往固定的端口
EndPoint localEp=new IPEndPoint(IPAddress.Any,11200);

//所以这里的bind很顺利,因为客户端发过来的端口是11200
s.Bind(localEp);

EndPoint senderRemote = (EndPoint)sender;

byte[] msg = new byte[2500];

//使用ReceiveFrom必须先使用s.Bind
s.ReceiveFrom(msg,SocketFlags.None, ref senderRemote);


//下面是服务端一个组件(textBox)接收数据
textBox2.Text+=System.Text.UTF8Encoding.UTF8.GetString(msg)+"\r\n";

//获得了客户端的IP和发送端口(当然这里的客户端端口不会是一个固定的值)
IPEndPoint sender2=(IPEndPoint)senderRemote;

textBox2.Text+=sender2.Address.ToString()+"\r\n";

textBox2.Text+=sender2.Port.ToString()+"\r\n";

textBox2.Text+="____________________________________\r\n";


//在这里服务端收到消息后立即回复客户端口


byte[] ByteGet=new byte[2500];

ByteGet=System.Text.UTF8Encoding.UTF8.GetBytes("服务器已经接收到!!!!!!!!!!!!");

//这里回复给客户端(由于恢复的客户端端口不确定,但是我们可以从senderRemote这里知道)
s.SendTo(ByteGet,SocketFlags.None,senderRemote);

//最后结束
s.Close();
}
}




//=========================================================================
客户端代码


public void sk()//发送过程,不在线程里,使用一个按钮事件调用
{
s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);

byte[] ByteGet=new byte[2500];

ByteGet=System.Text.UTF8Encoding.UTF8.GetBytes("发送了数据");

IPAddress a = IPAddress.Parse("219.137.203.209");

receivePoint = new IPEndPoint (a,11200);

EndPoint senderRemote = (EndPoint)receivePoint;

//发送给服务端,因为服务端是固定的IP和端口11200
//如果这里发送的端口不是11200,那么服务端接收不到
//因为在服务端代码里面已经s.Bind(localEp);到了11200
s.SendTo(ByteGet,SocketFlags.None,senderRemote);
s.Close();
//结果服务端可以正常接收,多太客户端同时发送,服务端也可以接收
}


客户端接收服务端代码

public void cs()//一个线程的过程
{
while ( true )
{


s1= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);

//设置超过
s1.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout,
3000
);


IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

//问题就在这里,到底客户端该如何Bind,跪求请高高高高手
EndPoint localEp=new IPEndPoint(IPAddress.Any,11003);

s1.Bind(localEp);

EndPoint senderRemote = (EndPoint)sender;

byte[] msg = new byte[2500];

int i=0;


try
{

//这里怎么样都无法得到服务器返回的消息
//我估计原因就在s1.Bind(localEp);但是localEp该如何设置呢?
//服务器每次返回端口的都不一样
s1.ReceiveFrom(msg,SocketFlags.None, ref senderRemote);
textBox4.Text+=System.Text.UTF8Encoding.UTF8.GetString(msg)+"\r\n";

}
catch(SocketException e)
{
textBox5.Text=e.Message;

}

s1.Close();

}

}



//============================================================================


哎^^^^^^就是这个问题,我查看了大量的文章和大量的论坛,都没有找到答案!!!
也就是服务端如何像客户端发送消息(使用Socket UDP )????

跪求各位大侠^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^







...全文
1422 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
xu_2007 2006-10-19
  • 打赏
  • 举报
回复
楼主说的这种问题根本不存在客户端不能和服务器通讯的问题,因为服务器始终是在公网上,客户端可以明确服务器的IP和端口,在客户端发送消息到服务器的时候,既使客户端是在内网中也是客户端先发送消息到服务器端,这样客户端就自动在它自己的N AT设备上注册了服务器的IP,这样服务器只要记录客户端的公网IP和端口就行了,因为服务器再发消息到客户端的时候NAT设备会自动把消息转发到在内网中客户端的IP和端口,所以这里根本不存在UDP穿透,因为没有客户端到客户端的通讯,既使存在这种情况,那么只要NAT中间设备不是CONE类型之外的也可以通过穿透的方法进行通讯!
szh3210 2006-10-19
  • 打赏
  • 举报
回复
up
jingjing_180 2006-10-09
  • 打赏
  • 举报
回复
NAPT 有2中类型,你可以网上查查的
如果你保证你的代码没问题的话,说不定是你的NAPT是Symmetric 类型的,如果真是这样的类型的话,你不妨在服务器端接受到最新的客护端口(例如 9000)上再加 1 (即 9001)试试看,也就是P2P中的猜测端口方法了
不过大部分的NAPT是CONE类型的
AA黄豆AA 2006-10-08
  • 打赏
  • 举报
回复
up up
-渔民- 2006-10-08
  • 打赏
  • 举报
回复
up
yesry 2006-10-08
  • 打赏
  • 举报
回复
up
changlongbaobao 2006-10-08
  • 打赏
  • 举报
回复
c#讨论群:30781666 欢迎有经验的同志加入
xingyaohua 2006-10-08
  • 打赏
  • 举报
回复
up
ycqing 2006-10-08
  • 打赏
  • 举报
回复
up
peteryhliu 2006-10-07
  • 打赏
  • 举报
回复
使用NAT将内网Ip mapping为路由器的端口,假设为KK(此路由器应该在公网,以下所说才成立),服务端所收到的数据报将是你的路由器Ip,假设为IK, 服务器向IK的KK端口发送的数据将由路由器转发给客户端。

wshuangminlg 2006-10-07
  • 打赏
  • 举报
回复
顶者有分
jingjing_180 2006-10-07
  • 打赏
  • 举报
回复
2种方法:
1。中转服务器
2。参考P2P吧
如果是中转服务器,比较简单
如果是P2P 的话,在SERVER端用IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0)来接受CLIENT端的外网IP和PORT,如果NAT穿透成功的话,直接S->C,C是可以接受到S的信息的,如果接受不到,那得继续NAT穿透
AA黄豆AA 2006-10-07
  • 打赏
  • 举报
回复
各位老大们可以贴上源代码吗??
peteryhliu 2006-10-07
  • 打赏
  • 举报
回复
根本用不着中转,你会NAT吧?
使用NAT将内网Ip mapping为路由器的端口,假设为KK(此路由器应该在公网,以下所说才成立),服务端所收到的数据报将是你的路由器Ip,假设为IK, 服务器向IK的KK端口发送的数据将由路由器转发给客户端。
例如:
客户端A,IP=192.168.1.21, 监听在10000
A所入口IP=70.134.123.123,(路由器的IP),将A mapping 为:
external Ip external Port A A_port
70.134.123.123 12000 192.168.1.21 10000
服务器只向external IP的External port发就行了,不要注意服务器收到的端口回应,当A所在的LAN有两台机子时你就要想点法子了。也比较容易。
绝对没问题。
SoftKnight 2006-10-07
  • 打赏
  • 举报
回复
学习,up!
jingjing_180 2006-10-07
  • 打赏
  • 举报
回复
外加句:我就是这样写的,我的是可以通讯的,代码可以证实!呵呵
如果还不行,你再查查别的地方是不是出了点小错误,别老盯在这一个地方上啊
jingjing_180 2006-10-07
  • 打赏
  • 举报
回复
外加句:我就是这样写的,我的是可以通讯的,代码可以证实!呵呵
如果还不行,你再查查别的地方是不是出了点小错误,别老盯在这一个地方上啊
jingjing_180 2006-10-07
  • 打赏
  • 举报
回复
由于你的通讯是S->C,C->S的模式,没有C->C,所以涉及不到P2P的NAT穿透
的却存在当C发消息给S的时候,每次发,IP是相同的,端口一直在变化,而且没规律的,不象P2P中的NAT是对称型的话,他的端口变化还有点规律的,每次加1吧
虽然端口一直在变化,你只要记下最近一次的端口是多少,然后往这个端口发消息,NAT会自动把此消息包根据映射出来的端口号转发到内网的某台机器
大体代码:
在服务端写个这样的 IPEndPoint 对象
private IPEndPoint remotePoint;
remotePoint = new IPEndPoint(IPAddress.Any,0);
byte[] msgBuffer = server.Receive(ref remotePoint);//接受任何SOCKET 对象发来的消息
IPEndPoint userEndPoint = new IPEndPoint(remotePoint.Address,remotePoint.Port);//记下当前的对象的IP和PORT,可以放在一个列表中存放起来
public UdpClient server;
server = new UdpClient(Port);//Port是先前定义好的端口,且客户端是知道服务器端的IP和PORT的,可以用下面的语句直接给C回发消息,也可以用这个userEndPoint 对象代替下面的remotePoint参数
server.Send(buffer,buffer.Length,remotePoint);
说白了,现在也用不着服务器中转了
AA黄豆AA 2006-10-07
  • 打赏
  • 举报
回复
请高人看完本贴,请高人贴出代码,如果测试成功,我将贴上完整的UDP通讯方式(通过服务器中转方式的),UP UP UP UP UP UP UP UP

高人请看___________________________________________________________
//=====================开始=========================================================

如果使用服务器中转!
问题是服务器如何和客户端联系!
情况是这样的,服务器是可以得到客户端的IP和端口的,但是由于有NAT的转发,所以服务器每次得到的客户端口是不一样的!
我们假设一种情况:
客户端:内网IP是192.168.1.100 ,外网IP是219.17.13.209
客户端发送服务端:由于服务端的IP是219.137.203.209(固定的),端口为11200
所以客户端口的发送代码为:
//===========客户端发送代码===============================================
s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
byte[] ByteGet=new byte[2500];
ByteGet=System.Text.UTF8Encoding.UTF8.GetBytes("发送了数据");
IPAddress a = IPAddress.Parse("219.137.203.209");
receivePoint = new IPEndPoint (a,11200);
EndPoint senderRemote = (EndPoint)receivePoint;
s.SendTo(ByteGet,SocketFlags.None,senderRemote);
s.Close();
//===========客户端发送代码END===============================================


那么服务端接收代码为:
//===========服务端接收代码===============================================
s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint localEp=new IPEndPoint(IPAddress.Any,11200);
s.Bind(localEp);
EndPoint senderRemote = (EndPoint)sender;
byte[] msg = new byte[2500];
s.ReceiveFrom(msg,SocketFlags.None, ref senderRemote);

//在这里senderRemote包含着客户端的共网IP和端,不过这个端可不是11200了,而是一个随时变换的数据
//===========服务端接收代码END===============================================

那么服务端得到了senderRemote,就可以像客户端发送数据了
我们可以利用这样的代码来查看客户端的IP和端
IPEndPoint sender2=(IPEndPoint)senderRemote;
sender2.Address.ToString();//表示客户端共网IP
sender2.Port.ToString();//表示客户端发送UDP报文端口(注意是随时可变的)

//===========服务端发送代码===============================================
s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
byte[] ByteGet=new byte[2500];
ByteGet=System.Text.UTF8Encoding.UTF8.GetBytes("服务器已经接收到!!!!!!!!!!!!");
s.SendTo(ByteGet,SocketFlags.None,senderRemote);
//===========服务端发送代码END===============================================


好了问题出来了!!!!!!!(用的方法是服务器中转,这样服务器已经可以发送数据到客户端了,经过测试也的确是发送了,可是客户端如何接收是个问题了,那位高人可以指点一下,贴出代码来)

//===========客户端接收代码===============================================

s= new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);




//这样Bind肯定接收不到
//EndPoint localEp=new IPEndPoint(IPAddress.Any,11200);
//s.Bind(localEp);

//这样Bind肯定接收不到
//EndPoint localEp=new IPEndPoint(IPAddress.Any,0);
//s.Bind(localEp);

所以客户端这里该如何Bind,请高人指点,或者有没有其他的办法,问题就在这里!!!!!!请高人贴出代码,如果测试成功,我将贴上完整的UDP通讯方式(通过服务器中转方式的)




IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint senderRemote = (EndPoint)sender;

byte[] msg = new byte[2500];

s.ReceiveFrom(msg,SocketFlags.None, ref senderRemote);



//===========客户端接收代码END===============================================





//=====================结束=========================================================


请高人看完本贴,请高人贴出代码,如果测试成功,我将贴上完整的UDP通讯方式(通过服务器中转方式的),UP UP UP UP UP UP UP UP



hawk234 2006-10-07
  • 打赏
  • 举报
回复
up
加载更多回复(8)

110,536

社区成员

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

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

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