Файл: Реализовать приложениесервер в среде MicrosoftVisualStudioна языкеVisualC#.odt
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 09.12.2023
Просмотров: 113
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Клиентская часть является TCP-клиентом и схожа с серверной частью, за тем исключением, что перечень хранит также информацию о последней версии в теге
2.4. Описание процесса взаимодействия между серверной и клиентской частью.
Общая идея синтаксиса запросов: сначала идёт слово-название запроса, затем, после двоеточия, указываются параметры запроса, разделённые через запятую.
В настоящей системе реализованы две основные команды запроса.
Синтаксис команды запроса последней версии:
version:<название_приложения>
где <название_приложения> — название приложения, по которому необходимо получить информацию о последней версии.
Синтаксис запроса обновления приложения:
get:<название_приложения>,<версия>
где <название_приложения> — название приложения для обновления,<версия> — требуемая версия приложения.
2.5. Описание приложения-клиента и приложения-сервера.
Приложения написаны на языке VisualC#, являются приложениями платформе .NET, что позволяет им запускаться на всех устройствах, поддерживающих .NET.
В приложениях были использованы классы:
-
System.Net.UdpClient— представляет возможности по развёртыванию сервера, клиента и обработки запросов. -
System.Net.Sockets.IPEndPoint— представляет возможности для установления и настройки конечной точки сервера или клиента. -
System.Net.Sockets.IPAddress— представляет возможности для обработки информации обIP-адресах.
И были реализованы основные методы:
-
Run— проверяет доступность порта, устанавливает конечную точку и, если это возможно, запускает сервер/клиент. -
Stop— Останавливает сервер/клиент и освобождает ресурсы. -
Listen— Переводит сервер в режим прослушивания порта и обрабатывает входящие запросы. -
Update— Выполняет отправку запроса на обновление и выполняет принятие файла. -
GetVersion— Выполняет отправку запроса на получение последней версии приложения и обрабатывает эту информацию.
Также были реализованы другие методы, не выполняющие основные функции, но упрощающие взаимодействие отдельных объектов приложения и улучшающих внешний вид и удобство приложения.
Все необходимый настройки находятся прямо на основных окнах клиента и сервера с помощью стандартных компонентов, так что пользователь сможет с лёгкостью настроить сервер или клиент прямо в интерфейсе приложения.
2.6. Описание реализованных классов.
В приложениях системы были реализованы следующие классы:
-
AppInfo. Класс реализован в приложении-клиенте и выполяет функцию инкапсулирования данных об одном приложении. Хранение таких данных в списке (List) позволяет удобно сериализовать и десериализовать данные в файл-перечень приложений, используя стандартные средства языкаVisualc# (КлассXMLSerializer, методыSerializeиDeserializeсоответственно).
Поля
Тип данных
Описание
name
string
Название приложения
version
int
Текущая версия приложения
lastVersion
int
Последняя доступная версия приложения. 0, если последняя версия неизвестна
location
string
Расположение приложения
AppServer. Класс очень похож на классAppInfoи выполняет смежные функции. Класс реализован в приложении-сервере и выполяет функцию инкапсулирования данных об одном приложении, хранимом на сервере. Хранение таких данных в списке (List) позволяет удобно сериализовать и десериализовать данные в файл-перечень приложений, используя стандартные средства языкаVisualc# (КлассXMLSerializer, методыSerializeиDeserializeсоответственно). В отличие от классаAppInfoэтот класс не содержит информации об установленной версии.
Поля | Тип данных | Описание |
name | string | Название приложения |
version | int | Текущая версия приложения |
location | string | Расположение приложения |
+
Убедитесь, что рядом с исполняемым файлом сервера находится файл-перечень приложений Apps.xml, если он отсутствует, вы получите сообщение об ошибке (рис. 4). Для устранения найдитеApps.xmlи переместите в каталог с исполнительным файлом сервера или создайте новый файл.
Рисунок 4. Ошибка об отсутствующем Apps.xml.
Если во время загрузки всплыло сообщение об ошибке в файле Apps.xml(рис. 5), то это означает, файл был повреждён либо он содержит неверную разметку, откройте его и вручную устраните ошибку, если это возможно.
Рисунок 5. Сообщение об ошибке в Apps.xml.
Основную часть окна составляет таблица, которая является представлением перечня приложений, на нём отображается информация: название приложения, текущая версия приложения, последняя доступная версия и расположение приложения. Если о последней версии ничего не известно, то в соответствующем столбце будет стоять прочерк.
Перед работой клиента его необходимо настроить. Выставьте адрес сервера и порт. Внимание! На всех компьютерах сети (и клиентах и серверах) номера портов должны быть одинаковыми.
Далее нужно получить информацию о последних версиях приложений. Для этого щелчком на таблице выберите интересующее вас приложение и нажмите кнопку «Проверить наличие обновлений», если новая версия доступна, вы можете обновить это приложение.
Чтобы обновить приложение, выберите его и щёлкните на кнопке «Обновить». После этого приложение перейдёт в режим обновления и будет недоступно на время обновления. По завершению операции вы получите сообщение о результате обновления.
В разработанном приложении существуют следующие обработчики:
- обработчик, который не позволяет подключиться к не существуещему серверу
#region The private fields
private bool isFinished = false;
private List
private List
private ManualResetEvent evtDownload = null;
private ManualResetEvent evtPerDonwload = null;
private WebClient clientDownload = null;
#endregion
#region The constructor of DownloadProgress
public DownloadProgress(List
{
InitializeComponent();
this.downloadFileList = downloadFileListTemp;
allFileList = new List
foreach (DownloadFileInfo file in downloadFileListTemp)
{
allFileList.Add(file);
}
}
#endregion
#region The method and event
-обработчик,который позволяет проверить процесс загрузки данных на корректность и оптимизировать загрузку
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (!isFinished && DialogResult.No == MessageBox.Show(ConstFile.CANCELORNOT, ConstFile.MESSAGETITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Question))
{
e.Cancel = true;
return;
}
else
{
if (clientDownload != null)
clientDownload.CancelAsync();
evtDownload.Set();
evtPerDonwload.Set();
}
}
private void OnFormLoad(object sender, EventArgs e)
{
evtDownload = new ManualResetEvent(true);
evtDownload.Reset();
ThreadPool.QueueUserWorkItem(new WaitCallback(this.ProcDownload));
}
long total = 0;
long nDownloadedTotal = 0;
-обработчик события загрузки
private void ProcDownload(object o)
{
string tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
if (!Directory.Exists(tempFolderPath))
{
Directory.CreateDirectory(tempFolderPath);
}
evtPerDonwload = new ManualResetEvent(false);
foreach (DownloadFileInfo file in this.downloadFileList)
{
total += file.Size;
}
try
{
while (!evtDownload.WaitOne(0, false))
{
if (this.downloadFileList.Count == 0)
break;
DownloadFileInfo file = this.downloadFileList[0];
//Debug.WriteLine(String.Format("Start Download:{0}", file.FileName));
this.ShowCurrentDownloadFileName(file.FileName);
//Download
clientDownload = new WebClient();
//Added the function to support proxy
clientDownload.Proxy = System.Net.WebProxy.GetDefaultProxy();
clientDownload.Proxy.Credentials = CredentialCache.DefaultCredentials;
clientDownload.Credentials = System.Net.CredentialCache.DefaultCredentials;
//End added
clientDownload.DownloadProgressChanged += (object sender, DownloadProgressChangedEventArgs e) =>
{
try
{
this.SetProcessBar(e.ProgressPercentage, (int)((nDownloadedTotal + e.BytesReceived) * 100 / total));
}
catch
{
//log the error message,you can use the application's log code
}
};
clientDownload.DownloadFileCompleted += (object sender, AsyncCompletedEventArgs e) =>
{
try
{
DealWithDownloadErrors();
DownloadFileInfo dfile = e.UserState as DownloadFileInfo;
nDownloadedTotal += dfile.Size;
this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
evtPerDonwload.Set();
}
catch (Exception)
{
//log the error message,you can use the application's log code
}
};
evtPerDonwload.Reset();
//Download the folder file
string tempFolderPath1 = CommonUnitity.GetFolderUrl(file);
if (!string.IsNullOrEmpty(tempFolderPath1))
{
tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
tempFolderPath += tempFolderPath1;
}
else
{
tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
}
clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(tempFolderPath, file.FileFullName), file);
//Wait for the download complete
evtPerDonwload.WaitOne();
clientDownload.Dispose();
clientDownload = null;
//Remove the downloaded files
this.downloadFileList.Remove(file);
}
}
catch (Exception)
{
ShowErrorAndRestartApplication();
//throw;
}
//When the files have not downloaded,return.
if (downloadFileList.Count > 0)
{
return;
}
//Test network and deal with errors if there have
DealWithDownloadErrors();
//Debug.WriteLine("All Downloaded");
foreach (DownloadFileInfo file in this.allFileList)
{
string tempUrlPath = CommonUnitity.GetFolderUrl(file);
string oldPath = string.Empty;
string newPath = string.Empty;
try
{
if (!string.IsNullOrEmpty(tempUrlPath))
{
oldPath = Path.Combine(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1), file.FileName);
newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME + tempUrlPath, file.FileName);
}
else
{
oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME, file.FileName);
}
//just deal with the problem which the files EndsWith xml can not download
System.IO.FileInfo f = new FileInfo(newPath);
if (!file.Size.ToString().Equals(f.Length.ToString()) && !file.FileName.ToString().EndsWith(".xml"))
{
ShowErrorAndRestartApplication();
}
//Added for dealing with the config file download errors
string newfilepath = string.Empty;
if (newPath.Substring(newPath.LastIndexOf(".") + 1).Equals(ConstFile.CONFIGFILEKEY))
{
if (System.IO.File.Exists(newPath))
{
if (newPath.EndsWith("_"))
{
newfilepath = newPath;
newPath = newPath.Substring(0, newPath.Length - 1);
oldPath = oldPath.Substring(0, oldPath.Length - 1);
}
File.Move(newfilepath, newPath);
}
}
//End added
if (File.Exists(oldPath))
{
MoveFolderToOld(oldPath, newPath);
}
else
{
//Edit for config_ file
if (!string.IsNullOrEmpty(tempUrlPath))
{
if (!Directory.Exists(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1)))
{
Directory.CreateDirectory(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1));
MoveFolderToOld(oldPath, newPath);
}
else
{
MoveFolderToOld(oldPath, newPath);
}
}
else
{
MoveFolderToOld(oldPath, newPath);
}
}
}
catch (Exception exp)
{
//log the error message,you can use the application's log code
}
}
//After dealed with all files, clear the data
this.allFileList.Clear();
if (this.downloadFileList.Count == 0)
Exit(true);
else
Exit(false);
evtDownload.Set();
}
//To delete or move to old files
void MoveFolderToOld(string oldPath, string newPath)
{
if (File.Exists(oldPath + ".old"))
File.Delete(oldPath + ".old");
if (File.Exists(oldPath))
File.Move(oldPath, oldPath + ".old");
File.Move(newPath, oldPath);
//File.Delete(oldPath
+ ".old");
}
delegate void ShowCurrentDownloadFileNameCallBack(string name);
private void ShowCurrentDownloadFileName(string name)
{
if (this.labelCurrentItem.InvokeRequired)
{
ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);
this.Invoke(cb, new object[] { name });
}
else
{
this.labelCurrentItem.Text = name;
}
}
delegate void SetProcessBarCallBack(int current, int total);
private void SetProcessBar(int current, int total)
{
if (this.progressBarCurrent.InvokeRequired)
{
SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);
this.Invoke(cb, new object[] { current, total });
}
else
{
this.progressBarCurrent.Value = current;
this.progressBarTotal.Value = total;
}
}
delegate void ExitCallBack(bool success);
private void Exit(bool success)
{
if (this.InvokeRequired)
{
ExitCallBack cb = new ExitCallBack(Exit);
this.Invoke(cb, new object[] { success });
}
else
{
this.isFinished = success;
this.DialogResult = success ? DialogResult.OK : DialogResult.Cancel;
this.Close();
}
}
private void OnCancel(object sender, EventArgs e)
{
//bCancel = true;
//evtDownload.Set();
//evtPerDonwload.Set();
ShowErrorAndRestartApplication();
}
private void DealWithDownloadErrors()
{
try
{
//Test Network is OK or not.
Config config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstFile.FILENAME));
WebClient client = new WebClient();
client.DownloadString(config.ServerUrl);
}
catch (Exception)
{
//log the error message,you can use the application's log code
ShowErrorAndRestartApplication();
}
}
private void ShowErrorAndRestartApplication()
{
MessageBox.Show(ConstFile.NOTNETWORK,ConstFile.MESSAGETITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
CommonUnitity.RestartApplication();
}
#endregion
}
}
2.3 Отладка и тестирование программы
Отладка программ заключается в проверке правильности работы программы и аппаратуры. Программа, не содержащая синтаксических ошибок тем не менее может содержать логические ошибки, не позволяющие программе выполнять заложенные в ней функции. Логические ошибки могут быть связаны с алгоритмом программы или с неправильным пониманием работы аппаратуры, подключённой к портам микроконтроллера.
Встроенный в состав интегрированной среды программирования отладчик позволяет отладить те участки кода программы, которые не зависят от работы аппаратуры, не входящей в состав микросхемы микроконтроллера. Обычно это относится к вычислению математических выражений или преобразованию форматов представления данных.
Для отладки программ обычно применяют три способа:
1) Пошаговая отладка программ с заходом в подпрограммы;
2) Пошаговая отладка программ с выполнением подпрограммы как одного оператора;
3) Выполнение программы до точки останова.
Пошаговая отладка программ заключается в том, что выполняется один оператор программы и, затем контролируются те переменные, на которые должен был воздействовать данный оператор.
Если в программе имеются уже отлаженные подпрограммы, то подпрограмму можно рассматривать, как один оператор программы и воспользоваться вторым способом отладки программ.
Если в программе существует достаточно большой участок программы, уже отлаженный ранее, то его можно выполнить, не контролируя переменные, на которые он воздействует. Использование точек останова позволяет пропускать уже отлаженную часть программы. Точка останова устанавливается в местах, где необходимо проверить содержимое переменных или просто проконтролировать, передаётся ли управление данному оператору.
Практически во всех отладчиках поддерживается это свойство (а также выполнение программы до курсора и выход из подпрограммы). Затем отладка программы продолжается в пошаговом режиме с контролем локальных и глобальных переменных
Тестирование - это один из важнейших этапов процесса разработки программного продукта, который необходим для выявления ошибок программирования или других дефектов, с целью их последующего устранения, что в свою очередь положительным образом сказывается на его качестве.
Цель тестирования - обнаружить все имеющиеся дефекты, чтобы обеспечить полное соответствие программного продукта требованиям, которые к нему предъявляются. По окончанию работ, а часто и в процессе разработки, готовые модули или программный продукт проходят тщательное тестирование.
Уровни тестирования
- Модульное тестирование (юнит-тестирование) -- тестируется минимально возможный для тестирования компонент, например, отдельный класс или функция
- Интеграционное тестирование -- проверяет, есть ли какие-либо проблемы в интерфейсах и взаимодействии между интегрируемыми компонентами, например, не передается информация, передается некорректная информация.- Системное тестирование -- тестируется интегрированная система на её соответствие исходным требованиям
o Альфа-тестирование -- имитация реальной работы с системой штатными разработчиками, либо реальная работа с системой потенциальными пользователями/заказчиком на стороне разработчика. Часто альфа-тестирование применяется для законченного продукта в качестве внутреннего приёмочного тестирования. Иногда альфа-тестирование выполняется под отладчиком или с использованием окружения, которое помогает быстро выявлять найденные ошибки. Обнаруженные ошибки могут быть переданы тестировщикам для дополнительного исследования в окружении, подобном тому, в котором будет использоваться ПО. o Бета-тестирование -- в некоторых случаях выполняется распространение версии с ограничениями (по функциональности или времени работы) для некоторой группы лиц, с тем чтобы убедиться, что продукт содержит достаточно мало ошибок. Иногда бета-тестирование выполняется для того, чтобы получить обратную связь о продукте от его будущих пользователей. Модульное тестирование - это тестирование программы на уровне отдельно взятых модулей, функций или классов. Цель модульного тестирования состоит в выявлении локализованных в модуле ошибок в реализации алгоритмов, а также в определении степени готовности системы к переходу на следующий уровень разработки и тестирования.Функциональная пара - это определённый тип результата работы модуля, соответствующий конкретным входным данным. Такие функциональные пары для модулей программы представлены в виде таблиц.
Входные данные | Ожидаемый результат | Полученный результат | Меры | |
Ввод адресов в поле «Почтовые адреса»: «адрес электронной почты» : SMNIKE89@rambler.ru «домен» : pop.mail.ru «имя пользователя»: SMNIKE89 «пароль»: 123 «протокол получения почты» : РОР3 | Установление связи с почтовым сервером, вход на указанный адрес с логином и паролем | Связь установлена, пьсьма получены | Программа сработала корректно |
Таблица 3. - Набор тестовых данных
Характерной чертой проводимых работ является их теоретическая направленность. В качестве конечного результата проектирования может рассматриваться прототип интеллектуальной системы, демонстрирующий возможность применения теоретических разработок и не предполагающий выход на рынок научно-технической продукции. Таким образом, основными источниками затрат при работе над темой как части этапа проектирования жизненного цикла целенаправленной интеллектуальной системы являются капитальные предпроизводственные затраты, которые в определенной степени могут быть учтены и минимизированы.
Калькулирование осуществляется по калькуляционным статьям расходов.
Таблица 2.2. Основная заработная плата разработчиков ПП
Наименование | | Трудоёмкость | Трудо-ёмкость | Оклад, руб. | Затраты | |
Анализ требований | Специалист по ИО | 10 | 0,436 | 2190,00 | 954,84 | |
Определение спецификации | Специалист по ИО | 10 | 0,436 | 2190,00 | 954,84 | |
Проектирование | Программист | 14 | 0,655 | 3100,00 | 2030,50 | |
Кодирование | Программист | 19 | 0,873 | 3100,00 | 2706,30 | |
Тестирование | Специалист по тестированию | 38 | 1,745 | 2190,00 | 3821,55 | |
Сдача темы | Программист | 5 | 0,218 | 2900,00 | 632,20 | |
| | | | Итого | 11100,23 | |
| |