Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лаба14.doc
Скачиваний:
9
Добавлен:
12.11.2019
Размер:
572.93 Кб
Скачать

3.5.1. Сторона клиента

Рассмотрим процедуру установки канала связи со стороны клиента, использованную нами в приложении CLIENT, исходные тексты которого будут приведены ниже.

Для установки соединения в приложении используется функция SetConnection:

SOCKADDR _IN dest_sin;

void SetConnection(HWND hWnd)

{

PHOSTENT phe;

// Создаем сокет

srv_socket = socket(AF_INET , SOCK_STREAM, 0);

if(srv_socket == INVALID_SOCKET)

{

MessageBox(NULL, "socket Error", "Error", MB_OK);

return;

}

// Устанавливаем адрес IP и номер порта

dest_sin.sin_family = AF_INET ;

// Определяем адрес узла

phe = gethostbyname ("localhost ");

if(phe == NULL)

{

closesocket (srv_socket);

MessageBox(NULL, "gethostbyname Error", "Error", MB_OK);

return;

}

// Копируем адрес узла

memcpy((char FAR *)&(dest_sin.sin_addr ), phe->h_addr ,

phe->h_length);

// Копируем номер порта

dest_sin.sin_port = htons(SERV_PORT);

// Устанавливаем соединение

if(connect(srv_socket , (PSOCKADDR )&dest_sin,

sizeof(dest_sin)) < 0)

{

closesocket (srv_socket);

MessageBox(NULL, "connect Error", "Error", MB_OK);

return;

}

}

Вначале с помощью функции socket эта функция создает сокет. Затем выполняется заполнение адресной информацией структуры dest_sin.

Обратите внимание, что для получения адреса IP мы воспользовались функцией gethostbyname , указав ей имя узла localhost .

Это имя отображается в файле HOSTS на адрес 127.0.0.1:

  1. localhost

Адрес 127.0.0.1 является локальным. Вы можете использовать его для тестирования приложений, выполняющих обмен данными при помощи протокола TCP/IP, запуская сервер и клиент на одном и том же компьютере.

После заполнения структуры с адресной информацией функция connect создает канал связи с сервером.

3.5.3. Передача и прием данных

После того как канал создан, можно начинать передачу данных. Для передачи данных при помощи протокола гарантированной доставки TCP вы можете воспользоваться функциями send и recv , которые входят в программный интерфейс Windows Sockets.

Функция передачи данных send имеет три параметра - дескриптор сокета sock, на котором выполняется передача, адрес буфера buf, содержащего передаваемое сообщение, размер этого буфера bufsize и флаги flags:

int send (SOCKET sock, const char FAR* buf, int bufsize, int flags);

В нашем приложении CLIENT мы передаем данные серверу следующим образом:

char szBuf[80];

lstrcpy(szBuf, "Test string");

send (srv_socket , szBuf, lstrlen(szBuf), 0);

Параметры функции recv, предназначенной для приема данных, аналогичны параметрам функции send :

int recv (SOCKET sock, char FAR * buf, int bufsize, int flags);

Заметим, что функции recv и send возвращают количество, соответственно, принятых и переданных байт данных. Приложение, которое принимает данные, должно вызывать функцию recv в цикле до тех пор, пока не будут приняты все переданные данные. При этом на один вызов функции send может приходиться несколько вызовов функции recv.

В случае ошибки обе эти функции возвращают значение SOCKET_ERROR . Для анализа причин возникновения ошибки следует воспользоваться функцией WSAGetLastError .

Cписок кодов ошибок, которые могут возникать при вызове команды send см. Таблица 6. в приложениях.

При выполнении функции recv могут возникать ошибки см. таблицу 9 в приложениях.

Передача и прием данных в цикле может привести к блокировке работы приложения. Если это неприемлемо, следует воспользоваться асинхронным расширением интерфейса Windows Sockets. Первое приложение SERVER демонстрирует асинхронный прием данных.

После установки канала связи оно вызывает функцию WSAAsyncSelect , указывая ей в качестве последнего параметра комбинацию констант FD_READ и FD_CLOSE . При этом функция главного окна приложения будет получать сообщение WSA_NETEVENT в тот момент времени, когда чтение данных не вызовет блокировки приложения:

#define WSA_NETEVENT (WM_USER + 2)

rc = WSAAsyncSelect (srv_socket , hWnd, WSA_NETEVENT,

FD_READ | FD_CLOSE );

При необходимости выполнения асинхронной посылки данных вы можете указать функции WSAAsyncSelect еще и параметр FD_WRITE .

Если функция WSAAsyncSelect выполнилась успешно, она возвращает нулевое значение, при ошибке - значение SOCKET_ERROR.

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

Дополнительный код ошибки можно получить из параметра lParam при помощи макрокоманды WSAGETSELECTERROR.

При использовании параметра FD_CONNECT возможно появление следующих ошибок см. Таблицу 11 в приложениях:

Если используется параметр FD_CLOSE, может возникнуть одна из следующих ошибок см. Таблицу 12 в приложениях.

В том случае, когда указаны параметры FD_READ , FD_WRITE , FD_OOB , или FD_ACCEPT , может возникнуть ошибка с кодом WSAENETDOWN .

Обработчик сообщения WSA_NETEVENT должен выполнить анализ причины, по которой он был вызван, так как за один вызов функции WSAAsyncSelect можно задать несколько событий, вызывающих генерацию сообщения. Этот анализ проводится, например, следующим образом:

void WndProc_OnWSANetEvent(HWND hWnd, UINT msg,

WPARAM wParam, LPARAM lParam)

{

char szTemp[256];

int rc;

// Если на сокете выполняется передача данных,

// принимаем и отображаем эти данные в виде

// текстовой строки

if(WSAGETSELECTEVENT(lParam) == FD_READ )

{

rc = recv ((SOCKET)wParam, szTemp, 256, 0);

if(rc)

{

szTemp[rc] = '\0';

MessageBox(NULL, szTemp, "Reсeived data", MB_OK);

}

return;

}

// Если соединение завершено, выводми об этом сообщение

else if(WSAGETSELECTEVENT(lParam) == FD_CLOSE )

{

MessageBox(NULL, "Connection closed", "Server", MB_OK);

}

}

Отметим, что параметр wParam содержит дескриптор сокета, на котором выполняется передача данных, а параметр lParam - код события, которое произошло в сети.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]