Передача файлов по локальной сети C# (с чатом, на сокетах)

Недавно, (примерно 1-2 недели назад) мне на почту пришло около 5-6 сообщений с просьбой, что де я представил способ передачи сообщений по локальной сети, но вот передачу файлов так и не показал.
Выполняю Ваше желание ;)
Передача файлов по локальной сети
Реализовывать, собственно, передачу файлов по локальной сети будем посредством сокетов (Socket) на языке C#
Предлагаю, прежде чем перейти к чтению данной статьи, посмотреть, что мы делали здесь Передача сообщений, потому что здесь мы будем дописывать именно это приложение.
Задача: организовать передачу файлов, в описанном ранее клиенте локальной сети.
Решение
Решим данную задачу самым простым способом.
Сообщения передаются в нашем клиенте, как поток байтов. Файлы также можно представить как поток байт.
Необходимо разграничивать сообщения и файлы. Поэтому сделаем самый простейший способ разграничения – сообщения будут передаваться через один порт, а файлы – через другой.
Причем первое сообщение в файловом потоке зарезервируем под название файла – которое будет получать клиент и под которым он будет сохранять принятый файл. (пусть на это возьмем 256 байт)
Начнем с кода приема файлов. Он будет практически аналогичным коду работы с сообщениями, с той разницей, что
1) Первые 256 байт он должен перевести в путь.
2) Последующие данные он записывает в MemoryStream, а затем сохраняет полученные данные в файл Примечание: лучшим вариантом является – сразу же записывать после получения данных, но это легко реализуемо, и если Вам будет необходимо – просто записывайте в файл после каждой операции чтения
Итак, прием данных будет иметь следующий вид:
  1. //Метод потока
  2.      protected void FileReceiver()
  3.      {
  4.         //Создаем Listener на порт "по умолчанию"
  5.         TcpListener Listen = new TcpListener(6999);
  6.         //Начинаем прослушку
  7.         Listen.Start();
  8.         //и заведем заранее сокет
  9.         Socket ReceiveSocket;
  10.        while (true)
  11.         {
  12.            try
  13.            {
  14.              //Пришло сообщение
  15.              ReceiveSocket = Listen.AcceptSocket();
  16.              Byte[ ] Receive = new Byte[ 256];
  17.              //Читать сообщение будем в поток
  18.              using (MemoryStream MessageR = new MemoryStream())
  19.              {
  20.                 
  21.                 //Количество считанных байт
  22.                Int32 ReceivedBytes;
  23.                Int32 Firest256Bytes = 0 ;
  24.                String FilePath = "" ;
  25.                do
  26.                  {//Собственно читаем
  27.                    ReceivedBytes = ReceiveSocket.Receive(Receive, Receive.Length, 0 );
  28.                    //Разбираем первые 256 байт
  29.                    if (Firest256Bytes < 256 )
  30.                    {
  31.                      Firest256Bytes += ReceivedBytes;
  32.                      Byte[ ] ToStr = Receive;
  33.                      //Учтем, что может возникнуть ситуация, когда они не могу передаться "сразу" все
  34.                      if (Firest256Bytes > 256 )
  35.                      {
  36.                        Int32 Start = Firest256Bytes - ReceivedBytes;
  37.                        Int32 CountToGet = 256 - Start;
  38.                         Firest256Bytes = 256 ;
  39.                         //В случае если было принято >256 байт (двумя сообщениями к примеру)
  40.                         //Остаток (до 256 ) записываем в "путь файла"
  41.                         ToStr = Receive.Take(CountToGet).ToArray();
  42.                         //А остальную часть - в будующий файл
  43.                         Receive = Receive.Skip(CountToGet).ToArray();
  44.                         MessageR.Write(Receive, 0 , ReceivedBytes);
  45.                      }
  46.                      //Накапливаем имя файла
  47.                      FilePath += Encoding.Default.GetString(ToStr);
  48.                    } else
  49.                    //и записываем в поток
  50.                    MessageR.Write(Receive, 0 , ReceivedBytes);
  51.                    //Читаем до тех пор, пока в очереди не останется данных
  52.                 } while (ReceivedBytes == Receive.Length);
  53.                 //Убираем лишние байты
  54.                String resFilePath = FilePath.Substring(0, FilePath.IndexOf(''\\0'' ));
  55.                using (var File = new FileStream(resFilePath, FileMode.Create))
  56.                 {//Записываем в файл
  57.                    File.Write(MessageR.ToArray(), 0 , MessageR.ToArray().Length);
  58.                 }//Уведомим пользователя
  59.                 ChatBox.BeginInvoke(AcceptDelegate, new object[ ] { "Received: " + resFilePath, ChatBox });
  60.              }
  61.            }
  62.            catch (System.Exception ex)
  63.            {
  64.              MessageBox.Show(ex.Message);
  65.            }
  66.         }
  67.      }

This code was highlighted with code.xnim.ru

Данный метод также как и метод приема сообщений выполняется в отдельном потоке.
Теперь познакомимся с отправкой файла.
Первым делом создадим кнопку, которую назовем незатейливо –«отправка файла»
Отправлять файл (вообще-то) правильно как и сообщение в отдельном потоке. Но как создать отдельный поток для такой задачи я уже описывал, поэтому приведу код «внутри» обработчика нажатия кнопки, ибо перевести его в отдельный поток будет также просто как и при отправке сообщения
Что делает код отправки?
1) Создаст сокет
2) Приконнектится
3) Получит от пути к файлу его название
4) Отправит название
5) Начнет считывание файла, попутно отправляя «куски» файла
6) Закончит работу, закроет сокет
Итак, привожу код кнопки:
  1. private void button1_Click(object sender, EventArgs e)
  2.      {//Отправляем файл
  3.         //Добавим на форму OpenFileDialog и вызовем его
  4.         if (openFileDialog1.ShowDialog() == DialogResult.OK)
  5.         {
  6.            //Коннектимся
  7.            IPEndPoint EndPoint = new IPEndPoint(IPAddress.Parse(IP.Text), 6999 );
  8.            Socket Connector = new Socket(EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  9.            Connector.Connect(EndPoint);
  10.            //Получаем имя из полного пути к файлу
  11.            StringBuilder FileName = new StringBuilder(openFileDialog1.FileName);
  12.            //Выделяем имя файла
  13.            int index = FileName.Length - 1 ;
  14.            while (FileName[index] != ''\\\\'' && FileName[index] != ''/'' )
  15.            {
  16.              index--;
  17.            }
  18.            //Получаем имя файла
  19.            String resFileName = "" ;
  20.            for (int i = index + 1 ; i < FileName.Length; i++)
  21.              resFileName += FileName[i];
  22.            //Записываем в лист
  23.            List <Byte > First256Bytes = Encoding.Default.GetBytes(resFileName).ToList();
  24.            Int32 Diff = 256 - First256Bytes.Count;
  25.            //Остаток заполняем нулями
  26.            for (int i = 0 ; i < Diff; i ++ )
  27.              First256Bytes.Add(0);
  28.           //Начинаем отправку данных
  29.            Byte[ ] ReadedBytes = new Byte[ 256];
  30.            using (var FileStream = new FileStream(openFileDialog1.FileName,FileMode.Open))
  31.            {
  32.              using (var Reader = new BinaryReader(FileStream))
  33.              {
  34.                  Int32 CurrentReadedBytesCount;
  35.                 //Вначале отправим название файла
  36.                 Connector.Send(First256Bytes.ToArray());
  37.                 do{
  38.                    //Затем по частям - файл
  39.                    CurrentReadedBytesCount = Reader.Read(ReadedBytes, 0 , ReadedBytes.Length);
  40.                    Connector.Send(ReadedBytes,CurrentReadedBytesCount,SocketFlags.None);
  41.                 }
  42.                while (CurrentReadedBytesCount == ReadedBytes.Length);
  43.              }
  44.            }
  45.            //Завершаем передачу данных
  46.            Connector.Close();
  47.         }
  48.      }

This code was highlighted with code.xnim.ru

Как и прошлый раз – прикрепляю полученный проект. SocketLocalChatAndFileSender.7z
2012-12-24