Сетевое программирование в .NET, страница 15

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;

addr.sin_addr.s_addr = inet_addr (myAddr.c_str());

addr.sin_port = htons (27015);

if (connect (sock, (SOCKADDR*) &addr, sizeof(addr)) == SOCKET_ERROR)

{

  cout << "\nFailed to connect";

  WSACleanup();

  return;

}

else

  cout << "\nConnected to : " << addr.sin_addr.s_addr << endl;

char* buf = strcpy (new char[32], "Hallo, Server!");

int nBytes = send (sock, buf, (int)strlen(buf) + 1, 0);

cout << "\nSent: " << buf << "  (" << nBytes << " bytes)";

while (true)

{

  nBytes = recv (sock, buf, 32, 0);

  if (nBytes <= 0 || nBytes == WSAECONNRESET)

  {

    cout << "\nConnection Closed\n";

    break;

  }

  cout << "\nReceived: " << buf << "  (" << nBytes << " bytes)\n: ";

  cin.getline (buf, 31);