Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Глобальные сети компьютеров. Практическое введение в Internet, E-Mail, FTP, WWW и HTML, программирование для Windows Sockets

© Александр Фролов, Григорий Фролов
Том 23, М.: Диалог-МИФИ, 1993, 283 стр.

[Назад] [Содеожание] [Дальше]

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

После того как канал создан, можно начинать передачу данных. Для передачи данных при помощи протокола гарантированной доставки 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 .

Приведем список кодов ошибок, которые могут возникать при вызове команды send:

Код ошибки Описание
WSANOTINITIALISED Перед использованием функции необходимо вызвать функцию WSAStartup
WSAENETDOWN Сбой в сети
WSAEACCES Указанный адрес является широковещательным (broadcast), однако перед вызовом функции не был установлен соответствующий флаг
WSAEINTR Работа функции была отменена при помощи функции WSACancelBlockingCall
WSAEINPROGRESS Выполняется блокирующая функция интерфейса Windows Sockets
WSAEFAULT Параметр buf указан неправильно (он не указывает на адресное пространство, принадлежащее приложению)
WSAENETRESET Необходимо сбросить соединение
WSAENOBUFS Возникла блокировка буфера
WSAENOTCONN Сокет не подсоединен
WSAENOTSOCK Указанный в параметре дескриптор не является сокетом
WSAESHUTDOWN Сокет был закрыт функцией shutdown
WSAEWOULDBLOCK Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке
WSAEMSGSIZE Был использован сокет типа SOCK_DGRAM (предназначенный для передачи датаграмм). При этом размер пакета данных превышает максимально допустимый для данной реализации интерфейса Windows Sockets
WSAEINVAL Сокет не был подключен функцией bind
WSAECONNABORTED Сбой из-за слишком большой задержки или по другой причине
WSAECONNRESET Сброс соединения удаленным узлом

При выполнении функции recv могут возникать следующие ошибки:

Код ошибки Описание
WSANOTINITIALISED Перед использованием функции необходимо вызвать функцию WSAStartup
WSAENETDOWN Сбой в сети
WSAENOTCONN Сокет не подсоединен
WSAEINTR Работа функции была отменена при помощи функции WSACancelBlockingCall
WSAEINPROGRESS Выполняется блокирующая функция интерфейса Windows Sockets
WSAENOTSOCK Указанный в параметре дескриптор не является сокетом
WSAESHUTDOWN Сокет был закрыт функцией shutdown
WSAEWOULDBLOCK Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке
WSAEMSGSIZE Размер пакета данных превышает размер буфера, в результате чего принятый пакет был обрезан
WSAEINVAL Сокет не был подключен функцией bind
WSAECONNABORTED Сбой из-за слишком большой задержки или по другой причине
WSAECONNRESET Сброс соединения удаленным узлом

Передача и прием данных в цикле может привести к блокировке работы приложения. Если это неприемлимо, следует воспользоваться асинхронным расширением интерфейса 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. Следующие ошибки могут возникнуть при любом значении параметра:

Код ошибки Описание
WSANOTINITIALISED Перед использованием функции необходимо вызвать функцию WSAStartup
WSAENETDOWN Сбой в сети
WSAEINVAL Сокет не был подключен функцией bind
WSAEINPROGRESS Выполняется блокирующая функция интерфейса Windows Sockets

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

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

Код ошибки Описание
WSAEADDRINUSE Указанный адрес уже используется
WSAEADDRNOTAVAIL Указанный адрес не доступен
WSAEAFNOSUPPORT Для данного сокета нельзя использовать указанное семейство адресов
WSAECONNREFUSED Попытка установления канала связи была отвергнута
WSAEDESTADDRREQ Необходимо указать адрес получателя пакета
WSAEFAULT Неправильно указан параметр namelen
WSAEINVAL Сокет уже подключен к адресу
WSAEISCONN Сокет уже подсоединен
WSAEMFILE Больше нет доступных дескрипторов
WSAENETUNREACH Из данного узла и в данное время невозможно получить доступ к сети
WSAENOBUFS Нет места для размещения буфера
WSAENOTCONN Сокет на подключен
WSAENOTSOCK Указан дескриптор файла, а не сокета
WSAETIMEDOUT При попытке установления канала связи возникла задержка во времени

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

Код ошибки Описание
WSAENETDOWN Сбой в сети
WSAECONNRESET Сброс соединения удаленным узлом
WSAECONNABORTED Сбой из-за слишком большой задержки или по другой причине

В том случае, когда указаны параметры 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 - код события, которое произошло в сети.

[Назад] [Содеожание] [Дальше]