#c# #wpf #tcpclient #tcplistener
Вопрос:
Когда я запускаю два экземпляра своего приложения, они должны подключиться и иметь возможность отправлять приветственное сообщение другому приложению. Я знаю, что они подключаются, потому что клиентская сторона покажет, что сообщение отправлено и даже получено с сервера. Однако видна только сторона клиента. Сервер «замораживается», как только я нажимаю «Пуск». Я что-то не так использую? Изображение замороженного и видимого приложения
private void Startbutton_Click(object sender, RoutedEventArgs e)
{
try
{
listener = new TcpListener(localAddr, port);
ChatScreentextBox.AppendText("waiting for connection..." "n");
listener.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
TcpClient client = listener.AcceptTcpClient();
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
ChatScreentextBox.AppendText(data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
ChatScreentextBox.AppendText(data "connection");
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException ex)
{
MessageBox.Show(ex.Message.ToString());
}
finally
{
// Stop listening for new clients.
listener.Stop();
}
}
private void Connectbutton_Click(object sender, RoutedEventArgs e)
{
try
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
Int32 port = 88;
TcpClient client = new TcpClient("127.0.0.1", port);
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes("hello");
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
//Console.WriteLine("Sent: {0}", message);
ChatScreentextBox.AppendText(data "n");
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
ChatScreentextBox.AppendText("you:" responseData "thisn");
// Close everything.
stream.Close();
client.Close();
}
catch (ArgumentNullException ex)
{
MessageBox.Show(ex.Message.ToString());
}
catch (SocketException ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Ответ №1:
Вы принимаете TCPClient
событие щелчка по кнопке в бесконечном while
цикле. Это является причиной того, что приложение перестает отвечать на запросы.
Что вам нужно сделать, так это запустить это в отдельном потоке. BackgroundWorker
это мой предпочтительный способ сделать это. Task
является также относительно новым и популярным.
Существует множество примеров того, как использовать и то, и другое. В двух словах, если вы идете с BackgroundWorker
, вам нужно создать поле типа BackgroundWorker
, у вас есть все ваши «мозги» в DoWork
событии, затем с помощью кнопки Нажмите событие, просто вызовите .RunWorkerAsync()
метод.
Если это неясно и вам нужна дополнительная помощь, просто прокомментируйте здесь.
Комментарии:
1. Огромное спасибо. Я не совсем понимаю, что такое «ум», я довольно новичок в программировании. Я предполагаю, что это означает поместить весь TcpListener, AcceptTcpClient в событие DoWork?
2. Да, точно, все содержимое вашего
Click
события должно быть вDoWork
случаеBackgroundWorker
экземпляра.3. Большое вам спасибо, это решило мою проблему!
4. Мы вам очень рады. Я создал для вас полный пример (хотя и в качестве приложения WinForms), есть еще несколько вещей, которые нужно изменить. А именно:
while(true)
больше не годится, и прямой доступ из потока BackgroundWorker очень нахмурен. Лучший способ сделать это-включить отчеты о ходе выполнения и сообщить некоторое число (для этой цели я использую отрицательные числа) со строкой, чтобыProgressChanged
событие могло получить доступ к элементам управления и обновить текст. Если вы хотите, скачайте и посмотрите на источник: drive.google.com/file/d/1TWodTJ35KRtY3rRLNv6NDw1PetrD-SRO/…
Ответ №2:
Когда вы принимаете соединение и запускаете (цикл while) для чтения данных из соединения, оно блокирует действие, и вы выполняете это действие в основном потоке (в котором выполняется процедура обновления пользовательского интерфейса). Когда вы принимаете соединение, вы считываете данные, но пользовательский интерфейс никогда не обновляется, потому что поток все еще читает/ожидает данные.
Чтобы исправить это, вам нужно запустить это действие чтения в отдельном потоке для обработки чтения и обработки. Вы можете увидеть пример здесь.
Чтобы узнать больше о потоковой передаче в C#, см. Пример здесь или прочитайте документы Microsoft.