воскресенье, 1 января 2012 г.

Введение в Windows Sockets API: Клиентские сокеты C++

Клиентские сокеты используют приложения, которым необходимо передавать и принимать данные с другим приложением. Примером такого приложения является браузер: по определенному ip-адресу он передает серверу сформированный HTTP-заголовок, в качестве ответа сервер передает данные, которые затребовал в HTTP-заголовке клиент (web-страницу, изображение и т.п.).
В этой статье я расскажу о средствах WSA, необходимых для реализации передачи данных между процессами через клиентские сокеты.

Инициализация WSA

WSADATA wsaData;
int result;
result = WSAStartup( MAKEWORD(2, 2), &wsaData);
if(result != 0)
{
 std::cout << "Ошибка WSAStartup: " << result << std::endl;
 return 1;
}

Перед началом работы с сокетами Windows необходимо инициализировать Windows sockets API (WSA)
Для этого надо вызывать функцию WSAStartup и передать в аргументах версию WSA и указатель на структуру WSAData. Функция возвращает 0, если инициализация прошла успешно, в противном случае возвращает код ошибки.

Создание сокета

SOCKET clientSocket = INVALID_SOCKET;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if( clientSocket == INVALID_SOCKET)
{
 std::cout << "Ошибка socket(): " << WSAGetLastError() << std::endl;
 WSACleanup();
 return 1;
}

Функция socket возвращает дескриптор сокета. Если при создании сокета произошла ошибка, она возвращает 0 (INVALID_SOCKET).

Присоединение к серверу

#define ip "127.0.0.1"
#define port 80

sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(ip);
clientService.sin_port = htons(port);

int result;
result = connect(
   clientSocket, 
   reinterpret_cast< SOCKADDR* >(&clientService), 
   sizeof(clientService)
  );
if(result != 0)
{
 std::cout << "Ошибка в connect(): " << WSAGetLastError() << std::endl;
 WSACleanup();
 return 1;
}

После того как сокет создан, можно начинать подключаться через него к серверам.
Для соединения нужен сам сокет, ip-адрес и порт процесса (сервера). Эти данные передаются функции connect, которая возвращает 0 в случае успешного соединения.
Ip-адрес и порт следует передать структуре sockaddr.

Передача данных серверу

int result;
char data[] = "Test";
result = send(clientSocket, data, static_cast< int >(strlen(data)), 0);
if( result < 0 )
{
 std::cout << "Ошибка в send(): " << WSAGetLastError() << std::endl;
 return 1;
}

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

Прием данных от сервера

#define bufsize 256

char buf[bufsize];
int r;
do
{
 r = recv(clientSocket, buf, bufsize, 0);
 if(r > 0)
  std::cout << "Приянтно " << r << " байт" << std::endl;
 else if(r == 0)
  std::cout << "Соединение разорвано" << std::endl;
 else
  std::cout << "Ошибка в recv(): " << WSAGetLastError() << std::endl;
} while(r > 0);

Что бы принять данные надо вызывать функцию recv и передать ей в качестве аргументов указатель на буфер данных и на размер этого буфера.
Из кода видно, что за один раз можно принять не более bufsize байт информации.

Разрыв соединения

closesocket(clientSocket);
// Если работа с сокетами больше не предполагается вызываем WSACleanup()
WSACleanup();

Заключение

Дополнительную информацию о функциях, структурах WSA можно найти в MSDN: Winsock reference.

Введение в WSA

Комментариев нет:

Отправить комментарий