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

Связываем socket

После того, как socket создан, нам надо связать его с адресом. Связь socket’а с адресом происходит с помощью функции bind. Подробно о функции bind прочитайте в первой части статьи. Для функции bind, нам необходимо заполнить структуру sockaddr_in. Делается это с помощью функции SetServerSockAddr

void SetServerSockAddr(sockaddr_in *pSockAddr, int portNumber)

{

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

pSockAddr->sin_family = AF_INET;

pSockAddr->sin_port = htons(portNumber);

pSockAddr->sin_addr.S_un.S_addr = INADDR_ANY;

}

Эта функция вызывается в функции RunServer:

// Связывае socket

cout << "Binding socket... ";

SetServerSockAddr(&sockAddr, portNumber);

if (bind(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr))!=0)

throw ROTException("could not bind socket.");

cout << "bound.\n";

«Пусть socket слушает»

Если socket успешно связан, его надо установить в режим прослушивания. Как только этот режим будет установлен, у сервера смогут запрашивать соединения. Установка режима прослушивание осуществляется с помощью функции listen

// Устанавливаем socket в режим прослушивания

cout << "Putting socket in listening mode... ";

if (listen(hSocket, SOMAXCONN)!=0)

throw ROTException("could not put socket in listening mode.");

cout << "done.\n";

В функцию передаются два параметра: первый – socket, которые будет «слушать», второй – длина очереди ждущих соединений. Обычно для второго параметра отлично подходит значение SOMAXCONN (подробнее о нем можете прочесть в первой части статьи).

Принимаем соединение

Что бы принимать входящие соединения, надо использовать функцию accept. Эта функция заблокирует Вашу программу, до тех пор, пока соединение не установится и функция не вернет дескриптор socket’а, по которому установлено соединение. Важно понимать, что socket сервера – всего лишь средство для установления соединения с клиентами. После того, как Вы создадите соединение, будет создан новый socket. Именно поэтому socket’у Вы и будете обмениваться данными с клиентом. Причем это надо иметь в виду, т.к. многие пытаются передать данные по прослушивающему socket’у.

Кроме разрешения соединения с клиентом и возвращения дескриптора socket’а, по которому будет происходить соединение, функция accept так же заполняет структуру sockaddr_in информацией о клиенте. В нашем примере эта информация будет использоваться для вывода IP адреса и номера порта клиента.

sockaddr_in clientSockAddr;

int clientSockSize = sizeof(clientSockAddr);

 

// Принимаем соединение:

hClientSocket = accept(hSocket,

reinterpret_cast<sockaddr*>(&clientSockAddr),

&clientSockSize);

 

// Проверяем успешно ли принято соединение

if (hClientSocket==INVALID_SOCKET)

throw ROTException("accept function failed.");

cout << "accepted.\n";

 

// Обрабатываем соединение:

HandleConnection(hClientSocket, clientSockAddr);

Я думаю этот код почти понятен. Полностью понятным он станет после того, как я расскажу про функцию HandleConnection.

HandleConnection

Функция HandleConnection обрабатывает соединение. Передаваемые параметры понятны из их названия. Сначала функция показывает краткую информацию о клиенте.

void HandleConnection(SOCKET hClientSocket, const sockaddr_in &sockAddr)

{

// Выводим информацию о подключенном клиенте

cout << "Connected with " << GetHostDescription(sockAddr) << ".\n";

А функция GetHostDescription как раз и формирует эту информацию

string GetHostDescription(const sockaddr_in &sockAddr)

{

ostringstream stream;

stream << inet_ntoa(sockAddr.sin_addr) << ":" << ntohs(sockAddr.sin_port);

return stream.str();

}

Теперь опишем функцию, которая осуществляет rot13. Эта функция циклически вызывается при завершении функции recv, до тех пор, пока recv не вернет 0. Каждый раз, когда приходят данные, функция преобразует их и возвращает клиенту.

void rot13(char *pBuffer, int size)

{

for(int i=0;i<size;i++)

{

char c = pBuffer<span style="font-style:italic">;

if ((c >= 'a' && c < 'n') || (c >= 'A' && c < 'N') )

c += 13;

else if ((c>='n' && c <= 'z') || (c>='N' && c <= 'Z'))

c -= 13;

else

continue;

pBuffer[i] = c;

}

}

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

// Считывем данные

while(true)

{

int retval;

retval = recv(hClientSocket, tempBuffer, sizeof(tempBuffer), 0);

if (retval==0)

{

break; // Соединение было закрыто

}

else if (retval==SOCKET_ERROR)

{

throw ROTException("socket error while receiving.");

}

else

{

//rot13 кодирует данные и отправляет их обратоно

rot13(tempBuffer, retval);

if (send(hClientSocket, tempBuffer, retval, 0)==SOCKET_ERROR)

throw ROTException("socket error while sending.");

}

}

cout << "Connection closed.\n";