你好!为什么程序会在收到对字符串 answer = ReceiveDataFromServer(); 的响应之前挂起?那些。直到它收到一个套接字作为响应。如果她不明白,就挂起。如果是这样,那么它就是一个损坏的编码。
namespace HotKeyTest
{
public partial class Form1 : Form
{
// Receiving byte array
byte[] bytes = new byte[1024];
Socket senderSock;
public Form1()
{
InitializeComponent();
Boolean success = Form1.RegisterHotKey(this.Handle, this.GetType().GetHashCode(), 0x0002, 0x4c);//Set hotkey as 'ctrl+l'
}
private void button1_Click(object sender, EventArgs e)
{
StreamReader sr = new StreamReader("settings");
IPAddress ip = IPAddress.Parse(sr.ReadLine());
Connect(ip);
sr.Close();
Thread.Sleep(2000);
Sendswitch();
Disconnect();
}
private void Connect(IPAddress ip)
{
try
{
// Create one SocketPermission for socket access restrictions
SocketPermission permission = new SocketPermission(
NetworkAccess.Connect, // Connection permission
TransportType.Tcp, // Defines transport types
"", // Gets the IP addresses
SocketPermission.AllPorts // All ports
);
// Ensures the code to have permission to access a Socket
permission.Demand();
// Resolves a host name to an IPHostEntry instance
IPHostEntry ipHost = Dns.GetHostEntry("");
// Gets first IP address associated with a localhost
IPAddress ipAddr = ip;
// Creates a network endpoint
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 55443);
// Create one Socket object to setup Tcp connection
senderSock = new Socket(
ipAddr.AddressFamily,// Specifies the addressing scheme
SocketType.Stream, // The type of socket
ProtocolType.Tcp // Specifies the protocols
);
senderSock.NoDelay = false; // Using the Nagle algorithm
// Establishes a connection to a remote host
senderSock.Connect(ipEndPoint);
}
catch (Exception exc) { MessageBox.Show(exc.ToString()); }
}
private void Sendswitch()
{
try
{
// Sending message
//<Client Quit> is the sign for end of data
byte[] msg = Encoding.Unicode.GetBytes("{\"id\":1,\"method\":\"get_prop\",\"params\":[\"power\", \"not_exist\", \"bright\"]}");
// Sends data to a connected Socket.
int bytesSend = senderSock.Send(msg);
Thread.Sleep(2000);
string answer = ReceiveDataFromServer();
MessageBox.Show(answer);
}
catch (Exception exc) { MessageBox.Show(exc.ToString()); }
}
private string ReceiveDataFromServer()
{
try
{
// Receives data from a bound Socket.
int bytesRec = senderSock.Receive(bytes);
// Converts byte array to string
String theMessageToReceive = Encoding.Unicode.GetString(bytes, 0, bytesRec);
// Continues to read the data till data isn't available
while (senderSock.Available > 0)
{
bytesRec = senderSock.Receive(bytes);
theMessageToReceive += Encoding.Unicode.GetString(bytes, 0, bytesRec);
}
return theMessageToReceive;
}
catch (Exception exc) { return exc.ToString(); }
}
private void Disconnect()
{
try
{
// Disables sends and receives on a Socket.
senderSock.Shutdown(SocketShutdown.Both);
//Closes the Socket connection and releases all resources
senderSock.Close();
}
catch (Exception exc) { MessageBox.Show(exc.ToString()); }
}
}
}
让我们将问题分为两部分 - 阻塞和损坏的数据。
根据文档 - https://msdn.microsoft.com/ru-ru/library/8s4y8aff(v=vs.110).aspx - Receive 调用正在阻塞。也就是说,只要套接字中至少有一个字节,它就会立即返回数据。由于那里有一个循环,所以会一直阻塞,直到另一边的socket关闭(也就是说,即使所有的数据都进来了,代码仍然会等待socket关闭。如果服务器没有关闭socket立即套接字,这可能是挂起的原因。)
现在关于损坏的数据。Receive 方法的设计使其可以返回从 1 个字节到 ... .NET 子系统足够好)。但这无关紧要。重要的是,如果一方面您发送 100 字节的一部分,那么另一方面,不一定会读取 100 字节。可能是 20 岁、40 岁和其他人。
这很重要,因为 Unicode 字符串(无论是 utf-8 还是 ucs-16)不一定每个字符包含一个字节,并且字符串可以在字符中间断开。这里会有问题。但是这个问题很容易解决——你需要读取所有的数据然后才解码。
但是第一个问题有点困难。你需要知道“数据结构”。例如,数据可能在换行之前被读取,或者数据的大小是已知的。