7. Програмне забезпечення серверу

Інтерейс серверу зображено на рисунку 6.1.

Рисунок 6. 1 – Інтерфейс серверу

Спочатку користувач вводит адрес серверу, а потім запускає його. Після цього кнопка стане неактивованою.

Сервер також використовую блокуючи сокети. Це приводить до того, що необхідно створювати нові потоки для кожної блокуючої функції. Це з одного боку спрощує роботу з самими сонетами, але ускладнює задачу взаємодії потоків, коли вони використовують одні й ті ж змінні, коли один потік закриваює інший. Велика кількість потоків прискорює роботу серверу на багатопроцесорних системах, але загальмовує її на одно процесорних, бо операційній системі необхідно перемикатися між задачами.

Сервер має постійним потік прийому сокетів та контролю таймаутій. Також програма створює новий потік для кожного клієнта.

Алгоритм прийому клієнтів має наступний вигляд:

while (1)

{

sockAccept = accept(sListen, NULL, NULL);

if ((sockAccept == INVALID_SOCKET) && (WSAGetLastError() == WSAENOTSOCK))

break;

EnterCriticalSection (&cs);

if ((sockAccept != INVALID_SOCKET) && (iNumClients < MAX_CLIENT ))

{

sockInfo[iNumClients].sClient = sockAccept;

sockInfo[iNumClients].typeSender = 0;

sockInfo[iNumClients].time = time(NULL);

sockInfo[iNumClients].hClientThread =(HANDLE) _beginthreadex(NULL, 0,

ClientThread, (LPVOID)iNumClients, 0, &iThreadId);

sockInfo[iNumClients].time = time(NULL);

iNumClients ++ ;

LeaveCriticalSection (&cs);

}

else

{

LeaveCriticalSection (&cs);

shutdown(sockAccept, SD_BOTH);

closesocket(sockAccept);

}

}

return 0;

Алгоритм контролю часу клієнтів працює в залежності від типу клієнта. Якщо це КОМ, то timeout дорівнює 1 хвилині, інакше це 10 хвилин.

while (1)

{

dwWaitState = WaitForSingleObject(hEvent, timeToSleep);

if (dwWaitState == WAIT_OBJECT_0)

break;

EnterCriticalSection (&cs);

for (i = 0; i< iNumClients; i++)

{

if ((sockInfo[i].typeSender == 5) || (sockInfo[i].typeSender == 0))

{

if ((time(NULL) - sockInfo[i].time)>600)

{

DeleteSockInfo(i , 1);

}

}

else

{

if ((time(NULL) - sockInfo[i].time)>60)

{

DeleteSockInfo(i , 1);

}

}

}//for

LeaveCriticalSection (&cs);

}//while

return 0;

Треба зазначити, що сокети клієнтів можуть закриватися при таймауті, при закритті серверу. Тому є спеціальний масив char bAlowCloseClient[MAX_CLIENT] , який указує потоку клієнта, що не потрібно видаляти сокет, бо це буде зроблено іншим модулем програми. В іншому разі, якщо виникла звичайна помилка, то потік клієнта самостійно закриє цей сокет.

Модуль обробки клієнта приймає запити та відповідно отриманих даних виконує дії. Сервер приймає запит req у якому знаходиться тип запиту, ідентифікатор клієнту та довина запросу.

nLeft = sizeof(request);

idx = 0;

while(nLeft > 0)

{

ret = recv(sockInfo[nClient].sClient, ((char *) &req)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}

Необхідно звернути увагу на те, як повідомлення закриття програми обробляється у сервері. Це важливо, бо необхідно зарити усі потоки, та видалити усі динамічні змінні.

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{

int i;

if (!bServWorking)

return;

// Закрытие потока Control и события ожидания

SetEvent (hEvent);

WaitForSingleObject(hThreadControl, INFINITE);

CloseHandle (hThreadControl);

CloseHandle (hEvent);

//закрытие сокета сервера и потока Accept

shutdown(sListen, SD_BOTH);

closesocket(sListen);

WaitForSingleObject(hThreadAccept, INFINITE);

CloseHandle (hThreadAccept);

//закрытие сокетов клиентов -> закрытие потоков

EnterCriticalSection (&cs);

for (i = 0; i<iNumClients; i++)

{

bAlowCloseClient[i] = 1;

shutdown(sockInfo[i].sClient, SD_BOTH);

closesocket(sockInfo[i].sClient);

WaitForSingleObject(sockInfo[i].hClientThread, INFINITE);

CloseHandle (sockInfo[i].hClientThread);

}

LeaveCriticalSection (&cs);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

WSACleanup();

}

8. Програмне забезпечення робочих станцій

Інтерфейс робочої станції зображено на рисунку 7. 1.

Рисунок 7. 1 – Інтерфейс робочої станції

Спочатку користувач повинен ввести адресу та порт серверу та натиснути відповідну кнопку. При помилці з’явиться відповідне повідомлення та процедуру необхідно буде повторити. Також користувач сам може відсоєдинитись від сервера, натиснувши кнопку. Якщо помилка не з’явилась, то програма ще й синхронізує клієнта з сервером. Процес синхронізації такий ж самий як і в КОМ.

if (connect(sClient, (struct sockaddr *)&server,

sizeof(server)) == SOCKET_ERROR)

{

Application->MessageBoxA("Неудалось подключится к серверу", "Error!", MB_OK);

Form1->Button1->Enabled = TRUE;

return;

}

req.typeRequest = 0; //запрос на синхронизацию

req.typeSender = 5; //идентификатор рабочей станции

req.lengthPack = sizeof(request);

//отправка запроса на синхронизацию времени

nLeft = req.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sClient, ((char *)&req) + idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

Application->MessageBoxA("Ошибка отправки запроса на синхронизацию", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

//приём времени сервера и установка его в системе

nLeft = sizeof(time_t);

idx = 0;

while(nLeft > 0)

{

ret = recv(sClient, ((char *)&UpdateTime)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма времени", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

// установка времени в системе

stime(&UpdateTime);

Далі програма очікує введення даних: типу КОМ, початкового та кінцевого часів. Після введення необхідно натиснути кнопку відправки запиту. Спочатку програма преобразує час. Якщо виникне якась помилка з часом, то з’явиться відповідне повідомлення.

//формирование структур времени

tmBegin.tm_sec = Form1->ComboBox3->ItemIndex;

tmBegin.tm_min = Form1->ComboBox2->ItemIndex;

tmBegin.tm_hour = Form1->ComboBox6->ItemIndex;

tmBegin.tm_mday = Form1->ComboBox8->ItemIndex+1;

tmBegin.tm_mon = Form1->ComboBox10->ItemIndex;

tmBegin.tm_year = Form1->ComboBox12->ItemIndex+70;

tmBegin.tm_isdst = 0;

time_tBegin = mktime(&tmBegin);

if (time_tBegin == -1)

{

Application->MessageBoxA("Ошибка преобразования начального времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

tmEnd.tm_sec = Form1->ComboBox5->ItemIndex;

tmEnd.tm_min = Form1->ComboBox4->ItemIndex;

tmEnd.tm_hour = Form1->ComboBox7->ItemIndex;

tmEnd.tm_mday = Form1->ComboBox9->ItemIndex+1;

tmEnd.tm_mon = Form1->ComboBox11->ItemIndex;

tmEnd.tm_year = Form1->ComboBox13->ItemIndex+70;

tmEnd.tm_isdst = 0;

time_tEnd = mktime(&tmEnd);

if (time_tBegin == -1)

{

Application->MessageBoxA("Ошибка преобразования конечного времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

if (time_tEnd < time_tBegin)

{

Application->MessageBoxA("Конечное время меньше начального", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

Далі програма відправить запит та надасть отримані дані або повідомить про відсутність даних у цьому діапазоні.

reqRange.typeRequest = 2;

reqRange.typeSender = 5;

reqRange.lengthPack = sizeof (requestRange);

reqRange.iTypeUVM = iTypeUVM;

reqRange.tBegin = time_tBegin;

reqRange.tEnd = time_tEnd;

nLeft = reqRange.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sClient, ((char *)&reqRange) + idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

Application->MessageBoxA("Ошибка отправки запроса на приём данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

nLeft = sizeof(packageServer);

idx = 0;

while(nLeft > 0)

{

ret = recv(sClient, ((char *)&packServ)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма количества данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

if (packServ.AmountPacks == 0)

{

Application->MessageBoxA("Нет данных в заданном диапазоне времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

StringGrid1->RowCount = packServ.AmountPacks+1;

for (i = 0; i<packServ.AmountPacks; i++)

{

if (iTypeUVM == 1)

nLeft = sizeof(package1);

else

nLeft = sizeof(package2);

idx = 0;

while(nLeft > 0)

{

if (iTypeUVM == 1)

ret = recv(sClient, ((char *)&pack1)+idx, nLeft, 0);

else

ret = recv(sClient, ((char *)&pack2)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма структуры данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}//while

Додаток А. Вихідний текст КОМ

//---------------------------------------------------------------------------

#include <time.h>

#include <vcl.h>

#pragma hdrstop

#pragma argsused

#include <winsock2.h>

#include "UVM.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

#include <process.h>

typedef unsigned char uc;

typedef unsigned short int ui;

#pragma pack (push)

#pragma pack (1)

typedef struct

{

uc typeRequest;

uc typeSender;

uc lengthPack;

time_t time;

uc speed1;

uc speed2;

ui temperature1;

ui temperature2;

ui temperature3;

ui weight1;

ui weight2;

ui weight3;

uc length1;

uc length2;

} package1;

typedef struct

{

uc typeRequest;

uc typeSender;

uc lengthPack;

time_t time;

uc speed1;

uc speed2;

uc speed3;

ui temperature1;

ui temperature2;

ui weight1;

ui weight2;

ui weight3;

ui weight4;

uc length;

} package2;

typedef struct

{

uc typeRequest; //0 - запрос на синхронизацию

//1 - данные от УВМ

//2 - запрос от клиента

uc typeSender; //1..4 номер УВМ

//5 клиент

uc lengthPack;

} request;

#pragma pack (pop)

TForm1 *Form1;

SOCKET sUvm;

HANDLE hEvent, hThreadUVM;

char bEndThread = 0;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

unsigned __stdcall UVMThread(LPVOID lpParam)

{

WSADATA wsd;

struct sockaddr_in server;

AnsiString sAddress, sPort, sNumUVM;

char * cAddress, * cPort, * cNumUVM;

char cBufTime[4], i;

unsigned int lenAdr, lenPort, iPort, iUVM,

idx, nLeft, ret;

uc bConnect, bTimeSync;

uc period;

request req;

package1 pack1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

package2 pack2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

char * pPack;

time_t curTime, lastUpdateTime, lastSendTime = 0;

DWORD timeToSleep;

Form1->Button1->Enabled = FALSE;

//создание события для временного прерывания работы программы

hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);

// преобразование адреса

sAddress = Form1->Edit2->Text;

cAddress = sAddress.c_str();

lenAdr = sAddress.Length();

cAddress[lenAdr] = '\0';

//преобразование порта

sPort = Form1->Edit3->Text;

cPort = sPort.c_str();

lenPort = sPort.Length();

cPort[lenPort] = '\0';

iPort = atoi(cPort);

//преобразование номера УВМ

sNumUVM = Form1->ComboBox1->Text;

cNumUVM = sNumUVM.c_str();

cNumUVM[1] = '\0';

iUVM = atoi(cNumUVM);

//формирование постоянных значений структур

req.typeRequest = 0;

req.typeSender = iUVM;

req.lengthPack = sizeof(request);

if (iUVM == 2)

{

pack1.weight1 = 0xFFFF;

}

if (iUVM == 4)

{

pack2.weight1 = 0xFFFF;

}

if (iUVM <3)

{

period = 14;

pack1.typeRequest = 1;

pack1.typeSender = iUVM;

pack1.lengthPack = sizeof(pack1);

pPack = (char *)&pack1;

}

else

{

period = 5;

pack2.typeRequest = 1;

pack2.typeSender = iUVM;

pack2.lengthPack = sizeof(pack2);

pPack = (char *)&pack2;

}

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

{

return 0;

}

//создание сокета

sUvm = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (sUvm == INVALID_SOCKET)

{

return 0;

}

server.sin_family = AF_INET;

server.sin_port = htons(iPort);

server.sin_addr.s_addr = inet_addr(cAddress);

if (server.sin_addr.s_addr == INADDR_NONE)

{

// Если не указан IP-адрес

return 0;

}

//подсоединение к серверу

if (connect(sUvm, (struct sockaddr *)&server,

sizeof(server)) == SOCKET_ERROR)

bConnect = 1;

else

bConnect = 0;

bTimeSync = 1;

while (!bEndThread)

{

//подключение к серверу

if (bConnect)

{

shutdown(sUvm, SD_BOTH);

closesocket(sUvm);

sUvm = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (!(connect(sUvm, (struct sockaddr *)&server,

sizeof(server)) == SOCKET_ERROR))

{

bConnect = 0;

bTimeSync = 1;

}

}//if

//отправка запроса на синхронизацию времени

if ((!bConnect) && (bTimeSync))

{

nLeft = req.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sUvm, ((char *)&req) + idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

bConnect = 1;

break;

}

nLeft -= ret;

idx += ret;

}

}//if

//приём времени сервера и установка его в системе

if ((!bConnect) && (bTimeSync))

{

nLeft = 4;

idx = 0;

while(nLeft > 0)

{

ret = recv(sUvm, ((char *)&lastUpdateTime)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

bConnect = 1;

break;

}

nLeft -= ret;

idx += ret;

}

bTimeSync = 0;

// установка времени в системе

//stime(&lastUpdateTime);

}//if

//остановка работы до контрольной точки отсылки

if (!bConnect)

{

curTime = time(NULL);

if (lastSendTime == curTime)

timeToSleep = period * 1000;

else

timeToSleep = (period-(curTime % period))*1000;

WaitForSingleObject(hEvent, timeToSleep);

}

//считывание датчиков и текущего времени, отправка пакета

if (!bConnect)

{

if (iUVM < 3)

{

//считывание времени и установка параметров

curTime = time(NULL);

pack1.time = curTime;

nLeft = sizeof(pack1);

}

else

{

//считывание времени и установка параметров

curTime = time(NULL);

pack2.time = curTime;

nLeft = sizeof(pack2);

}

lastSendTime = time(NULL);

idx = 0;

while(nLeft > 0)

{

ret = send(sUvm, pPack+idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

bConnect = 1;

break;

}

nLeft -= ret;

idx += ret;

}

}//if

//проверка необходимости на повторную синхронизацию

if (!bConnect)

{

if ((time (NULL) - lastUpdateTime) > 600)

bTimeSync = 1;

}//if

}//while

WSACleanup();

CloseHandle(hEvent);

// Form1->Button1->Enabled = TRUE;

return 0;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

UINT iThreadId;

int i = 2;

Form1->Button1->Enabled = FALSE;

hThreadUVM = (HANDLE)_beginthreadex(NULL, 0, UVMThread, (LPVOID)i, 0,

&iThreadId);

if (hThreadUVM == NULL)

{

return;

}

return;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{

if (sUvm != NULL)

{

bEndThread = 1;

shutdown(sUvm, SD_BOTH);

closesocket(sUvm);

SetEvent (hEvent);

WaitForSingleObject(hThreadUVM, INFINITE);

CloseHandle (hThreadUVM);

}

}

//---------------------------------------------------------------------------


Додаток Б

Вихідний текст серверу

#include <vcl.h>

#pragma hdrstop

#include "Server.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

#include <winsock2.h>

#include <process.h>

#include <time.h>

#include <fcntl.h>

#include <stdio.h>

#include <conio.h>

#define MAX_CLIENT 10

#define timeToSleep 10000

typedef unsigned char uc;

typedef unsigned short int ui;

#pragma pack (push)

#pragma pack (1)

typedef struct

{

time_t time;

uc speed1;

uc speed2;

ui temperature1;

ui temperature2;

ui temperature3;

ui weight1;

ui weight2;

ui weight3;

uc length1;

uc length2;

} package1;

typedef struct

{

time_t time;

uc speed1;

uc speed2;

uc speed3;

ui temperature1;

ui temperature2;

ui weight1;

ui weight2;

ui weight3;

ui weight4;

uc length;

} package2;

typedef struct

{

uc typeRequest; //0 - запрос на синхронизацию

//1 - данные от УВМ

//2 - запрос от клиента

//3 - данные от сервера

uc typeSender; //1..4 номер УВМ

//5 клиент

//6 сервер

uc lengthPack;

} request;

typedef struct

{

ui iTypeUVM;

time_t tBegin;

time_t tEnd;

} requestRange;

typedef struct

{

uc typeRequest;

uc typeSender;

uc lengthPack;

unsigned long AmountPacks;

} packageServer;

typedef struct

{

HANDLE hClientThread;

SOCKET sClient;

time_t time;

uc typeSender;

}SOCKET_INFORMATION;

#pragma pack (pop)

//---------------------------------------------------------------------------

//прототипы функций

void DeleteSockInfo(int, uc);

//---------------------------------------------------------------------------

//глобальные переменные

TForm1 *Form1;

WSADATA wsd;

SOCKET sListen;

HANDLE hThreadAccept, hThreadControl;

HANDLE hEvent;

char bAlowCloseClient[MAX_CLIENT];

BOOL bServWorking = FALSE;

CRITICAL_SECTION csFile;

FILE *f1;

FILE *f2;

time_t lastTimeGroup1 = 0, lastTimeGroup2 = 0;

CRITICAL_SECTION cs;

int iNumClients = 0;

SOCKET_INFORMATION sockInfo[MAX_CLIENT];

//---------------------------------------------------------------------------

unsigned __stdcall ClientThread(LPVOID lpParam)

{

int nClient=(int)lpParam;

unsigned int idx, nLeft, ret, iFound;

request req;

requestRange reqRange;

packageServer packServ;

uc bError = 0, TypeSender;

time_t curTime;

package1 pack1;

package1 * pack1Array;

package2 pack2;

package2 * pack2Array;

long int curPos, endPos, startPos;

unsigned int i, nStructs;

while (!bError)

{

//приём запроса клиента

nLeft = sizeof(request);

idx = 0;

while(nLeft > 0)

{

ret = recv(sockInfo[nClient].sClient, ((char *) &req)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}

//установка типа клиента при получении первого запроса

if ((TypeSender == 0) && (!bError))

{

EnterCriticalSection (&cs);

sockInfo[nClient].typeSender = req.typeSender;

LeaveCriticalSection (&cs);

TypeSender = req.typeSender;

}

//запрос на синхронизацию?

if ((req.typeRequest == 0) && (!bError))

{

EnterCriticalSection (&cs);

sockInfo[nClient].time = time(NULL);

LeaveCriticalSection (&cs);

nLeft = 4;

idx = 0;

curTime = time(NULL);

while(nLeft > 0)

{

ret = send(sockInfo[nClient].sClient, ((char *) &curTime)+idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}

}//if синхронизация

//приём данных от УВМ

if ((req.typeRequest == 1) && (!bError))

{

EnterCriticalSection (&cs);

sockInfo[nClient].time = time(NULL);

LeaveCriticalSection (&cs);

if (TypeSender < 3)

nLeft = sizeof(package1);

else

nLeft = sizeof(package2);

idx = 0;

while(nLeft > 0)

{

if (TypeSender < 3)

ret = recv(sockInfo[nClient].sClient, ((char *)&pack1)+idx, nLeft, 0);

else

ret = recv(sockInfo[nClient].sClient, ((char *)&pack2)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}//while

//запись полученных данных в файл

if (!bError)

if (TypeSender < 3)

{

EnterCriticalSection (&csFile);

if (pack1.time >= lastTimeGroup1)

{

lastTimeGroup1 = pack1.time;

fwrite((void *)&pack1,sizeof(package1) ,1,f1);

fflush(f1);

}

LeaveCriticalSection (&csFile);

}

else //TypeSender > 3

{

EnterCriticalSection (&csFile);

if (pack2.time >= lastTimeGroup2)

{

lastTimeGroup2 = pack2.time;

fwrite((void *)&pack2,sizeof(package2) ,1,f2);

fflush(f2);

}

LeaveCriticalSection (&csFile);

}

}//if УВМ

//работа с рабочей станцией

if ((req.typeRequest == 2) && (!bError))

{

//сохранение времени последнего обращения

EnterCriticalSection (&cs);

sockInfo[nClient].time = time(NULL);

LeaveCriticalSection (&cs);

//приём диапазона и типа УВМ

nLeft = sizeof (requestRange);

idx = 0;

while(nLeft > 0)

{

ret = recv(sockInfo[nClient].sClient, ((char *)&reqRange)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}//while

//поиск кол-ва файлов удовлетворяющих диапазону времени

packServ.typeRequest = 3; //данные от сервера

packServ.typeSender = 6; //сервер

packServ.lengthPack = sizeof (packageServer);

packServ.AmountPacks = 0;

EnterCriticalSection (&csFile);

if (reqRange.iTypeUVM == 1)

{

curPos = ftell(f1);

fseek(f1, 0, SEEK_END);

endPos = ftell(f1);

fseek(f1, 0, SEEK_SET);

nStructs = endPos / (sizeof(package1));

iFound = 0;

for (i = 0; i<nStructs; i++)

{

fread((void *)&pack1, sizeof(package1), 1, f1);

if ((pack1.time >=reqRange.tBegin) && ( pack1.time <= reqRange.tEnd))

{

packServ.AmountPacks++;

if (iFound == 0)

{

iFound = 1;

startPos = ftell(f1) - sizeof(package1);

}

}

}//for

fseek(f1, curPos, SEEK_SET);

}

else

{

curPos = ftell(f2);

fseek(f2, 0, SEEK_END);

endPos = ftell(f2);

fseek(f2, 0, SEEK_SET);

nStructs = endPos / (sizeof(package2));

iFound = 0;

for (i = 0; i<nStructs; i++)

{

fread((void *)&pack2, sizeof(package2), 1, f2);

if ((pack2.time >=reqRange.tBegin) && ( pack2.time <= reqRange.tEnd))

{

packServ.AmountPacks++;

if (iFound == 0)

{

iFound = 1;

startPos = ftell(f2) - sizeof(package2);

}

}

}//for

fseek(f2, curPos, SEEK_SET);

}

LeaveCriticalSection (&csFile);

//отсылка количества найденных структур

nLeft = packServ.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sockInfo[nClient].sClient, ((char *) &packServ)+idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}

//считывание структур из файлов

if ((iFound != 0)&&(!bError))

{

EnterCriticalSection (&csFile);

if (reqRange.iTypeUVM == 1)

{

pack1Array = new package1[packServ.AmountPacks];

curPos = ftell(f1);

fseek(f1, startPos, SEEK_SET);

for (i = 0; i<packServ.AmountPacks; i++)

fread((void *)&pack1Array[i], sizeof(package1), 1, f1);

fseek(f1, curPos, SEEK_SET);

}

else

{

pack2Array = new package2[packServ.AmountPacks];

curPos = ftell(f2);

fseek(f2, startPos, SEEK_SET);

for (i = 0; i<packServ.AmountPacks; i++)

fread((void *)&pack2Array[i], sizeof(package2), 1, f2);

fseek(f2, curPos, SEEK_SET);

}

LeaveCriticalSection (&csFile);

//отсылка структур

for (i = 0; i<packServ.AmountPacks; i++)

{

if (reqRange.iTypeUVM == 1)

nLeft = sizeof(package1);

else

nLeft = sizeof(package2);

idx = 0;

while(nLeft > 0)

{

if (reqRange.iTypeUVM == 1)

ret = send(sockInfo[nClient].sClient, ((char *) &pack1Array[i])+idx, nLeft, 0);

else

ret = send(sockInfo[nClient].sClient, ((char *) &pack2Array[i])+idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

bError = 1;

break;

}

nLeft -= ret;

idx += ret;

}//while

if (bError == 1)

{

idx = 5;

break;

}

}//for

if (reqRange.iTypeUVM == 1)

delete[] pack1Array;

else

delete[] pack2Array;

}//if iFound

}//if PC

}//while (!bError)

//удаление записи о скруктуре текущего сокете

if (!bAlowCloseClient[nClient])

{

EnterCriticalSection (&cs);

DeleteSockInfo (nClient, 0);

LeaveCriticalSection (&cs);

}

return 0;

}//ClientThread

//---------------------------------------------------------------------------

unsigned __stdcall AcceptThread(LPVOID lpParam)

{

SOCKET sockAccept;

UINT iThreadId;

while (1)

{

sockAccept = accept(sListen, NULL, NULL);

if ((sockAccept == INVALID_SOCKET) && (WSAGetLastError() == WSAENOTSOCK))

break;

EnterCriticalSection (&cs);

if ((sockAccept != INVALID_SOCKET) && (iNumClients < MAX_CLIENT ))

{

sockInfo[iNumClients].sClient = sockAccept;

sockInfo[iNumClients].typeSender = 0;

sockInfo[iNumClients].time = time(NULL);

sockInfo[iNumClients].hClientThread =(HANDLE) _beginthreadex(NULL, 0,

ClientThread, (LPVOID)iNumClients, 0, &iThreadId);

sockInfo[iNumClients].time = time(NULL);

iNumClients ++ ;

LeaveCriticalSection (&cs);

}

else

{

LeaveCriticalSection (&cs);

shutdown(sockAccept, SD_BOTH);

closesocket(sockAccept);

}

}

return 0;

} // AcceptThread()

//---------------------------------------------------------------------------

unsigned __stdcall ControlThread(LPVOID lpParam)

{

int i;

DWORD dwWaitState;

while (1)

{

dwWaitState = WaitForSingleObject(hEvent, timeToSleep);

if (dwWaitState == WAIT_OBJECT_0)

break;

EnterCriticalSection (&cs);

for (i = 0; i< iNumClients; i++)

{

if ((sockInfo[i].typeSender == 5) || (sockInfo[i].typeSender == 0))

{

if ((time(NULL) - sockInfo[i].time)>600)

{

DeleteSockInfo(i , 1);

}

}

else

{

if ((time(NULL) - sockInfo[i].time)>60)

{

DeleteSockInfo(i , 1);

}

}

}//for

LeaveCriticalSection (&cs);

}//while

return 0;

} // ControlThread()

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

struct sockaddr_in server;

UINT iThreadId;

AnsiString sAddress, sPort;

char * cAddress, * cPort;

unsigned int lenAdr, lenPort, iPort;

Form1->Button1->Enabled = FALSE;

//создание или открытие файлов

hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);

if ((f1=fopen("group1.txt","a+b"))==NULL)

{

Form1->Button1->Enabled = TRUE;

return;

}

fseek (f1, 0, SEEK_END);

if ((f2=fopen("group2.txt","a+b"))==NULL)

{

fclose(f1);

Form1->Button1->Enabled = TRUE;

return;

}

fseek (f2, 0, SEEK_END);

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

{

fclose(f1);

fclose(f2);

Form1->Button1->Enabled = TRUE;

return;

}

//создание необходимых событий, секций

hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);

InitializeCriticalSection (&cs);

InitializeCriticalSection (&csFile);

//создание сокета

sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (sListen == INVALID_SOCKET)

{

CloseHandle (hEvent);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

Form1->Button1->Enabled = TRUE;

return;

}

// преобразование адреса

sAddress = Form1->Edit2->Text;

cAddress = sAddress.c_str();

lenAdr = sAddress.Length();

cAddress[lenAdr] = '\0';

//преобразование порта

sPort = Form1->Edit3->Text;

cPort = sPort.c_str();

lenPort = sPort.Length();

cPort[lenPort] = '\0';

iPort = atoi(cPort);

server.sin_family = AF_INET;

server.sin_port = htons(iPort);

server.sin_addr.s_addr = inet_addr(cAddress);

if (server.sin_addr.s_addr == INADDR_NONE)

{

CloseHandle (hEvent);

shutdown(sListen, SD_BOTH);

closesocket(sListen);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

Form1->Button1->Enabled = TRUE;

return;

}

if (bind(sListen, (SOCKADDR*) &server, sizeof(server)) == SOCKET_ERROR)

{

CloseHandle (hEvent);

shutdown(sListen, SD_BOTH);

closesocket(sListen);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

Form1->Button1->Enabled = TRUE;

return;

}

if (listen(sListen, 8) == SOCKET_ERROR)

{

CloseHandle (hEvent);

shutdown(sListen, SD_BOTH);

closesocket(sListen);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

Form1->Button1->Enabled = TRUE;

return;

}

//создание потока accept

hThreadAccept = (HANDLE)_beginthreadex(NULL, 0, AcceptThread, (LPVOID)sListen, 0,

&iThreadId);

if (hThreadAccept == NULL)

{

CloseHandle (hEvent);

shutdown(sListen, SD_BOTH);

closesocket(sListen);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

Form1->Button1->Enabled = TRUE;

return;

}

//создание потока отслеживания времени последнего обращени клиентов

hThreadControl = (HANDLE)_beginthreadex(NULL, 0, ControlThread, (LPVOID)sListen, 0,

&iThreadId);

if (hThreadControl == NULL)

{

return;

}

bServWorking = TRUE;

return;

}

//---------------------------------------------------------------------------

void DeleteSockInfo(int num, uc bWaitThread)

{

int i;

bAlowCloseClient[num] = 1;

shutdown(sockInfo[num].sClient, SD_BOTH);

closesocket(sockInfo[num].sClient);

if (bWaitThread)

WaitForSingleObject(sockInfo[num].hClientThread, INFINITE);

CloseHandle (sockInfo[num].hClientThread);

bAlowCloseClient[num] = 0;

for (i = num; i<(iNumClients-1); i++)

sockInfo[i] = sockInfo[i+1];

iNumClients--;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{

int i;

if (!bServWorking)

return;

// Закрытие потока Control и события ожидания

SetEvent (hEvent);

WaitForSingleObject(hThreadControl, INFINITE);

CloseHandle (hThreadControl);

CloseHandle (hEvent);

//закрытие сокета сервера и потока Accept

shutdown(sListen, SD_BOTH);

closesocket(sListen);

WaitForSingleObject(hThreadAccept, INFINITE);

CloseHandle (hThreadAccept);

//закрытие сокетов клиентов -> закрытие потоков

EnterCriticalSection (&cs);

for (i = 0; i<iNumClients; i++)

{

bAlowCloseClient[i] = 1;

shutdown(sockInfo[i].sClient, SD_BOTH);

closesocket(sockInfo[i].sClient);

WaitForSingleObject(sockInfo[i].hClientThread, INFINITE);

CloseHandle (sockInfo[i].hClientThread);

}

LeaveCriticalSection (&cs);

fclose(f1);

fclose(f2);

DeleteCriticalSection (&cs);

DeleteCriticalSection (&csFile);

WSACleanup();

}

Додаток В. Вихідний текст робочої станції

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Client.h"

#include <time.h>

#include <winsock2.h>

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

typedef unsigned char uc;

typedef unsigned short int ui;

#pragma pack (push)

#pragma pack (1)

typedef struct

{

time_t time;

uc speed1;

uc speed2;

ui temperature1;

ui temperature2;

ui temperature3;

ui weight1;

ui weight2;

ui weight3;

uc length1;

uc length2;

} package1;

typedef struct

{

time_t time;

uc speed1;

uc speed2;

uc speed3;

ui temperature1;

ui temperature2;

ui weight1;

ui weight2;

ui weight3;

ui weight4;

uc length;

} package2;

typedef struct

{

uc typeRequest; //0 - запрос на синхронизацию

//1 - данные от УВМ

//2 - запрос от клиента

//3 - данные от севера

uc typeSender; //1..4 номер УВМ

//5 клиент

//6 сервер

uc lengthPack;

} request;

typedef struct

{

uc typeRequest;

uc typeSender;

uc lengthPack;

ui iTypeUVM;

time_t tBegin;

time_t tEnd;

} requestRange;

typedef struct

{

uc typeRequest;

uc typeSender;

uc lengthPack;

unsigned long AmountPacks;

} packageServer;

#pragma pack (pop)

SOCKET sClient;

WSADATA wsd;

//---------------------------------------------------------------------------

void CloseClientSocket()

{

Form1->Button2->Enabled = FALSE;

Form1->Button3->Enabled = FALSE;

shutdown(sClient, SD_BOTH);

closesocket(sClient);

Form1->Button1->Enabled = TRUE;

}

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

StringGrid1->RowCount = 2;

StringGrid1->Rows[1]->Clear();

StringGrid1->Cells[0][0] = "№";

StringGrid1->Cells[1][0] = "Год";

StringGrid1->Cells[2][0] = "Месяц";

StringGrid1->Cells[3][0] = "День месяца";

StringGrid1->Cells[4][0] = "Часы";

StringGrid1->Cells[5][0] = "Минуты";

StringGrid1->Cells[6][0] = "Секунды";

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

struct sockaddr_in server;

AnsiString sAddress, sPort;

char * cAddress, * cPort;

unsigned int lenAdr, lenPort, iPort;

int nLeft, idx, ret;

request req;

time_t UpdateTime;

Form1->Button1->Enabled = FALSE;

// преобразование адреса

sAddress = Form1->Edit1->Text;

cAddress = sAddress.c_str();

lenAdr = sAddress.Length();

cAddress[lenAdr] = '\0';

//преобразование порта

sPort = Form1->Edit2->Text;

cPort = sPort.c_str();

lenPort = sPort.Length();

cPort[lenPort] = '\0';

iPort = atoi(cPort);

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

{

Application->MessageBoxA("Ошибка WSAStartup!", "Error!", MB_OK);

Form1->Button1->Enabled = TRUE;

return;

}

//создание сокета

sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (sClient == INVALID_SOCKET)

{

Application->MessageBoxA("Невозможно создать сокет", "Error!", MB_OK);

Form1->Button1->Enabled = TRUE;

return;

}

server.sin_family = AF_INET;

server.sin_port = htons(iPort);

server.sin_addr.s_addr = inet_addr(cAddress);

if (server.sin_addr.s_addr == INADDR_NONE)

{

// Если не указан IP-адрес

Application->MessageBoxA("Напрвальный IP адрес", "Error!", MB_OK);

Form1->Button1->Enabled = TRUE;

return;

}

if (connect(sClient, (struct sockaddr *)&server,

sizeof(server)) == SOCKET_ERROR)

{

Application->MessageBoxA("Неудалось подключится к серверу", "Error!", MB_OK);

Form1->Button1->Enabled = TRUE;

return;

}

req.typeRequest = 0; //запрос на синхронизацию

req.typeSender = 5; //идентификатор рабочей станции

req.lengthPack = sizeof(request);

//отправка запроса на синхронизацию времени

nLeft = req.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sClient, ((char *)&req) + idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

Application->MessageBoxA("Ошибка отправки запроса на синхронизацию", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

//приём времени сервера и установка его в системе

nLeft = sizeof(time_t);

idx = 0;

while(nLeft > 0)

{

ret = recv(sClient, ((char *)&UpdateTime)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма времени", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

// установка времени в системе

//stime(&UpdateTime);

Form1->Button2->Enabled = TRUE;

Form1->Button3->Enabled = TRUE;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

CloseClientSocket();

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)

{

int iTypeUVM, nLeft, idx, ret;

package1 pack1;

package2 pack2;

packageServer packServ;

requestRange reqRange;

tm tmBegin, tmEnd, *tmTime;

time_t time_tBegin, time_tEnd;

unsigned long i;

Form1->Button3->Enabled = FALSE;

StringGrid1->RowCount = 2;

StringGrid1->Rows[1]->Clear();

//формирование структур времени

tmBegin.tm_sec = Form1->ComboBox3->ItemIndex;

tmBegin.tm_min = Form1->ComboBox2->ItemIndex;

tmBegin.tm_hour = Form1->ComboBox6->ItemIndex;

tmBegin.tm_mday = Form1->ComboBox8->ItemIndex+1;

tmBegin.tm_mon = Form1->ComboBox10->ItemIndex;

tmBegin.tm_year = Form1->ComboBox12->ItemIndex+70;

tmBegin.tm_isdst = 0;

time_tBegin = mktime(&tmBegin);

if (time_tBegin == -1)

{

Application->MessageBoxA("Ошибка преобразования начального времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

tmEnd.tm_sec = Form1->ComboBox5->ItemIndex;

tmEnd.tm_min = Form1->ComboBox4->ItemIndex;

tmEnd.tm_hour = Form1->ComboBox7->ItemIndex;

tmEnd.tm_mday = Form1->ComboBox9->ItemIndex+1;

tmEnd.tm_mon = Form1->ComboBox11->ItemIndex;

tmEnd.tm_year = Form1->ComboBox13->ItemIndex+70;

tmEnd.tm_isdst = 0;

time_tEnd = mktime(&tmEnd);

if (time_tBegin == -1)

{

Application->MessageBoxA("Ошибка преобразования конечного времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

if (time_tEnd < time_tBegin)

{

Application->MessageBoxA("Конечное время меньше начального", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

iTypeUVM = Form1->ComboBox1->ItemIndex + 1;

//Формирование шапки таблицы

if (iTypeUVM == 1)

{

StringGrid1->Cells[7][0] = "Скорость 1";

StringGrid1->Cells[8][0] = "Скорость 2";

StringGrid1->Cells[9][0] = "Темпер. 1";

StringGrid1->Cells[10][0] = "Темпер. 2";

StringGrid1->Cells[11][0] = "Темпер. 3";

StringGrid1->Cells[12][0] = "Вес 1";

StringGrid1->Cells[13][0] = "Вес 2";

StringGrid1->Cells[14][0] = "Вес 3";

StringGrid1->Cells[15][0] = "Длина 1";

StringGrid1->Cells[16][0] = "Длина 2";

}

else

{

StringGrid1->Cells[7][0] = "Скорость 1";

StringGrid1->Cells[8][0] = "Скорость 2";

StringGrid1->Cells[9][0] = "Скорость 3";

StringGrid1->Cells[10][0] = "Темпер. 1";

StringGrid1->Cells[11][0] = "Темпер. 2";

StringGrid1->Cells[12][0] = "Вес 1";

StringGrid1->Cells[13][0] = "Вес 2";

StringGrid1->Cells[14][0] = "Вес 3";

StringGrid1->Cells[15][0] = "Вес 4";

StringGrid1->Cells[16][0] = "Длина";

}

//формирование и отсылка запроса на диапазон времён

reqRange.typeRequest = 2;

reqRange.typeSender = 5;

reqRange.lengthPack = sizeof (requestRange);

reqRange.iTypeUVM = iTypeUVM;

reqRange.tBegin = time_tBegin;

reqRange.tEnd = time_tEnd;

nLeft = reqRange.lengthPack;

idx = 0;

while(nLeft > 0)

{

ret = send(sClient, ((char *)&reqRange) + idx, nLeft, 0);

if (ret == SOCKET_ERROR)

{

Application->MessageBoxA("Ошибка отправки запроса на приём данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

//приём от сервера кол-ва записей входяих в диапазон

nLeft = sizeof(packageServer);

idx = 0;

while(nLeft > 0)

{

ret = recv(sClient, ((char *)&packServ)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма количества данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}

if (packServ.AmountPacks == 0)

{

Application->MessageBoxA("Нет данных в заданном диапазоне времени", "Error!", MB_OK);

Form1->Button3->Enabled = TRUE;

return;

}

//приём в цикле записей

StringGrid1->RowCount = packServ.AmountPacks+1;

for (i = 0; i<packServ.AmountPacks; i++)

{

if (iTypeUVM == 1)

nLeft = sizeof(package1);

else

nLeft = sizeof(package2);

idx = 0;

while(nLeft > 0)

{

if (iTypeUVM == 1)

ret = recv(sClient, ((char *)&pack1)+idx, nLeft, 0);

else

ret = recv(sClient, ((char *)&pack2)+idx, nLeft, 0);

if ((ret == SOCKET_ERROR)||(ret == 0))

{

Application->MessageBoxA("Ошибка приёма структуры данных", "Error!", MB_OK);

CloseClientSocket();

return;

}

nLeft -= ret;

idx += ret;

}//while

//отображение полученной записи

StringGrid1->Cells[0][i+1] = i+1;

if (iTypeUVM == 1)

tmTime = localtime(&pack1.time);

else

tmTime = localtime(&pack2.time);

StringGrid1->Cells[1][i+1] = (*tmTime).tm_year+1900;

StringGrid1->Cells[2][i+1] = (*tmTime).tm_mon;

StringGrid1->Cells[3][i+1] = (*tmTime).tm_mday+1;

StringGrid1->Cells[4][i+1] = (*tmTime).tm_hour;

StringGrid1->Cells[5][i+1] = (*tmTime).tm_min;

StringGrid1->Cells[6][i+1] = (*tmTime).tm_sec;

if (iTypeUVM == 1)

{

StringGrid1->Cells[7][i+1] = pack1.speed1;

StringGrid1->Cells[8][i+1] = pack1.speed2;

StringGrid1->Cells[9][i+1] = pack1.temperature1;

StringGrid1->Cells[10][i+1] = pack1.temperature2;

StringGrid1->Cells[11][i+1] = pack1.temperature3;

StringGrid1->Cells[12][i+1] = pack1.weight1;

StringGrid1->Cells[13][i+1] = pack1.weight2;

StringGrid1->Cells[14][i+1] = pack1.weight3;

StringGrid1->Cells[15][i+1] = pack1.length2;

StringGrid1->Cells[16][i+1] = pack1.length2;

}

else

{

StringGrid1->Cells[7][i+1] = pack2.speed1;

StringGrid1->Cells[8][i+1] = pack2.speed2;

StringGrid1->Cells[9][i+1] = pack2.speed3;

StringGrid1->Cells[10][i+1] = pack2.temperature1;

StringGrid1->Cells[11][i+1] = pack2.temperature2;

StringGrid1->Cells[12][i+1] = pack2.weight1;

StringGrid1->Cells[13][i+1] = pack2.weight2;

StringGrid1->Cells[14][i+1] = pack2.weight3;

StringGrid1->Cells[15][i+1] = pack2.weight4;

StringGrid1->Cells[16][i+1] = pack2.length;

}

}//for

Form1->Button3->Enabled = TRUE;

}

//---------------------------------------------------------------------------


Информация о работе «Розробка програмного забезпечення системи збору даних про хід та параметри технологічного процесу»
Раздел: Информатика, программирование
Количество знаков с пробелами: 52962
Количество таблиц: 2
Количество изображений: 9

Похожие работы

Скачать
56956
0
11

... є інтереси відповідного бізнесу. Прецеденти є, але про суспільну користь говорити можна не завжди. Переглянувши державні бюджети України чи бюджети окремих міст, можна знайти факти підтримки суспільно корисних громадських організацій. Велика частина з них стала предметом розслідування КРУ, податкової міліції, чи депутатських комісій. Якщо влада таким чином не хоче ощасливити когось із своїх родич ...

Скачать
117936
0
10

... технологи НДІ постійно працюють з технологами КБ (більш детально питання розробки будуть розглянуті нижче). Технологи КБ повинні знати основи економіки даного виробництва і ціноутворення вироби для того, щоб розроблювальний технологічний процес дозволяв випускати продукцію більш низькою собівартістю, ніж аналоги. Розроблена технологічна документація з КБ надходить до служби головного технолога, ...

Скачать
165990
30
46

... ії; - існуючий підрозділ імпортування італійських меблів буде забезпечувати поставку меблів із Італії за напрацьованою схемою; РОЗДІЛ 3. РОЗРОБКА ТА АНАЛІЗ ЕФЕКТИВНОСТІ МАРКЕТИНГОВОЇ СТРАТЕГІЇ КОНЦЕНТРАЦІЇ ТОВ „КЛАСС-ЛАЙН” В СЕГМЕНТІ ПОСЛУГ „ДІЗАЙН ІНТЕР’ЄРІВ»   3.1 Стратегічні цілі проектного комплексу концентрованого маркетингу ТОВ „Класс-Лайн”   У світовій практиці відомо чотири види ...

Скачать
143644
51
28

... моментів, якому потрібно знати при створенні нової інформаційної систем - те, що цей процес є одним видом запланованої організаційної зміни. 2. Перепроектування бізнесів-процесів Нові інформаційні системи можуть бути могутніми інструментами для організаційних змін. Вони не тільки допомагають раціоналізувати організаційні процедури і документообіг, але вони можуть фактично використовуватися для ...

0 комментариев


Наверх