Разработка браузера на Borland Delphi 7

Автор работы: Пользователь скрыл имя, 21 Мая 2013 в 02:01, курсовая работа

Описание работы

Актуальность. Данная программа предназначена для быстрого поиска, какой либо информации. Именно через нее мы получаем основной поток информации и проводим в ней большую часть времени. Данную программу не надо устанавливать, программа открывается за доли секунды. Так же лёгкий интерфейс.
Объект: Инструментальные средства и технологии разработки Windows-приложений
Предмет: Программирование в Borland Delphi 7
Цель: Разработка приложения для быстрого поиска, какой либо информации.

Содержание работы

ВВЕДЕНИЕ ..7
Глава 1 Разработка Web-browser на основе EI в среде Delphi…..8
1.1 Назначение работы и область ее применения.....................................10
1.2 Технологии и средства разработка программы 13
1.3 Описание языка программирования Delphi. 15
Вывод по главе 1 17

Глава 2 Этапы разработки программы 18
2.1 Обоснование выбора языка программирования 18
2.2 Алгоритм программы 19
2.3 Структурные и функциональные характеристики
программы. 20
2.4 Пользовательский интерфейс 21
2.5 Описание кода, тестирование и верификация
программы. 23
Вывод по главе 2 23

ЗАКЛЮЧЕНИЕ 23
ЛИТЕРАТУРА 25
ПРИЛОЖЕНИЕ 26

Файлы: 1 файл

kursovaya_rabota_ISIT.doc

— 308.00 Кб (Скачать файл)

Сервер: прежде, чем сервер сможет использовать сокет, он должен связать его с локальным адресом. Локальный, как, впрочем, и любой  другой адрес Интернета, состоит  из IP-адреса узла и номера порта. Если сервер имеет несколько IP адресов, то сокет может быть связан как со вмести ними сразу (для этого вместо IP-адреса следует указать константу INADDR_ANY равную нулю), так и с каким-то конкретным одним.

Связывание осуществляется вызовом функции "int bind (SOCKET s, const struct sockaddr FAR* name, int namelen)". Первым слева аргументом передается дескриптор сокета, возращенный функций socket, за ним следуют указатель на структуру sockaddr и ее длина (см. раздел "Адрес раз, адрес два").

Строго говоря, клиент также должен связывать сокет  с локальным адресом перед  его использованием, однако, за него это делает функция connect, ассоциируя сокет с одним из портов, наугад выбранных из диапазона 1024-5000. Сервер же должен "садиться" на заранее определенный порт, например, 21 для FTP, 23 для telnet, 25 для SMTP, 80 для WEB, 110 для POP3 и т.д. Поэтому ему приходится осуществлять связывание "вручную".

При успешном выполнении функция возвращает нулевое  значение и ненулевое в противном  случае.

Сервер, выполнив связывание, потоковый сервер переходит в режим ожидания подключений, вызывая функцию "int listen (SOCKET s, int backlog )", где s – дескриптор сокета, а backlog – максимально допустимый размер очереди сообщений.

Датаграммные  серверы не вызывают функцию listen, т.к. работают без установки соединения и сразу же после выполнения связывания могут вызывать recvfrom для чтения входящих сообщений, минуя четвертый и пятый шаги.

Извлечение  запросов на соединение из очереди  осуществляется функцией "SOCKET accept (SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen)", которая автоматически создает новый сокет, выполняет связывание и возвращает его дескриптор, а в структуру sockaddr заносит сведения о подключившемся клиенте (IP-адрес и порт). Если в момент вызова accept очередь пуста, функция не возвращает управление до тех пор, пока с сервером не будет установлено хотя бы одно соединение. В случае возникновения ошибки функция возвращает отрицательное значение.

Функция send возвращает управление сразу же после ее выполнения независимо от того, получила ли принимающая сторона наши данные или нет. При успешном завершении функция возвращает количество передаваемых (не переданных!) данных - т. е. успешное завершение еще не свидетельствует от успешной доставке! В общем-то, протокол TCP (на который опираются потоковые сокеты) гарантирует успешную доставку данных получателю, но лишь при условии, что соединение не будет преждевременно разорвано. Если связь прервется до окончания пересылки, данные останутся не переданными, но вызывающий код не получит об этом никакого уведомления! А ошибка возвращается лишь в том случае, если соединение разорвано до вызова функции send!

Функция же recv возвращает управление только после  того, как получит хотя бы один байт. Точнее говоря, она ожидает прихода целой дейтаграммы. Дейтаграмма - это совокупность одного или нескольких IP пакетов, посланных вызовом send. Упрощенно говоря, каждый вызов recv за один раз получает столько байтов, сколько их было послано функцией send. При этом подразумевается, что функции recv предоставлен буфер достаточных размеров, - в противном случае ее придется вызвать несколько раз. Однако, при всех последующих обращениях данные будет браться из локального буфера, а не приниматься из сети, т.к. TCP-провайдер не может получить "кусочек" дейтаграммы, а только ею всю целиком.

Перед выходом  из программы, необходимо вызвать функцию "int WSACleanup (void)" для деинициализации  библиотеки WINSOCK и освобождения используемых этим приложением ресурсов.

Примечание: более сложные приемы закрытия соединения - протокол TCP позволяет выборочно закрывать соединение любой из сторон, оставляя другую сторону активной. Например, клиент может сообщить серверу, что не будет больше передавать ему никаких данных и закрывает соединение "клиент ( сервер", однако, готов продолжать принимать от него данные, до тех пор, пока сервер будет их посылать, т.е. хочет оставить соединение "клиент ( сервер" открытым.

Для этого  необходимо вызвать функцию "int shutdown (SOCKET s ,int how )", передав в аргументе how одно из следующих значений: SD_RECEIVE для закрытия канала "сервер ( клиент", SD_SEND для закрытия канала "клиент ( сервер", и, наконец, SD_BOTH для закрытия обоих каналов.

 

2.4 Пользовательский интерфейс 

 

Для пользователей  создан простейший интерфейс программы, который запускается на компьютере пользователя. Серверная часть приложения имеет вид при запуске (Рис.3) командной строки. В которой необходимо ввести только значение порта.

При запуске  клиентской части как показано на рисунке 4 необходимо ввести значении IP-адреса сервера, и порта который предназначен для соединения. На рисунке 5 показано как отправляются сообщения в многопользовательском чате для локальной сети.

Рис.3 Вид запущенного  серверной части многопользовательского чата для локальной сети.

 

Рис.4 Запуск клиентской части приложения многопользовательского чата для локальной сети.

 

Рис.5 проверка отправки сообщений..

 

2.5 Описание кода, тестирование и  верификация программы.

 

Пул поток - этот подход предполагает, что вы указываете число потоков, которые могут существовать в любой момент, и вполне приемлем, если соединения будут недолговечными. Однако соединения с серверами (например, с сервером-чатом) обычно остаются открытыми длительное время, поэтому ограничивать число соединений числом потоков в пуле зачастую неприемлемо.

Лучше использовать статический метод Socket.Select. Вы можете передать ему три списка сокетов, за которыми хотите следить: первый позволяет  определить возможность чтения, второй — возможность записи, а третий — обнаруживать ошибки. Когда метод Select возвращает управление, оставшиеся в конкретном списке элементы готовы к выполнению соответствующей списку операции. Кроме того, метод Select принимает параметр microSeconds, сообщающий методу, сколько времени ждать ответа. Один из способов на основе метода Select предполагает, что вы создаете таймер, срабатывающий через небольшие интервалы, а в обработчике событий таймера вызываете Select с нулевым значением microSeconds, чтобы вызов был неблокирующим. Однако это неэффективно. Время, необходимое для обслуживания сокетов, зависит от частоты срабатывания таймера, что приводит к неоправданному снижению быстродействия кода. Как правило, лучше создать поток, который вызывает Select и обслуживает запросы, но больше ничего не делает.

Слушающий сокет  следует перед вызовом Select поместить  в список проверки возможности чтения. Если после вызова Select данный сокет  все еще присутствует в этом списке, значит, у нас есть соединение, которое  следует принять (такое использование Select для определения наличия запроса гарантирует, что метод Accept не заблокируется). Теперь вы можете вызвать метод Accept и начать работу с новым сокетом. Для обслуживания входящих данных новые сокеты, создаваемые при вызове Accept, нужно помещать в тот список, где находится сокет, для которого вы вызвали метод Accept (это довольно удобно). То есть в нашем сервере нужно поддерживать только один список.

Законченные реализации.

Для их компиляции с помощью Microsoft Visual C++ достаточно отдать команду: "cl.exe имя_файла.cpp ws2_32.lib".

Проверка работоспособности TCP-сервера: запустите TCP-сервер и наберите в командной строке Windows "telnet.exe 127.0.0.1 ***", где 127.0.0.1 обозначает локальный  адрес вашего узла (это специально зарезервированный для этой цели адрес и он выглядит одинаково для всех узлов), а 666 - номер порта на который "сел" сервер. Если все работает успешно, то telnet установит соединение и на экране появится приветствие "Hello, Sailor!". Теперь можно набирать на клавиатуре некоторый текст и получать его назад от сервера.

Проверка работоспособности TCP-клиента: запустите TCP-сервер и затем  одну или несколько копий клиента. В каждом из них можно набирать некоторый текст на клавиатуре и  после нажатия на Enter получать его  обратно от сервера.

 

Вывод по главе 2

 

В этой главе  мы определили алгоритм программы, структурные  и функциональные характеристики. Также  описали инструментарий для разработки  кода программы и ее проектирование.

В должной  мере определенны функции механизма  пул потоков, для использования их в качестве инструмента в разработке программы. Так же описаны подключаемые  библиотеки Microsoft Visual Studio .NET. И описан пошаговый метод разработки многопользовательского чата для локальной сети

 

Заключение

Предметом разработки данной курсовой работы являлось  создание ПО, необходимого для обеспечения общения пользователей в локальной сети. В данной курсовой работе описаны все необходимые компоненты для создания такой системы ПО.

В заключении хочется вкратце перечислить  список технологий, использованных при реализации данного проекта, дополненный списком научной документации:

- Программирование  приложений с использованием .NET Framework

- Создание  собственного протокола передачи  данных с использованием пул  потоков.

- Использование  многопоточности

- ООП

Конечно, у  данной программы есть недостатки: короткие сообщения, проблема с кодировками, невозможность посмотреть историю  сообщений при подключении. Но тем  временем основная задача по реализации клиент-серверного приложения достигнута в полной мере. Задействованы основные возможности языка программирования С++.

 

Литература

    1. Стивен П. “Язык программирования C++. Лекции и упражнения. 6-е издание” 2012
    2. Пахомов Б. “Самоучитель C/C++ и C++ Builder 2007” 2008
    3. Страуструп Б. “Язык программирования C++” 2011
    4. Макс Ш. “Профессиональное программирование на C++” 2010
    5. Касперский К. “Секреты поваров компьютерной кухни или ПК: решение проблем” 2003
    6. Www.cyberforum.ru
    7. Www.programmersforum.ru
    8. Www.habrahabr.ru
    9. Www.vingrad.ru
    10. Www.wikipedia.org
    11. Www.virusinfo.info
    12. Www.rsdn.ru
    13. Www.vsokovikov.narod.ru
    14. Www.stackoverflow.com

 

 

Приложение

1. Листинг  программы сервера для многопользовательского чата для локальной сети

#include <winsock2.h>

#include <windows.h>

#include <list>

#include <cstdlib>

#pragma comment(lib, "ws2_32.lib")

//#pragma warning(disable:4996)

#define BUFSIZE   512

class xClient;

std::list<xClient*>  clients;

CRITICAL_SECTION  section;

// клиентский  сокет, использующий механизм  пула

class xClient {

private:

SOCKET         client;

HANDLE         thread;

DWORD          tid;

volatile BOOL  loop;

public:

xClient(void) {

tid    = 0u;

client = 0u;

thread = NULL;

loop   = FALSE;

}

~xClient() {

this->Close();

}

public:

BOOL   Create(SOCKET  sock) {

thread = CreateThread(NULL, 0u, (LPTHREAD_START_ROUTINE)xClient::ThreadReader, (LPVOID)this, CREATE_SUSPENDED, &tid);  

if(thread == NULL) {

this->Close();

return FALSE;

}

client = sock;

loop   = TRUE;

ResumeThread(thread);

return TRUE;

}

BOOL  Send(const CHAR* buf, int size) {

int result = send(client, buf, size, 0);

if(result > 0)

return TRUE;

this->Detach();

return FALSE;

}

void Close(void) {

loop = FALSE;

if(client != 0u) {

shutdown(client, SD_RECEIVE);

closesocket(client);

}

if(thread != NULL) {

if(WaitForSingleObject(thread, 1000u) != WAIT_OBJECT_0)

TerminateThread(thread, 0u); 

CloseHandle(thread);

}

thread = NULL;

client = 0u;

tid    = 0u;

}

// при отключение  потока подвесить поток и задать ему самый низкий приоритет

void  Detach(void) {

EnterCriticalSection(&section);

if(client != 0u) {

shutdown(client, SD_RECEIVE);

closesocket(client);

}

client = 0u;

SetThreadPriority(thread, THREAD_PRIORITY_IDLE);

LeaveCriticalSection(&section);

SuspendThread(thread);

}

// пробудить поток

void Attach(SOCKET  sock) {

        client = sock;

SetThreadPriority(thread, THREAD_PRIORITY_NORMAL);

ResumeThread(thread);

}

BOOL IsConnected(void) const {

return (client != 0u);

}

DWORD  GetID(void) const {

return tid;

}

private:

static DWORD WINAPI  ThreadReader(LPVOID param) {

xClient* obj = reinterpret_cast<xClient*>(param);

int  result;

CHAR buf[BUFSIZE + 1];

while(obj->loop) {

if(! obj->IsConnected()) {

Sleep(0u);

continue;

}

result = recv(obj->client, buf, BUFSIZE, 0);

if(result > 0) {

EnterCriticalSection(&section);

for(std::list<xClient*>::iterator iter = clients.begin(); iter != clients.end(); ++iter) {

if(! (*iter)->IsConnected())

continue;

if((*iter)->GetID() != GetCurrentThreadId())

(*iter)->Send(buf, result);

}

LeaveCriticalSection(&section);

} else if(result == 0 || result == SOCKET_ERROR)

obj->Detach();

}

return 0u;

}

};

// Реализация  серверного - объекта TCP

class xTCPServer {

private:

SOCKET  server;

HANDLE  fiber;

public:

xTCPServer(void) {

server = 0u;

fiber  = NULL;

}

xTCPServer() {

this->Close();

}

public:

// Функция  по созданию серверного сокета, в параметре принимает номер  порта используйте выше чем  > 1024  IANA <= 1024

// параметер  count_lisen - задаёт кол-во одновременных  соедененний, обычно указывают  пять, зависит от ресурсов сервера

BOOL   Create(USHORT port, int count_lisen = 5) {

sockaddr_in  addr;

addr.sin_family       = AF_INET;

addr.sin_port         = htons(port);

addr.sin_addr.s_addr  = htonl(INADDR_ANY);

server = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

if(server == SOCKET_ERROR )

return FALSE;

int result = bind(server, (const sockaddr*)&addr, sizeof(addr));

if(result == SOCKET_ERROR)

return FALSE;

int size    = sizeof(int);

int bufsize = 0;

// проверяем размер приёмного-буфера tcp

if(getsockopt(server, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, &size) != SOCKET_ERROR) {

if(bufsize < BUFSIZE) {  // если меньше указанного  пытаемся свой задать размер

bufsize = BUFSIZE;

setsockopt(server, SOL_SOCKET, SO_RCVBUF, (const char*)&bufsize, sizeof(int));

}

}

// также проверяем посылаемого-буфера tcp

if(getsockopt(server, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, &size) != SOCKET_ERROR) {if(bufsize < BUFSIZE) {

bufsize = BUFSIZE;

setsockopt(server, SOL_SOCKET, SO_SNDBUF, (const char*)&bufsize, sizeof(int));

}

}

listen(server, count_lisen);

ZeroMemory(&section, sizeof(CRITICAL_SECTION));

InitializeCriticalSection(&section);

fiber  = CreateThread(NULL, 0U, xTCPServer::ThreadAccept, (LPVOID)this, 0u, NULL);

if(fiber == NULL )  {

closesocket(server);

server = NULL;

return FALSE;

}

return TRUE;

}

void  Close(void) {

DeleteCriticalSection(&section);

if(fiber != NULL ) {

TerminateThread(fiber, 0u);

Информация о работе Разработка браузера на Borland Delphi 7