Можно ли использовать asyn c -aaait при передаче файлов tcp в C#? - PullRequest
0 голосов
/ 30 апреля 2020

Прежде всего, не судите меня, пожалуйста, я довольно новичок в программировании. Я пытаюсь создать приложение P C -> android, которое отправляет выбранные файлы на мой телефон. Это работает, все хорошо, за исключением того, что методы не являются асинхронными. Таким образом, если я отправляю что-то на свой телефон, мой пользовательский интерфейс останавливается до завершения отправки. Может кто-нибудь мне помочь? Я читал все документы по методам asyn c, но я просто не могу получить его, как мне его реализовать?

Вот необходимый код:

Это событие, которое «отправляет» файлы, я хочу, чтобы оно было асин c.

        private void button2_Click(object sender, EventArgs e) {
            await push();
        }

        public async Task push() {
            if (folder != null) {
                string ip = textBox1.Text + "." + textBox2.Text + "." + textBox3.Text + "." + textBox4.Text;
                listBox1.Items.Add("Creating a test server on the machine on port " + 8001 + ". Host ip: " + ip);
                server = new Server(ip, 8001);
                listBox1.Items.Add("Server running.");
                int i = 0;
                listBox1.Items.Add("Fetching files...");
                getFileNum(folder, ref i);
                listBox1.Items.Add("Files scanned. Current number: " + i + " files.");

                //send number of files to be transmitted
                listBox1.Items.Add("Getting your files ready... please standby.");
                server.send(i.ToString());
                listBox1.Items.Add("Your files are ready, beggining the transmitting process.");

                //actual method for sending files
                sendFiles(folder);
                listBox1.Items.Add(".");
                listBox1.Items.Add(".");
                listBox1.Items.Add("Files sent!");

            }
            else {
                MessageBox.Show("No directory path selected.", "Error_null_path");
            }
        }
        public async Task<Task> sendFiles(DirectoryInfo dir) {

            FileInfo[] files = dir.GetFiles();
            DirectoryInfo[] dirs = dir.GetDirectories();
            string path = dir.FullName + "/";
            foreach (FileInfo file in files) {
                await server.sendFile(path + file.Name, folder.FullName.Replace(folder.Name,""));
                listBox1.Items.Add("Sent file: " + file.Name);
            }
            foreach (DirectoryInfo subDir in dirs) {
                await sendFiles(subDir);
            }
            return null;
        }

это отправляющая часть кода в классе «Сервер»:

        public async Task sendFile(string filePath, string root) {
            FileInfo file = new FileInfo(filePath);
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Parse(ip), port));

            //send song name length

            server.Listen(0);
            Socket client = server.Accept();
            byte[] send;
            if (filePath.Replace(root, "").Length < 10)
                send = new UTF8Encoding(true).GetBytes("0" + filePath.Replace(root, "").Length);
            else
                send = new UTF8Encoding(true).GetBytes(filePath.Replace(root, "").Length.ToString());
            client.Send(send);
            client.Close();
            server.Close();

            //send song name

            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
            server.Listen(0);
            client = server.Accept();
            send = new UTF8Encoding(true).GetBytes(filePath.Replace(root,""));
            client.Send(send);
            client.Close();
            server.Close();

            //send the song

            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
            server.Listen(0);
            client = server.Accept();
            client.SendFile(file.FullName);
            client.Close();

            server.Close();
            //return null;
        }
        public async Task send(string data) {
            switch (data.Length) {
                case 1:
                    data = "000" + data;
                    break;
                case 2:
                    data = "00" + data;
                    break;
                case 3:
                    data = "0" + data;
                    break;
                default:
                    data = "0000";
                    break;
            }
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
            server.Listen(0);
            Socket client = server.Accept();
            byte[] send = new UTF8Encoding(true).GetBytes(data);
            client.Send(send);
            client.Close();
            server.Close();
            //return null;
        }

1 Ответ

1 голос
/ 01 мая 2020

Я довольно новичок в программировании

Совет: обратите внимание на предупреждения компилятора. Они укажут на очень полезные вещи. Как и для этого кода, будет предупреждение компилятора о том, что вы пометили метод async, но он будет работать синхронно.

Сокеты TCP / IP очень сложны для новичка. Черт, они очень сложны для продвинутых разработчиков. Асинхронный код также сложен, и асинхронные сокеты - это огненная буря сложности.

Итак, для вашего случая, поскольку у вас уже есть работающее решение, я бы сказал, что нужно использовать Task.Run, чтобы получить sh ваш существующий синхронный код для потока пула потоков. Это приемлемый шаблон для приложений пользовательского интерфейса, но вы не захотите делать это для любых серверных приложений (например, ASP. NET).

public async Task push() {
  ...
  var progress = new Progress<string>(report => listBox1.Items.Add(report));
  await Task.Run(() => sendFiles(folder, progress));
  listBox1.Items.Add(".");
  listBox1.Items.Add(".");
  listBox1.Items.Add("Files sent!");
  ...
}

public void sendFiles(DirectoryInfo dir, IProgress<string> progress) {
  ...
  foreach (FileInfo file in files) {
    server.sendFile(path + file.Name, folder.FullName.Replace(folder.Name,""));
    progress?.Report("Sent file: " + file.Name);
  }
  foreach (DirectoryInfo subDir in dirs) {
    sendFiles(subDir);
  }
}

public void sendFile(string filePath, string root) {
  ...
}

Это не качественное решение, но это должен быть шаблон, который поможет вам начать работу.

...