private bool ParseOptions(Packet.Packet packet) { switch (packet.Header.Option1) { case PacketOption1.Acknowledge: { var acknowledge = StructConvertor.FromBytes<Acknowledge>(packet.Data.Content); // Обработка пакета подверждения доставки сообщения // Если первый бит опций равен ACK и CRC в пакете совпала с последним отправленым пакетом для этого клиента // if (_clientArray[packet.Header.Sender].LastMessageCrc == BitConverter.ToUInt16(packet.ByteData, 0)) if (_clientArray[packet.Header.Sender].LastMessageCrc == acknowledge.DeliveredPacketCrc) { // Елси был доставлен пакет "запрос на передачу файла" то запустить таймер ожидания ответа if (_clientArray[packet.Header.Sender].LastPacket.Data.Type == DataType.FileRequest) { OnMessageRecived(new MessageRecivedEventArgs(MessageType.WaitFileRecipientAnswer, FileToTransfer.Name, packet.Header.Sender, packet.Header.Recipient)); _waitFileTransferAnswerTimer.Change(_waitFileTransferAnswerTimeOut, Timeout.Infinite); } // Если последний пакет данных успешно доставлен то увеличить количество переданных байт на величину пакета if (_clientArray[packet.Header.Sender].LastPacket.Data.Type == DataType.FileData) { ProcessedFileSize += _filePacketSize; } // Установить что последнее сообщение было доставлено _clientArray[packet.Header.Sender].AnswerEvent.Set(); return true; } } break; case PacketOption1.FileTransferAllowed: { // Обработка пакета разрешения на передачу файла // Если получено разрешение на передачу файлов и отправитель пакета является тем кому был отправлен запрос на передачу if (Client.AllowSendingFile && Client.FileRecipient == packet.Header.Sender) { // Событие о разрещении на передачу файла OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileTransferAllowed, FileToTransfer.Name, packet.Header.Sender, packet.Header.Recipient)); // Начать отправку файла // Отчищает очередь пакетов файла на передачу // TO DO: Добавить отчистку очереди? // Запрещает отправлять файла на последующие запросы до завершения передачи Client.AllowSendingFile = false; // Устанавливает что идет передача файла Client.IsSendingFile = true; // Обнуляет счетчик пакетов Client.CountOfFilePackets = 0; // Запускает поток для упаковки файла в пакеты и добавления их в очередь _fileSenderThread = new Thread(FileSender); _fileSenderThread.Start(packet.Header.Sender); } // Выслать подверждение получения пакета SendAcknowledge(packet); return true; } break; case PacketOption1.FileTransferDenied: { // Если получен пакет отмены передачи файла // Если файл принимался if (IsRecivingFile) { // Событие отмены перадачи файла отправителем OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileTransferCanceledBySender, _receivingFileName, packet.Header.Sender, packet.Header.Recipient)); CancelRecivingFile(); // Выслать подверждение получения пакета SendAcknowledge(packet); return true; } // Если файл отправлялся if (Client.IsSendingFile) { // Событие отмены перадачи файла получателем OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileTransferCanceledByRecipient, FileToTransfer.Name, packet.Header.Sender, packet.Header.Recipient)); CancelSendingFile(); // Выслать подверждение получения пакета SendAcknowledge(packet); return true; } // Если был отправлен только запрос на передачу файла if (Client.AllowSendingFile) { Client.AllowSendingFile = false; // Событие отказа от приема файла OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileTransferDenied, FileToTransfer.Name, packet.Header.Sender, packet.Header.Recipient)); } if (_waitFileTransferAnswer) { _waitFileTransferAnswer = false; // Отправитель отменил запрос OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileRequestCanceledRecipientSide, _receivingFileName, packet.Header.Sender, packet.Header.Recipient)); } // Выслать подверждение получения пакета SendAcknowledge(packet); return true; } break; case PacketOption1.FileTransferCompleted : { if (packet.Header.Option1 == PacketOption1.FileTransferCompleted) { ProcessedFileSize = 0; Client.IsSendingFile = false; // Событие доставки файла OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileSendingComplete, FileToTransfer.Name, packet.Header.Sender, packet.Header.Recipient)); SendAcknowledge(packet); return true; } } break; case PacketOption1.InitializationRequest: { SendAcknowledge(packet); if (_clientArray.ContainsKey(packet.Header.Sender)) { SendInitializationData(DateTime.UtcNow, _enabledClientIDs, packet.Header.Sender); } return true; } break; } return false; }
// TODO постараться вынести инициализацию в метод Read private InitializationData ReadInitialization(SerialPort readport) { while (true) { try { readport.ReadTo("\xAA\x55"); // Считывание данных для создания пакета // Здесь важен строгий порядок считывания байтов, точно как в пакете. byte recipient = (byte)readport.ReadByte(); byte sender = (byte)readport.ReadByte(); ushort dataLenght = BitConverter.ToUInt16( new byte[] { (byte)readport.ReadByte(), (byte)readport.ReadByte() }, 0); byte option1 = (byte)readport.ReadByte(); byte option2 = (byte)readport.ReadByte(); ushort crc = BitConverter.ToUInt16( new byte[] { (byte)readport.ReadByte(), (byte)readport.ReadByte() }, 0); // Счетчик количества итерация цикла while int count = 0; while (readport.BytesToRead < dataLenght) { count++; Thread.Sleep(_sleepTime); if (count > dataLenght) { break; } } byte[] data = new byte[dataLenght]; readport.Read(data, 0, dataLenght); var packet = new Packet.Packet(new Header(recipient, sender, option1, option2), data); // Проверка crc и id клиента, id отправителя и типа пакета if (packet.Header.Crc == crc && packet.Header.Recipient == ClietnId && packet.Header.Sender == 0 && packet.Data.Type == DataType.Initialization) { SendAcknowledge(packet); var initialization = StructConvertor.FromBytes<InitializationData>(packet.Data.Content); return initialization; } } catch (InvalidOperationException) { IsPortAvailable(readport); Thread.Sleep(3000); } catch (TimeoutException exception) { // TODO ограничить количество отправок запроса SendInitializationRequest(); } catch (Exception exception) { LogHelper.GetLogger<CommunicationUnit>().Error("Ошибка при чтение с порта", exception); } } }
private void SendAcknowledge(Packet.Packet packet) { // _clientArray[(int)packet.Header.Sender].AddPacketToQueue(BitConverter.GetBytes(Crc16.ComputeChecksum(packet.ByteData)), ClietnId, 0x06, 0x00, true); Acknowledge acknowledge = new Acknowledge(Crc16.ComputeChecksum(packet.ByteData)); _clientArray[(int)packet.Header.Sender].AddPacketToQueue(acknowledge, ClietnId, 0x06, 0x00, true); }
private void Read(object readport) { SerialPort readPort = (SerialPort)readport; while (Client.Continue) { try { readPort.ReadTo("\xAA\x55"); // Считывание данных для создания пакета // Здесь важен строгий порядок считывания байтов, точно как в пакете. byte recipient = (byte)readPort.ReadByte(); byte sender = (byte)readPort.ReadByte(); ushort dataLenght = BitConverter.ToUInt16( new byte[] { (byte)readPort.ReadByte(), (byte)readPort.ReadByte() }, 0); byte option1 = (byte)readPort.ReadByte(); byte option2 = (byte)readPort.ReadByte(); ushort crc = BitConverter.ToUInt16( new byte[] { (byte)readPort.ReadByte(), (byte)readPort.ReadByte() }, 0); // Счетчик количества итерация цикла while int count = 0; while (readPort.BytesToRead < dataLenght) { count++; Thread.Sleep(_sleepTime); if (count > dataLenght) { break; } } byte[] data = new byte[dataLenght]; readPort.Read(data, 0, dataLenght); var packet = new Packet.Packet(new Header(recipient, sender, option1, option2), data); if (_isServer) { if (packet.Header.Crc == crc) { if (packet.Header.Recipient != ClietnId || packet.Data.Type == DataType.BroadcastText) { // _clientArray[0].SendPacketNow(packet); _routerQueue.Enqueue(packet); // if ((packet.Data.Type == DataType.Text || packet.Data.Type == DataType.BroadcastText) && packet.Header.Option1 != PacketOption1.Acknowledge) // До обновления бродкастинга // Если пакет текстовый или пакет широковешательный и предназначен для этого клиента и это не ACK то пакет парсится if ((packet.Data.Type == DataType.Text || (packet.Data.Type == DataType.BroadcastText && packet.Header.Recipient == ClietnId)) && packet.Header.Option1 != PacketOption1.Acknowledge) { ParsePacket(packet); } continue; } //Функция разбора пакета ParsePacket(packet); } } else { // Проверка crc и id клиента, то есть предназначен ли этот пакет этому клиенту или пакет является широковешательным // if (packet.Header.Crc == crc && (packet.Header.Recipient == ClietnId || packet.Data.Type == DataType.BroadcastText )) // // До обновления бродкастинга if (packet.Header.Crc == crc && packet.Header.Recipient == ClietnId) { //Функция разбора пакета ParsePacket(packet); } } } catch (InvalidOperationException) { IsPortAvailable(readPort); // Передает событие с текстом ошибки // OnMessageRecived(new MessageRecivedEventArgs(MessageType.ReadPortUnavailable, _comPortReader.PortName, 255)); // ReOpenPort(_comPortReader); Thread.Sleep(3000); } catch (TimeoutException exception) { } catch (Exception exception) { LogHelper.GetLogger<CommunicationUnit>().Error("Ошибка при чтение с порта: " + readPort.PortName, exception); } } }
private void ParsePacket(Packet.Packet packet) { // Функция вовращает true если найдена опция и дальнейший разбор данных не требуется. if (ParseOptions(packet)) { return; } switch (packet.Data.Type) { // Обработка пакета текстового сообщения case DataType.Text: { var text = StructConvertor.FromBytes<Text>(packet.Data.Content); // Определяет необходимость разархивирования if (packet.Header.Option2 == PacketOption2.Compressed) { text.Content = Compressor.Unzip(packet.Data.Content); } // Событие передает тип пакета и текст для пользователя OnMessageRecived(new MessageRecivedEventArgs(MessageType.Text, Encoding.UTF8.GetString(text.Content), packet.Header.Sender, packet.Header.Recipient)); // Выслать ACK SendAcknowledge(packet); } break; // Обработка пакета текстового сообщения case DataType.BroadcastText: { var broabroadcastText = StructConvertor.FromBytes<BroadcastText>(packet.Data.Content); // Определяет необходимость разархивирования if (packet.Header.Option2 == PacketOption2.Compressed) { broabroadcastText.Content = Compressor.Unzip(packet.Data.Content); } // Событие передает тип пакета и текст для пользователя OnMessageRecived(new MessageRecivedEventArgs(MessageType.BroadcastText, Encoding.UTF8.GetString(broabroadcastText.Content), packet.Header.Sender, packet.Header.Recipient)); // Выслать ACK SendAcknowledge(packet); } break; // Обработка пакета запроса на передачу файла case DataType.FileRequest: { var fileRequest = StructConvertor.FromBytes<FileRequest>(packet.Data.Content); // Выслать подверждение получения пакета SendAcknowledge(packet); // Если не принимается и не передается файл if (!Client.IsSendingFile && !IsRecivingFile) { var ea = new FileRequestRecivedEventArgs(fileRequest.FileName, fileRequest.FileLenght, packet.Header.Sender); OnFileRequestRecived(ea); _waitFileTransferAnswer = true; // Сохраняет параметры файла _receivingFileName = fileRequest.FileName; ReceivingFileSize = fileRequest.FileLenght; // Сохраняет id отправителя файла _fileSender = packet.Header.Sender; _waitFileTransferAnswerTimer.Change(_waitFileTransferAnswerTimeOut, Timeout.Infinite); } else { SendFileTransferCancel(packet.Header.Sender); // Событие - сообщение о ошибке OnMessageRecived(new MessageRecivedEventArgs(MessageType.Error, "Клиенту № " + packet.Header.Sender + " Было отказано в передачи файла " + fileRequest.FileName + " размером " + fileRequest.FileLenght / 1024 / 1024 + "МБ, так как в данный момент уже осуществляется прием другого файла ", 0, 0)); } } break; // Обработка пакета файла case DataType.FileData : { var fileData = StructConvertor.FromBytes<FileData>(packet.Data.Content); // Если совпал номер пакета и разрешено получение файлов и файл существует и id отправителя совпал с id отправителя файла if (Client.CountOfFilePackets == fileData.PacketNumber && IsRecivingFile && File.Exists(ReceivingFileFullName) && packet.Header.Sender == _fileSender) { ProcessedFileSize += _filePacketSize; // Устанавливает что пакет получен _waitForFilePacketEvent.Set(); // Выслать подверждение получения пакета SendAcknowledge(packet); // Разархивация данных // fileData.Content = Compressor.Unzip(packet.Data.Content); // var unzipContent = Compressor.Unzip(packet.Data.Content); // Запись данных в файл if (!ByteArrayToFile(ReceivingFileFullName, fileData.Content)) { OnMessageRecived(new MessageRecivedEventArgs(MessageType.Error, "Ошибка при записи в файл", packet.Header.Sender, 0)); OnMessageRecived( new MessageRecivedEventArgs(MessageType.FileTransferCanceledRecipientSide, _receivingFileName, _fileSender, 0)); CancelRecivingFile(); break; } // Инкрементирует число принятых пакетов Client.CountOfFilePackets++; // Если пакет последний в цепочке if (fileData.LastPacket) { // Событие о заверщении приема файла OnMessageRecived(new MessageRecivedEventArgs(MessageType.FileReceivingComplete, _receivingFileName, packet.Header.Sender, packet.Header.Recipient)); SendFileTransferCompleted(packet.Header.Sender); // Закрывает поток записи файла _fileStream.Close(); IsRecivingFile = false; } } else { #if DEBUG // Событие - сообщение о ошибке OnMessageRecived(new MessageRecivedEventArgs(MessageType.Error, "Пакет файла: не совпал номер пакета, принятый номер " + fileData.PacketNumber + "сохраненый номер " + Client.CountOfFilePackets, packet.Header.Sender, 0)); #endif } } break; case DataType.Initialization: { // Выслать подверждение получения пакета SendAcknowledge(packet); } break; } }
public bool SendPacketNow(Packet.Packet packet) { if (!TryWrite(ComPortWriter, packet)) { // Передает событие с текстом ошибки // OnAcknowledgeRecived(new MessageRecivedEventArgs(MessageType.Error, "Порт " + _comPortWriter.PortName + " недоступен, отправка невозможна.", 0)); return false; } return true; }
public bool AddPacketToQueue(object data, byte sender, byte option1 = 0x00, byte option2 = 0x00, bool sendPacketImmediately = false) { Packet.Packet packet = new Packet.Packet(new Header(Id, sender, option1, option2), data); // TO DO: Поправить логику условий // Валидация данных if (sendPacketImmediately) { if (!TryWrite(ComPortWriter, packet)) { // Передает событие с текстом ошибки OnAcknowledgeRecived(new MessageRecivedEventArgs(MessageType.Error, "Порт " + ComPortWriter.PortName + " недоступен, отправка невозможна.", 0,0)); } return true; } if (packet.Data.Type == DataType.FileData) { OutFilePacketsQueue.Enqueue(packet); return true; } //Добавляем пакет в очередь на отправку OutMessagesQueue.Enqueue(packet); return true; }
public static bool TryWrite(SerialPort port, Packet.Packet packet) { try { lock (port) { port.Write(packet.ToByte(), 0, packet.ToByte().Length); } return true; } catch (Exception exception) { LogHelper.GetLogger<Client>().Error("Не удалось произвести запись в порт: " + port.PortName, exception); CommunicationUnit.IsPortAvailable(port); CommunicationUnit.ReOpenPort(port); return false; } return false; }