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