以上几个问题。
- 不要使用
ME
在 C# 中,它是this
. Me
是VB。如果使用 C#,上面的代码将无法编译,因为您遗漏了User()
您定义为的类ME
。我不知道为什么你认为你需要它,因为它似乎包含的是UserIP
and UserName
。 IP 是Socket
,所以如果你需要的话,你应该使用它:
IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
And UserName
可以成为全局字符串变量 - 不必是类的一部分。
也许我很挑剔,但我没有看到哪里需要在User()
对我来说,试图破译代码,只是把事情搞砸了。
- 始终定义您的
Socket
,连接到它,然后做你的.Send()
。您错过了按钮点击中的前两个步骤 - 您只需执行您的操作即可.Send()
. UdpClient
不是一个Socket
,我认为最好这样做Socket
并稍后定义您的连接类型。我认为你可能是对的,你正在努力做你的事情.Send()
使用UdpClient
你定义为你的听众。不要使用同一个对象来发送和收听!通常您会这样做,但每个事件都有 2 个不同的地址和端口。
-
不要使用foreach
在你的CreateUDPClient()
函数来获取你的IPAddress
分配给你的IPEndPoint
。你已经知道你的IP了。直接赋值即可。这是浪费处理时间。
IPAddress ip = IPAddress.Parse("192.168.0.25");
IPEndPoint endPoint = new IPEndPoint(ip, port);
如果您只有主机名,您会这样做:
string hostName = "MyComputerName";
int port = 5555; // or int.Parse(txt_Port.Text); ???
IPHostEntry hostEntry = Dns.GetHostAddresses(hostName);
IPEndPoint endPoint = new IPEndPoint(hostEntry[0], port);
不要使用Dns.GetHostEntry()
-- 如果该名称没有反向查找 (PTR) 记录,则会失败。使用Dns.GetHostAddresses()
。我不知道为什么你认为你需要循环,除非你有与你提供的相同主机名的 IPv6 地址。如果没有,只需使用[0]
- 如果不使用 IPv6,它应该是您将使用的第一个也是唯一一个返回的 IP。但同样,由于您已经拥有 IP,只需将其插入即可 - 无需进行查找。它可以帮助你消除Dns.GetHostName()
,也 - 只需使用192.168.0.25
.
供您参考,MSDN 在这里提供了同步套接字发送/接收的过程:https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx
以及异步套接字发送/接收:
http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
因为我鄙视仅链接的答案,并且您似乎通过使用混合这两种方法Send()
and EndReceive()
,分别到上面的链接,我将尽力简洁地描述其内容并帮助修复您的代码:
基本上他们说使用StateObject
类,而不是全局变量MyUDPClient
你有:
public class StateObject
{
public byte[] buffer = new byte[1024];
public Socket workSocket;
public StringBuilder sb = new StringBuilder();
}
您将创建一个套接字并将其添加到其中。缓冲区是一种告诉Receive()
or EndReceive()
您想要一次从响应中读回的块的大小,以及sb
将作为响应的占位符。
看来你在这里发生了很多事情:SendtoTarget_Click
从表单和你的听众中进行一次性测试。你的SendtoTarget
按钮进行同步发送,您的StartUDP_Click()
进行异步接收。
你会改变你的SendtoTarget_Click()
事件是这样的(其中以前从未定义过您的套接字,并且您必须在发送之前连接到它):
private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");
// Create a UDP socket.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try
{
// Connect to the remote endpoint.
sender.Connect(TargetIP);
// Send message -- already contains the endpoint so no need to
// specify again
sender.Send(Message, 0, Message.Length, SocketFlags.None);
sender.Close();
}
catch (Exception)
{
// do something here...
}
}
对于你的听众,你可以这样做:
private void CreateUDPClient()
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse("192.168.0.25"), 5555);
// Create a UDP socket.
Socket receiver = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try {
// Create the state object.
StateObject state = new StateObject();
state.workSocket = receiver;
// Begin receiving the data from the remote device.
receiver.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveMessage), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
你的函数叫做ReceiveMessage()
, 做这个:
private void ReceiveMessage(IAsyncResult IAR)
{
string response = String.Empty;
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) IAR.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(IAR);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
client.Close();
}
ProcessMSG(response);
CreateUDPClient(); // personally, I would re-create than calling BeginReceive directly
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
我尽力以一种可行的方式将您的代码与 MSDN 集成。您也许可以通过将该套接字分配给StateObject
并打电话BeginReceive()
再次强调 - 不确定。但不要重复使用UdpClient
像这样的对象。使用StateObject
像 MSDN 上的类一样,并且仅将其用作您的侦听器。