#pragma comment (lib, "Ws2_32.lib")
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <iostream>
#include <string>
#include <tchar.h>
#include <winsock2.h>
using namespace std;
Важным моментом является подключение библиотеки Ws2_32.lib (WinSock). Найдите две строки кода, которые делают это. Замените весь код серверного приложения (файла WinSockServer.cpp) на тот, что приведен ниже. В нем реализуется алгоритм вызова API-функций, соответствующий серверной части диаграммы.
#include "stdafx.h"
void main()
{
WSADATA data;
int res = WSAStartup (MAKEWORD(2,2), &data); // Initialize WSA (Winsock Applications)
if (res != NO_ERROR)
cout << "Error at WSAStartup()";
SOCKET sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
cout << "\nError at socket(): " << WSAGetLastError();
WSACleanup();
return;
}
string myAddr = "127.0.0.1"; // Потом вставьте реальный адрес
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr (myAddr.c_str());
addr.sin_port = htons (0x6987); // 27015
if (bind (sock, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
cout << "\nbind() failed";
closesocket (sock);
return;
}
if (listen (sock, 1) == SOCKET_ERROR)
cout << "\nError listening on socket";
cout << "\nMy address: " << myAddr << "\nWaiting for a client to connect...";
SOCKET acceptSocket = SOCKET_ERROR;
while (acceptSocket == SOCKET_ERROR)
acceptSocket = accept (sock, 0, 0);
cout << "\nClient Connected\n";
sock = acceptSocket;
char* buf = new char[32];
while (true)
{
int nBytes = recv (sock, buf, 32, 0);
if (nBytes < 0 || strcmp (buf, "Bye") == 0)
break;
cout << "\nReceived: " << buf << " (" << nBytes << " bytes)";;
strcpy (buf, "Yes, Client!");
nBytes = send (sock, buf, (int)strlen(buf) + 1, 0);
cout << "\nSent: " << buf << " (" << nBytes << " bytes)\n";
}
cout << "\n\n";
}
Вызов функции WSAStartup рассматривайте, как инициализацию библиотеки ws2_32.dll, то есть загрузку ее в адресное пространство процесса серверного приложения. Далее в функции main создается разъем (socket), заполняется определяющая его тип структура sockaddr_in, производится связывание (bind) разъема с этой структурой, точнее, с парой (локальный адрес, порт), и разъем переводится в режим прослушивания сети. Разъем ждет, когда какой-либо клиент откроет с ним соединение. Цикл ожидания этого события имеет такой вид.
SOCKET acceptSocket = SOCKET_ERROR;
while (acceptSocket == SOCKET_ERROR)
acceptSocket = accept (sock, 0, 0);
После открытия соединения разъем переходит в режим циклического обмена данными с клиентским приложением. Цикл обмена (вызов функций recv, send) завершается, когда от клиента придет сообщение с текстом: "Bye". Такое решение принято произвольно. Вы можете изменить алгоритм и завершать сессию, по прибытии любого другого сигнала. Например, сервер может решить сложную задачу, по ее окончании переслать ответ (массив данных) клиенту, и завершить цикл обмена, когда клиент подтвердит получение массива. Перейдите в клиентское приложение (файл WinSockClient.cpp) и полностью замените его код.
#include "stdafx.h"
void main()
{
WSADATA data;
int res = WSAStartup (MAKEWORD(2,2), &data); // Initialize WSA (Winsock Applications)
if (res != NO_ERROR)
cout << "Error at WSAStartup()";
SOCKET sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
cout << "\nError at socket(): " << WSAGetLastError();
WSACleanup();
return;
}
string myAddr = "127.0.0.1"; // Потом вставьте реальный адрес
sockaddr_in addr;
addr.sin_family = AF_INET;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.