Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
1

Task вызов

08.04.2018, 21:33. Показов 2016. Ответов 14
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!
Сейчас разбираюсь с асинхронностью и тут встал вопрос.
есть функция -

C#
1
2
3
4
private static async Task ClientService(Client client, CancellationToken ct)
{
    await ReadAsync(client, ct);
}
ee можно вызвать так -
C#
1
var task = ClientService(client, cts.Token);
и так -
C#
1
var task = Task.Run(() => ClientService(client, cts.Token));
Вопрос! в чем разница? и как правильнее ?

или может так ?
C#
1
2
3
4
private static void ClientService(Client client, CancellationToken ct)
{
     var task = Task.Run(() => ReadAsync(client, cts.Token));
}
и вызвать просто -
C#
1
ClientService(client, cts.Token);
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.04.2018, 21:33
Ответы с готовыми решениями:

Вызов событий из Task
Добрый день. Как мне вызвать event из Task? Дело в том что Taks в качестве параметра принимает...

Task.WhenAll для разных типов Task
Здравствуйте! Есть код вида SomeType a = await SomeTask; OtherType b = await OtherTask; //other...

Отмена одного Task в массиве Task
Как можно отменить одну задачу в массиве Task? Никак же нельзя передать CancellationTokenSource в...

Вызов методов классов друг у друга (вызов метода из другого класса)
Есть несколько классов, которые могут вызывать методы (функции) друг у друга. Логика: класс1 имеет...

14
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
08.04.2018, 21:58 2
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
в чем разница?
В первом случае запускается асинхронная операция и возвращается ссылка на объект, ее представляющий.
Во втором случае запускается асинхронная операция, которая запускает асинхронную операцию и возвращает ссылку на объект, представляющий асинхронную операцию, которая возвращает асинхронную операцию. Масло-масляное, короче.

Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
как правильнее ?
Если выбирать из двух, то первый вариант.
Первый вариант.

Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
или может так ?
Не.
1
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
09.04.2018, 08:20  [ТС] 3
Спасибо за ответ!
Цитата Сообщение от kolorotur Посмотреть сообщение
Если выбирать из двух, то первый вариант.
а есть еще лучше варианты? я только учусь был бы рад узнать
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
09.04.2018, 09:01 4
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
а есть еще лучше варианты?
Поскольку в первом варианте у вас в методе ничего кроме асинхронного ожидания не происходит, было бы логичнее просто возвращать Task, а не создавать конечный автомат, ожидающий завершения задачи (это делается при использовании конструкции await) только для того, чтобы тут же завершить работу метода:
C#
1
2
3
4
private static Task ClientService(Client client, CancellationToken ct)
{
    return ReadAsync(client, ct);
}
0
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
09.04.2018, 09:33  [ТС] 5
а ну тут не совсем так, там у меня цикл
C#
1
2
3
4
5
6
while (!cts.IsCancellationRequested)
                {
                    Console.WriteLine("Waiting for a connection...");
                    var client = await AcceptClient();
                    var task = ClientService(client, cts.Token);
                }
и мне надо чтоб цикл прошел итерацию чтоб другие смогли тоже приконнектиться

просто я честно даже не знаю что делать с task который создается от ClientService а сделать
C#
1
2
3
4
private static async void ClientService(Client client, CancellationToken ct)
{
    return ReadAsync(client, ct);
}
async Void вроде как не желательно...
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
09.04.2018, 09:40 6
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
тут не совсем так
На будущее: лучше все-таки для конкретного ответа выкладывать конкретный код, а не гипотетический пример
Особенно если нет четкого понимания происходящего (а его нет, иначе бы темы не было!)
Разница может быть существенная, в чем вы убедитесь, дочитав ответ до конца.

Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
там у меня цикл
Вот в этом варианте я бы уже предложил запускать ClientService через Task.Run — как во втором примере, поскольку асинхронный вызов не гарантирует многопоточности, а Task.Run запускает выполнение в одном из потоков пула.
Если оставить код как у вас, то возможна ситуация при которой следующий клиент не подключится до тех пор, пока не прекратится работа с последним подключившимся. Вероятность мала, но не нулевая.

Не совсем по теме, но я бы так же предложил передавать CancellationToken в метода AcceptClient, а то сейчас при отмене у вас цикл не прекратится до следующего подключения клиента, которое может никогда не произойти.
2
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
09.04.2018, 15:02  [ТС] 7
Большое спасибо за советы, Вы очень помогли

Добавлено через 58 минут
Цитата Сообщение от kolorotur Посмотреть сообщение
я бы так же предложил передавать CancellationToken в метода AcceptClient
C#
1
2
3
4
5
6
7
8
9
10
11
private static async Task<Client> AcceptClient(CancellationToken ct)
{
     var client = new Client();
     var socket = await Task<Socket>.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null).ConfigureAwait(false);;
     client.workSocket = socket;
     client.id = clients.Count;
     client.ip = socket.RemoteEndPoint.ToString();
     clients.Add(client);
     Console.WriteLine("Clients count is: " + clients.Count + " IP: " + client.ip);
     return client;
}
А не подскажите куда именно вставить, токен отмены?

Добавлено через 1 час 3 минуты
Цитата Сообщение от kolorotur Посмотреть сообщение
CancellationToken в метода AcceptClient
блин я так понял что это сделать нельзя?
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
10.04.2018, 10:31 8
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
куда именно вставить, токен отмены?
Поскольку вы используете обертку над асинхронными вызовами, напрямую токен передать не получится — придется проверять после.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
private static async Task<Client> AcceptClient(CancellationToken ct)
{
     var socket = await Task<Socket>.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null).ConfigureAwait(false);
     ct.ThrowIfCancellationRequested();
 
     var client = new Client();
     client.workSocket = socket;
     client.id = clients.Count;
     client.ip = socket.RemoteEndPoint.ToString();
     clients.Add(client);
     Console.WriteLine("Clients count is: " + clients.Count + " IP: " + client.ip);
     return client;
}
Заодно зарегистрируйте отмену операции на закрытие сервера:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var token = cts.Token;
using (var registration = token.Register(client.Close))
{
   while (!token.IsCancellationRequested)
   {
      Console.WriteLine("Waiting for a connection...");
      try
      {
         var client = await AcceptClient();
         var task = ClientService(client, token);
      }
      catch (OperationCancelledException) { break; }
      catch (ObjectDisposedException) when (token.IsCancellationRequested) { break; }
   }
}
Добавлено через 22 секунды
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
блин я так понял что это сделать нельзя?
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
Добавлено через 1 час 3 минуты
Люди же работают, не всегда есть время на форуме отдыхать.
1
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
10.04.2018, 17:14  [ТС] 9
Спасибо за ответы
Цитата Сообщение от kolorotur Посмотреть сообщение
token.Register(client.Close)
а что за client.Close Вы сюда передали? tcpClient?
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
10.04.2018, 17:23 10
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
а что за client.Close Вы сюда передали? tcpClient?
Да, он самый.
При отмене будет вызван метод Close на "слушателе" портов, вызов которого приведет к прерыванию асинхронного BeginAccept и выбросу исключения.
Не помню точно, какое исключение бросается в этом случае: ObjectDisposedException или SocketException (поэкспериментируйте!), но это исключение отлавливается и цикл завершается.
0
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
10.04.2018, 17:27  [ТС] 11
у меня правда там нет tcpClient там просто слушаю сокет я так понимаю мне нужно вызвать socket.Close?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 using (var registration = cts.Token.Register(() => listener.Close()))
            {
                while (!cts.IsCancellationRequested)
                {
                    Console.WriteLine("Waiting for a connection...");
                    try
                    {
                        var client = await AcceptClient(cts.Token);
                        var task = Task.Run(() => ClientService(client, cts.Token));
                    }
                    catch (OperationCanceledException) { break; }
                    catch (ObjectDisposedException) when (cts.Token.IsCancellationRequested) { break; }
                }
            }
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
10.04.2018, 17:30 12
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
я так понимаю мне нужно вызвать socket.Close?
Ну да, это я имена переменных перепутал.
Должно быть так:
C#
1
using (var registration = token.Register(listener.Close))
Лямбду создавать не обязательно, т.к. сигнатуры совпадают.
0
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
10.04.2018, 18:22  [ТС] 13
я очень много от Вас понял т.к. получил инфу и понял что нужно почитать Спсибо!
наверно я много прошу но может быть вы посмотрите код всего сервера и дадите еще какие нить советы?
конечно если не затруднит...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Database;
using MongoScripts;
using Microservices;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Driver;
using System.Collections.Concurrent;
using Server;
using System.IO;
 
namespace Server
{
    public class Client
    { 
        public Socket socket = null;        
        public int id { get; set; }
        public string userId { get; set; }
        public string ip { get; set; }
        public string authToken { get; set; }
        public string characterId { get; set; }
        //Size of receive buffer.
        public const int BufferSize = 1000000;
        //Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        //Received data string.
        public StringBuilder sb = new StringBuilder();  
    }
 
    public static class Connector
    {
        public static List<Client> clients = new List<Client>();
        private static CancellationTokenSource cts;
        private static Socket listener;
 
        /// <summary>
        /// Start tcp server
        /// </summary>
        public static async Task StartListening()
        {  
            cts = new CancellationTokenSource();      
 
            // IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
            // IPAddress ipAddress = ipHostInfo.AddressList[0];
            // IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
 
            //Establish the endpoint for the socket.
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 1121);
 
            //Create a TCP/IP socket.
            listener = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            Console.WriteLine(@"  
            ===================================================  
                   Started listening requests at: {0}:{1}  
            ===================================================",   
            endPoint.Address, endPoint.Port);  
            try 
            {
                //Bind the socket to the local endpoint and listen for incoming connections.
                listener.Bind(endPoint);
                listener.Listen(100);
 
                DbConnect.Connect();
                // var monstersGenerator = new MonstersGenerator();
                // var skillsGenerator = new SkillsGenerator();
                // var eliteMonstersGenerator = new EliteMonstersGenerator();
                // var bosses = new BossesGenerator();
                // var locationGenerator = new LocationGenerator();
                // ServerGenerator.ServerGeneratorAsync("Server3");
                // CharacterClassesGenerator.CharacterClassesGeneratorAsync();
                // monstersGenerator.GenerateMonster();
                // skillsGenerator.GenerateSkills();
                // eliteMonstersGenerator.EliteGenerateMonsterArmor();
                // eliteMonstersGenerator.EliteGenerateMonsterDmg();
                // eliteMonstersGenerator.EliteGenerateMonsterHp();
                // bosses.GenerateBoss();
                // locationGenerator.GenerateLocation();
                // ItemGenerator.itemGeneratorAsync(characterId: "5aa4eeb4482907ab7479adf9", level: 1, quantity: 30);
                // BotsGenerator.BotsGeneratorAsync();
            }
            catch (Exception e) 
            {
                Console.WriteLine(e.ToString());
            }
            Stop();
            using (var registration = cts.Token.Register(listener.Close))
            {
                while (!cts.IsCancellationRequested)
                {
                    Console.WriteLine("Waiting for a connection...");
                    try
                    {
                        var client = await AcceptClient(cts.Token);
                        var task = Task.Run(() => ClientService(client, cts.Token));
                    }
                    catch (OperationCanceledException) { break; }
                    catch (ObjectDisposedException) when (cts.Token.IsCancellationRequested) { break; }
                }
            }
        }
 
        private static async Task ClientService(Client client, CancellationToken ct)
        {
            await ReadAsync(client, ct);
        }
 
        private static async Task<Client> AcceptClient(CancellationToken ct)
        {
            var socket = await Task<Socket>.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null).ConfigureAwait(false);
            ct.ThrowIfCancellationRequested();
            var client = new Client();
            client.socket = socket;
            client.id = clients.Count;
            client.ip = socket.RemoteEndPoint.ToString();
            clients.Add(client);
            Console.WriteLine("Clients count is: " + clients.Count + " IP: " + client.ip);
            return client;
        }
 
        private static async void Stop()
        {
            await Task.Delay(7000);
            try
            {
                cts.Cancel();
            }
            finally
            {
            }
            for (int i = 0; i < clients.Count; i++)
            {
                clients[i].socket.Shutdown(SocketShutdown.Both);
            }
            
            Console.Write("Server Stopped! ");
        }
 
        private static async Task ReadAsync(Client client, CancellationToken ct)
        {
            while (!ct.IsCancellationRequested)
            {
                try
                {
                    client.socket.SetKeepAlive(1000, 1000);
                    string content = string.Empty;
 
                    var bytesRead = await Task.Factory.FromAsync(
                        client.socket.BeginReceive(client.buffer, 0, Client.BufferSize, SocketFlags.None, null, client.socket),
                            client.socket.EndReceive).ConfigureAwait(false);
                    ct.ThrowIfCancellationRequested();
 
                    if (bytesRead > 0) 
                    {
                        client.sb.Append(Encoding.UTF8.GetString(
                            client.buffer, 0, bytesRead));
                        content = client.sb.ToString();
 
                        //Check for end-of-file tag. If it is not there, read 
                        //more data.
                        if (content.EndsWith("±☭")) 
                        {
                            string[] fullCommands = content.Remove(content.Length - 1).Split('☭');
 
                            for (int i = 0; i < fullCommands.Length; i++)
                            {
                                string[] commands = fullCommands[i].Remove(fullCommands[i].Length - 1).Split('§');
                            
                                //string[] commands = content.Remove(content.Length - 2).Split('§');
                                //All the data has been read from the 
                                //client. Display it on the console.
                                Console.WriteLine("Read {0} bytes from socket. \nData : {1}",
                                    content.Length, content );
                                //для дебага
                                for (int j = 0; j < commands.Length; j++)
                                {
                                    Console.WriteLine($"Command {j}: " + commands[j]);
                                }
 
                                if (commands[0].Contains("GetServers"))
                                    CommandProcessor.GetServers(commands[0], client.socket);
                                else if (commands[0].Contains("Login"))
                                    CommandProcessor.Login(commands[0], commands[1], client.socket);
                                else if (commands[0].Contains("GetCharacterClasses"))
                                    CommandProcessor.GetCharacterClasses(commands[0], commands[1], client.socket);
                                else if (commands[0].Contains("CreateCharacter"))
                                    CommandProcessor.CreateCharacter(commands[0], commands[1], client.socket);
                                else if (!string.IsNullOrEmpty(commands[2]) && !string.IsNullOrEmpty(commands[3]))
                                {
                                    if(clients.Any(c => c.authToken == commands[2] && c.characterId == commands[3]))
                                    {
                                        CommandProcessor.CommandHandler(commands[0], commands[1], client.socket);
                                    }
                                    else
                                    {
                                        SocketClose(client);
                                        break;
                                    }
                                }
                                else
                                {
                                    SocketClose(client);
                                    break;
                                }
                                    
                                client.sb.Clear();
                                Array.Clear(commands, 0, commands.Length); //очищаем команды
                            }
                        }
                    }
                    else
                    {
                        //Disconnect clients
                        SocketClose(client);
                        break;
                    }
                }
                catch (SocketException se)
                {
                    Console.WriteLine(se.SocketErrorCode.ToString());
                    SocketClose(client);
                    break;
                }
            }
        }
 
        private static void SocketClose(Client client)
        {
            client.socket.Shutdown(SocketShutdown.Both);
            client.socket.Disconnect(false);
            client.socket.Close();
 
            if(!string.IsNullOrEmpty(client.characterId))
                ClientsHandler.UpdateUserConnectDisconnectTime(client.characterId, "lastSeen").GetAwaiter().GetResult();
 
            clients.Remove(client);
            Console.WriteLine($"User with ID: {client.id} and IP: {client.ip} is disconnected");
        }
 
        public static async Task SendAsync(Socket client, string data)
        {
            // Convert the string data to byte data using UTF8 encoding.
            byte[] byteData = Encoding.UTF8.GetBytes(data);
            try
            {
                var bytesSent = await Task.Factory.FromAsync(
                    client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, null, client),
                        client.EndSend).ConfigureAwait(false);
                Console.WriteLine("Sent {0} bytes to client with ID: {1}.", bytesSent, clients.FirstOrDefault(c => c.socket == client).id);
            }
            catch(SocketException e)
            {
                Console.WriteLine("Send: " + e.SocketErrorCode);
            }         
        }
 
        public static async Task SendToAllClientsAsync(string data)
        {
            for (int i = 0; i < clients.Count; i++)
            {
                await SendAsync(clients[i].socket, data);
            }
        }
        
        public static int Main(String[] args) 
        {
            StartListening().GetAwaiter().GetResult();
          
            return 0;
        }
    }
}
Добавлено через 46 минут
я тут потестил и получается если использовать один токен отмены то данной записи достаточно чтоб отключить сервер без проблем
Цитата Сообщение от kolorotur Посмотреть сообщение
var token = cts.Token;
using (var registration = token.Register(client.Close))
{
* *while (!token.IsCancellationRequested)
* *{
* * * Console.WriteLine("Waiting for a connection...");
* * * try
* * * {
* * * * *var client = await AcceptClient();
* * * * *var task = ClientService(client, token);
* * * }
* * * catch (OperationCancelledException) { break; }
* * * catch (ObjectDisposedException) when (token.IsCancellationRequested) { break; }
* *}
}
Цитата Сообщение от kolorotur Посмотреть сообщение
ct.ThrowIfCancellationRequested();
и запись не на что не влияет ))
0
Эксперт .NET
17688 / 12873 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
10.04.2018, 19:11 14
Цитата Сообщение от AlexeyTsoy Посмотреть сообщение
я тут потестил
Плохо потестили.
Многопоточные приложения вообще не сильно поддаются тестированию.
Например, если будет такая очередность инструкций:
1. Вызывается Cancel
2. Заканчивается вызов await
3. listener закрывается
4. Метод AcceptClient продолжает работать и завершает выполнение.
5. Запускается процесс считывания.

По-хорошему вызов ThrowIfCancellationRequested должен быть перед return, но у вас ранее идет добавление в список, потому я добавил его сразу после завершения асинхронного метода.
0
0 / 0 / 0
Регистрация: 24.01.2018
Сообщений: 22
10.04.2018, 19:29  [ТС] 15
а ок понял))Буду рад любым замечаниям
0
10.04.2018, 19:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.04.2018, 19:29
Помогаю со студенческими работами здесь

Task не останавливается
Всем доброго времени суток! Есть такой код(не обращайте внимание на частички кода из WPF, это не...

Отмена Task
Здраствуйте, Таск запускается при нажатии Calculate, проводит долгую операцию с двумя числами и...

Отмена Task
Добрый день, у меня очередной вопрос к Гуру..) Есть Таск, который можно отменить извне с помощью...

Работа с Task
Здравствуйте. Как проверить, завершилась ли задача запущенная с Task? Если не завершилась, то...

Задачи Task
Господа, имеется такой вот код, который распараллеливает выполнение задач на три &quot;ветви&quot; по одной...

Task и исключение
Я правильно понимаю, что если в Task происходит исключение, которое не ловится, то оно не рушит...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru