Поскольку вы не обращаетесь к пользовательскому интерфейсу внутри серверного цикла и не меняете его, я бы предложил использовать поток.
Вы можете начать новую тему, как это:
public Form2()
{
InitializeComponent();
Thread serverThread = new Thread(() => ExecuteServer("test"));
serverThread.Start();
}
Здесь следует отметить несколько вещей.
Прежде всего, вы никогда не должны запускать долго работающие потоки внутри конструктора. Для этого используйте событие Load
. Вы можете создать обработчик событий для него, если дважды щелкнуть форму в конструкторе. Вы также можете сделать что-то вроде этого:
public Form2()
{
InitializeComponent();
this.Load += (o, e) => StartServer();
}
private void StartServer()
{
Thread serverThread = new Thread(() => ExecuteServer("test"));
serverThread.Start();
}
Следующее, что следует отметить, это то, что в данный момент у вас нет другого способа остановить поток, кроме отправки правильных данных в сокет. Вы должны по крайней мере использовать volatile bool
вместо true
во внешнем цикле while.
Также вы должны использовать Application.Exit
как можно меньше. С этим решением потока я бы предложил просто выйти из цикла while и выполнить некоторое закрывающее действие в конце метода потока. Ваш ExecuteServer
-метод может выглядеть примерно так:
public static void ExecuteServer(string pwd, Action closingAction)
{
// Establish the local endpoint
// for the socket. Dns.GetHostName
// returns the name of the host
// running the application.
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, 11111);
// Creation TCP/IP Socket using
// Socket Class Costructor
Socket listener = new Socket(ipAddr.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
// Using Bind() method we associate a
// network address to the Server Socket
// All client that will connect to this
// Server Socket must know this network
// Address
listener.Bind(localEndPoint);
// Using Listen() method we create
// the Client list that will want
// to connect to Server
listener.Listen(10);
while (_shouldContinue)
{
//Console.WriteLine("Waiting connection ... ");
// Suspend while waiting for
// incoming connection Using
// Accept() method the server
// will accept connection of client
Socket clientSocket = listener.Accept();
// Data buffer
byte[] bytes = new Byte[1024];
string data = null;
while (true)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,
0, numByte);
if (data.IndexOf("<EOF>") > -1)
break;
}
Console.WriteLine("Text received -> {0} ", data);
if (data == "<EOF> " + "kill")
{
break;
}
else if (data == "<EOF>" + "getpw")
{
sendtoclient(clientSocket, pwd);
}
else
{
sendtoclient(clientSocket, "Error 404 message not found!");
}
// Close client Socket using the
// Close() method. After closing,
// we can use the closed Socket
// for a new Client Connection
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
}
closingAction();
}
И ваш StartServer
должен быть немного скорректирован:
private void StartServer()
{
Action closingAction = () => this.Close();
Thread serverThread = new Thread(() => ExecuteServer("test", closingAction));
serverThread.Start();
}
Это закроет форму после завершения работы сервера. Конечно, вы можете изменить то действие, которое выполняется.
Также shouldContinue
bool должен выглядеть примерно так:
private static volatile bool _shouldContinue = true;
Вы, конечно, можете обменять его на свойство или что угодно, просто установите его в false, если хотите, чтобы цикл завершился.
И последнее, имейте в виду, что если вы используете блокирующие вызовы, такие как listener.Accept();
, вы, конечно, не будете сразу отменять поток при изменении bool. Для этих вещей я бы посоветовал вам отказаться от блокировки вызовов, как это, и попытаться найти вещи с тайм-аутом, например.
Я надеюсь, что вы можете начать что-то с этим.
Удачи!
EDIT:
При рассмотрении принятого ответа я должен повторить, что вы никогда не должны запускать долго выполняющиеся потоки / задачи внутри конструктора . Если вы действительно хотите использовать async / await вместо задач, не делайте этого так, как предлагает принятый ответ.
Прежде всего, завершение всего тела метода в Task.Run
выглядит ужасно и приносит еще больше вложенности. Есть так много способов сделать это лучше:
- Используйте локальную функцию и выполните
Task.Run
для этого.
- Используйте отдельную функцию и выполните
Task.Run
для этого.
- Если вы хотите запустить его асинхронно только один раз, и есть варианты использования для выполнения функции синхронно (блокировка), тогда вы должны оставить функцию, подобную этой, и делать
Task.Run
для нее при вызове.
Также, как упомянуто в моем комментарии под принятым ответом, было бы намного лучше использовать событие Load и сделать так в конструкторе:
Load += async (o, e) => await Task.Run(() => ExecuteServer("test"));
.
Это не только устраняет проблему запуска долго выполняющейся задачи внутри конструктора, но и делает асинхронный вызов прямо там, без какого-либо уродливого вложения в функцию ExecuteServer
(см. Пункт 3).
Если вы хотите, чтобы функция ExecuteServer
была асинхронной сама по себе, см. Пункты 1 и 2.