在 VB.NET 中连接到源游戏服务器
我正在开发一个应用程序,用于检测在 LAN 上运行的基于源的游戏。根据 Valve 提供的 规范,我将其范围缩小到了我想要的范围:在端口 27015 上建立 UDP 连接,发送 A2S_INFO
查询(0xFFFFFFFF 后跟“TSource Engine Query”)并解析二进制回复。
这是我正在使用的代码:
Dim sIP As String = "192.168.0.154"
Dim nPort As Integer = 27015
Dim connectionMessage As String = "ÿÿÿÿTSource Engine Query" & Chr(0)
Dim endPoint As New IPEndPoint(IPAddress.Parse(sIP), nPort)
Dim client As Socket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 6000)
client.SendTo(Encoding.ASCII.GetBytes(connectionMessage), endPoint)
Console.WriteLine("Message sent to " & sIP & ":" & nPort & vbCrLf & connectionMessage)
Dim sBuffer(1400) As Byte
Try
client.ReceiveFrom(sBuffer, endPoint)
MsgBox(System.Text.Encoding.Unicode.GetString(sBuffer))
Catch ex As SocketException
MsgBox("Failed to receive response on " & sIP & ":" & nPort & ":" & vbCrLf & ex.Message)
End Try
我不断收到 SocketError.TimedOut 异常,通知我:
无法在 192.168.0.154:27015 上接收响应: 连接尝试失败,因为连接方在一段时间后没有正确响应,或者建立的连接失败,因为连接的主机未能响应
我相当确定这非常接近答案,因为以下非常简单的 PHP 版本可以工作就像一个魅力:
$ip = "192.168.0.154";
$port = 27015;
$fp = fsockopen("udp://".$ip,$port, $errno, $errstr);
socket_set_timeout($fp, 6);
$prefix = "\xff\xff\xff\xff";
$command = "TSource Engine Query";
$msg = "$prefix$command";
fputs($fp, $msg, strlen($msg));
$response = "";
do {
$response .= fgets($fp, 16);
$status = socket_get_status($fp);
} while ($status['unread_bytes']);
fclose ($fp);
echo $response;
这为我提供了符合规范的答复。
我已经很接近了,但是我的 VB.NET 代码出了点问题。我做错了什么?
解决方案
编码类型对于传输二进制数据无效。我将以下内容替换
Encoding.ASCII.GetBytes(connectionMessage)
为:
System.Text.Encoding.[Default].GetBytes(connectionMessage)
并立即解决了。
“pub”建议的更强大的解决方案可能是指定代码页(尽管我还没有测试过这一点):
Encoding.GetEncoding("iso-8859-1").GetBytes(connectionMessage)
I'm developing an application that detects Source-based games running on the LAN. Following up on the specifications provided by Valve, I have it narrowed down to exactly what I want: making a UDP connection on port 27015, sending an A2S_INFO
query (0xFFFFFFFF followed by "TSource Engine Query") and parsing the binary reply.
This is the code I'm working with:
Dim sIP As String = "192.168.0.154"
Dim nPort As Integer = 27015
Dim connectionMessage As String = "ÿÿÿÿTSource Engine Query" & Chr(0)
Dim endPoint As New IPEndPoint(IPAddress.Parse(sIP), nPort)
Dim client As Socket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 6000)
client.SendTo(Encoding.ASCII.GetBytes(connectionMessage), endPoint)
Console.WriteLine("Message sent to " & sIP & ":" & nPort & vbCrLf & connectionMessage)
Dim sBuffer(1400) As Byte
Try
client.ReceiveFrom(sBuffer, endPoint)
MsgBox(System.Text.Encoding.Unicode.GetString(sBuffer))
Catch ex As SocketException
MsgBox("Failed to receive response on " & sIP & ":" & nPort & ":" & vbCrLf & ex.Message)
End Try
I keep getting SocketError.TimedOut
exceptions, informing me:
Failed to receive response on 192.168.0.154:27015:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I'm fairly certain this is very close to the answer, because the following very simple PHP version works like a charm:
$ip = "192.168.0.154";
$port = 27015;
$fp = fsockopen("udp://".$ip,$port, $errno, $errstr);
socket_set_timeout($fp, 6);
$prefix = "\xff\xff\xff\xff";
$command = "TSource Engine Query";
$msg = "$prefix$command";
fputs($fp, $msg, strlen($msg));
$response = "";
do {
$response .= fgets($fp, 16);
$status = socket_get_status($fp);
} while ($status['unread_bytes']);
fclose ($fp);
echo $response;
This provides me with a reply in accordance with the specifications.
I'm close, but something's amiss with my VB.NET code. What am I doing wrong?
The solution
The encoding type is not valid for transmitting binary data. I replaced the following:
Encoding.ASCII.GetBytes(connectionMessage)
with:
System.Text.Encoding.[Default].GetBytes(connectionMessage)
And it was instantly solved.
A more robust solution, suggested by "pub", might be to specify the code page (although I haven't tested this):
Encoding.GetEncoding("iso-8859-1").GetBytes(connectionMessage)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于世界各地的计算机上没有将 iso-8859-1 代码页设置为默认值的人,请使用:
Encoding.GetEncoding("iso-8859-1").GetBytes(connectionMessage)
For those couple guys around the world who doesn't have iso-8859-1 code page set as default on computer, use:
Encoding.GetEncoding("iso-8859-1").GetBytes(connectionMessage)
您看过VB.Net 中的多线程游戏服务器浏览器 CodeProject 上的文章?如果您不想重复使用已经编写的代码,我相信您可以检查他们是如何做到的,看看是否能找到您的问题。
希望有帮助,和平。
Did you take a look at this Multi-Threaded Game Server Browser in VB.Net article at CodeProject? If you don't want to re-use the code that's already been written, I'm sure you can check how they did it to see if you can find your problem.
Hope that helps, peace.
不要打开套接字,而是尝试 http://msdn .microsoft.com/en-us/library/system.net.sockets.udpclient.aspx
Rather than opening a Socket, try http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.aspx