好吧,所以我对C#很陌生,我绝对是图形编程的新手。我正在使用Visual Studio 2015并在C#中编写我的应用程序。 我有一大堆代码,我已经玩了一段时间。基本上我的程序会将HELLO发送到服务器,但服务器不会发回HELLO。我现在在客户端和服务器中间没有防火墙,但是进程正在等待回复。老实说,我甚至不想这样做,我希望听众总是在后台运行,而用户做其他的东西,这样我的程序功能正常。所以我来找你哦很棒Stackoverflow ...因为我肯定做错了!有人可以指出我正确的方向吗?
当前代码:
private void button1_Click(object sender, EventArgs e)
{
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(this.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
this.send_message("127.0.0.1", 10545, 10545, "HELLO");
this.send_message("127.0.0.1", 10545, 10545, "AUTH:" + this.login.Text + ":" + hash);
//ListenForData.Start();
}
private void send_message(string server, int localPort, int remotePort, string message)
{
label4.Text = "Listening on port:" + localPort;
IPEndPoint lep = new IPEndPoint(IPAddress.Any, localPort);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress loginServer = IPAddress.Parse(server.ToString());
byte[] sendbuf = Encoding.ASCII.GetBytes(message);
IPEndPoint ep = new IPEndPoint(loginServer, remotePort);
s.SendTo(sendbuf, ep);
try
{
UdpClient udpClient = new UdpClient(lep);
byte[] bytes = udpClient.Receive(ref lep);
label4.Text = ep.ToString();
} catch ( Exception ex )
{
Console.WriteLine(ex.ToString());
}
}
UDPATE:
private static void UDPListener(object obj)
{
Task.Run(async () =>
{
using (var udpClient = new UdpClient(10545))
{
string rMessage = "";
string[] rArgs = new string[0];
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
rMessage += Encoding.ASCII.GetString(receivedResults.Buffer);
rArgs = rMessage.Split(new char[] { ':' });
if( rArgs[0] == "HELLO")
{
Console.Write("Received HELLO from server.");
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(obj.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
send_message("127.0.0.1", 10545, 10545, "AUTH:" + obj.login.Text + ":" + hash);
}
}
}
});
}
答案 0 :(得分:2)
你可以放心地忽略Blindy的建议。 UdpClient.ReceiveAsync()
方法是专门围绕Task
范例设计的,并且比专用线程接收数据更有效。由于Task
是等待的,因此将ReceiveAsync()
方法与GUI程序(例如Winforms或WPF)集成也更容易。也就是说,对于所有工作,您希望在UI线程中执行ReceiveAsync()
调用,而不是在另一个Task
中执行。
不幸的是,由于缺少a good, minimal, complete code example清楚地说明了您的问题,因此无法确定这看起来如何。但它最有可能涉及使UDPListener()
方法成为async
方法并从UI线程调用它。此外,由于您说该方法无法访问非静态成员,因此明显的解决方案是使该方法本身是非静态的。 E.g:
private static async Task UDPListener(object obj)
{
using (var udpClient = new UdpClient(10545))
{
string rMessage = "";
string[] rArgs = new string[0];
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
rMessage += Encoding.ASCII.GetString(receivedResults.Buffer);
rArgs = rMessage.Split(new char[] { ':' });
if( rArgs[0] == "HELLO")
{
Console.Write("Received HELLO from server.");
byte[] data = new byte[512];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(Encoding.UTF8.GetBytes(obj.password.Text));
var hash = BitConverter.ToString(result).Replace("-", "");
send_message("127.0.0.1", 10545, 10545, "AUTH:" + obj.login.Text + ":" + hash);
}
}
}
}
您的更新问题尚不清楚您是否修复了未能收到回复的问题。但是,如果您没有更改send_message()
方法,则会出现一些明显的问题,尤其是在创建单独的UdpClient
实例以接收数据报的情况下。
最明显的问题是,在发送消息之后 之前,您不会创建预期用于接收响应的UdpClient
实例。这有两个原因:
s
。即使您在调用udpClient
之前创建了s.SendTo()
对象,实际上也会将回复发送到s
套接字,而不是udpClient.Client
套接字。同样,如果没有一个好的代码示例,就无法知道服务器实际上做了什么。但无论它的行为是普通服务器还是非标准实现,您发布的代码都无法可靠地从服务器接收响应。
您应该修改您的设计,以便您的客户端只创建一个套接字(例如,一个初始UdpClient
实例)。您可以通过致电ReceiveAsync()
来准备沟通,只有在您完成后才能做好准备,从而确保您已准备好接收回复,然后您就可以发送数据。
确保您只创建 此单个对象。
另请注意,客户端实现通常不会绑定到特定端口。相反,您让操作系统分配一个端口。只有服务器需要绑定到特定端口,以便来自未知端点的入站请求可以知道发送其请求的端口。服务器的接收操作将包括客户端的端口号,因此服务器将知道发送其响应的端口,而客户端没有选择任何特殊的端口号。
最后,我强烈建议您学习现有的套接字编程教程,尤其是Winsock Programmer's FAQ。这些材料都没有直接适用于.NET套接字API,但是您遇到的大多数问题都是完全那里记录的事情。如果没有对套接字编程的基本理解,通常无法使用.NET套接字API。
如果上述内容无法让您朝着正确的方向前进,请确保您提出的任何未来问题都包含一个良好的代码示例,如上面提供的链接所述。请注意,对于任何网络问题,完整的代码示例包括两者客户端和服务器。任何人都无法完全理解您的问题,更不用说测试和修复您的代码示例,而不需要两者的实现。