После того как канал создан, можно начинать передачу данных. Для передачи данных при помощи протокола гарантированной доставки 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 - код события, которое произошло в сети.
Приложение SERVER
В этом разделе мы представим вам исходные тексты приложения SERVER, которое выполняет прием сообщений от приложения CLIENT с использованием протокола гарантированной доставки TCP и канала связи. При необходимости вы сможете самостоятельно организовать передачу данных в обратном направлении.
Вы можете запускать приложения SERVER и CLIENT как на одном, так и на разных компьютерах, соединенных локальной или глобальной сетью TCP/IP. В случае запуска этих приложений на одном и том же компьютере в качестве адреса IP используется локальный тестовый адрес 127.0.0.1.
Создавая проект для этого, а также всех остальных приложений, приведенных в нашей книге, вы должны указать, что для разрешения внешних ссылок необходимо использовать библиотеки объектных модулей wsock32.lib и comctl32.lib. Первая из них нужна для работы с программным интерфейсом Windows Sockets, вторая - для работы с органом управления Statusbar.
Для подключения указанных библиотек из меню Build системы разработки Microsoft Visual C++ версии 4.0 нужно выбрать строку Settings. На экране появится блокнот project Settings, который следует открыть на странице Link. Затем вы должны дописать названия библиотек в поле Object/library modules и нажать кнопку OK.
Исходный текст приложения SERVER представлен в листинге 5.1.