我正在尝试开发一个项目,我可以让多个客户端为压力测试提出自己的服务器请求。当我创建一个新线程并希望该线程完成工作时,我很难弄清楚如何操作自定义控件属性。我有超过100个控件;理想情况下,100个客户。问题是我的控件是GUI的一部分,我不知道如何允许有问题的线程从该相对控件获得访问权。
以下是我所拥有的:
// Custom project.class to get access to a custom base of properties created within the tool itself.
List<custom_control_project.custom_control_widget> controlList = new List<custom_control_project.custom_control_widget>();
private async void btnStart_Click(object sender, EventArgs e)
{
...// control property initializations
foreach (var control in controlList)
{
if (control.Enabled)
{
Thread thread = new Thread(() => StartClient());
thread.Start();
// Loop until worker thread activates.
while (!thread.IsAlive);
... // Ideally the GUI updates would happen from these threads. Simple updates to labels based on status code responses and expected xml parameters received.
}
}
我的StartClient()
主要基于Microsoft的异步套接字客户端示例:http://msdn.microsoft.com/en-us/library/bew39x2a%28v=vs.110%29.aspx
我是异步运行这些客户端但程序不是我的最终结果。我做了一些更改,包括重置ManualResetEvents。但是,当我运行我的应用程序时,所有控件仍然依次运行,我希望它们是独立的。通过使用StartClient()创建新线程,我有正确的方法吗?
参考microsofts示例,我最感兴趣的部分是ReceiveCallback(IAsyncResult ar)
方法:
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
// ManualResetEvent instances signal completion.
private ManualResetEvent connectDone =
new ManualResetEvent(false);
private ManualResetEvent sendDone =
new ManualResetEvent(false);
private ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private String response = String.Empty;
public void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
//IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
//IPAddress ipAddress = ipHostInfo.AddressList[0];
//IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(asyncServerHolder, asyncPortHolder,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, (Upload)); //POST HTTP string + xml parameters
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
//MessageBox.Show("Response received : " + response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
// Reset all manual events for next instance.
connectDone.Reset();
sendDone.Reset();
receiveDone.Reset();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
//MessageBox.Show("Socket connected to " + client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
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, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response1 = state.sb.ToString();
///
///
/// **THIS IS WHERE I WANT ALL THE PROCESSING TO BE DONE**
/// **AFTER THE RESPONSE IS COMPLETE!!**
///
///
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void Send(Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
//MessageBox.Show("Sent " + bytesSent + " bytes to server.");
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
我如何从传递给方法的foreach语句中获取相对控制,然后根据结果修改我的GUI(以某种方式调用?)?此外,是否可以使每个客户端独立,并且同时具有多个客户端到服务器到客户端请求?这是我的主要目标。
如果这是一个牵强附会或非常沮丧的尝试方法,请说出来。如果不考虑太多的编程术语(为了理解目的,我对编程很新),你会怎么做呢?
提前致谢!
答案 0 :(得分:0)
好吧,你可以排序通过使用控件上的BeginInvoke
函数来操纵来自不同线程的任何控件,传递你想要执行的操作。该操作将在UI线程上执行。
但是你的主要问题是你没有separate the concerns。您可以确定UI代码可以使操作发生,但这些操作应该与任何UI代码不同。您应该以这样的方式设计您的操作以使它们可重用。换句话说,如果您决定从头开始重写UI,您仍然可以按原样重用您的操作。
为了实现这一点,您的操作不应该引用任何UI,他们甚至不应该知道任何UI的存在。这将使您的代码更易于管理。因此,在不同的类中提取所有内容,然后使用类似事件的内容与UI进行通信。然后,UI代码将进行BeginInvoke
调用。