ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.06.2019
Просмотров: 106
Скачиваний: 1
Лабораторная работа №3
Программирование сокетов. Протокол TCP
Студента ИТ 14-1 Красовского Абхая
Цель работы: изучить возможности для создания сетевых приложений.
Ход работы:
Сервер:
#pragma comment(lib, "Ws2_32.lib")
#include <stdio.h>
#include <iostream>
#include <winsock2.h> /* Wincosk2.h должен быть раньше windows.h! */
#include <windows.h> /* Иначе будет переопределение функций -> много ошибок */
#define MY_PORT 777 /* Порт, который слушает сервер */
/* макрос для печати количества активных пользователей */
#define PRINTNUSERS if (nclients) cout << nclients << " user on_line" << endl; else cout << "No User on line" << endl;
/* прототип функции, обслуживающий подключившихся пользователей */
DWORD WINAPI ToClient(LPVOID client_socket);
int nclients = 0; /* глобальная переменная – количество активных пользователей */
using namespace std;
void freeWsaAndSocket(SOCKET socket)
{
closesocket(socket);
WSACleanup(); /* Деинициализация библиотеки Winsock */
}
void main()
{
system("color 1a");
setlocale(LC_ALL, "rus");
char buff[1024];
cout << "TCP-Server" << endl;
/* Шаг 1 - Инициализация библиотеки сокетов */
if (WSAStartup(0x0202, (WSADATA *)&buff[0]))
/* Ошибка */
cout << "Error WSAStartup: " << WSAGetLastError();
/* Шаг 2 - создание сокета */
SOCKET mysocket;
/* AF_INET _ сокет Интернета
SOCK_STREAM - потоковый сокет (с установкой соединения)
0 - по умолчанию выбирается TCP-протокол */
if ((mysocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
freeWsaAndSocket(mysocket); /* Ошибка */
/* Шаг 3 - связывание сокета с локальным адресом */
sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(MY_PORT);
local_addr.sin_addr.s_addr = 0; /* сервер принимает подключения на все свои IP-адреса
вызываем bind для связывания */
if (bind(mysocket, (sockaddr *)&local_addr, sizeof(local_addr)))
{
cout << "Error bind: " << WSAGetLastError() << endl;
freeWsaAndSocket(mysocket);
}
/* Шаг 4 - ожидание подключений, размер очереди – 0x100 */
if (listen(mysocket, 0x100))
{
printf("Error listen %d\n", WSAGetLastError());
freeWsaAndSocket(mysocket);
}
cout << "Ожидание подключений…" << endl;
/* Шаг 5 - извлекаем сообщение из очереди */
SOCKET client_socket; /* сокет для клиента */
sockaddr_in client_addr; /* адрес клиента (заполняется системой)
функции accept необходимо передать размер структуры */
int client_addr_size = sizeof(client_addr);
/* цикл извлечения запросов на подключение из очереди */
while ((client_socket = accept(mysocket, (sockaddr *)&client_addr, &client_addr_size)))
{
nclients++; /* увеличиваем счетчик подключившихся клиентов */
/* пытаемся получить имя хоста */
HOSTENT *hst;
hst = gethostbyaddr((char *)&client_addr.sin_addr.s_addr, 4, AF_INET);
/* вывод сведений о клиенте */
printf("+%s [%s] new connect!\n", (hst) ? hst->h_name : "", inet_ntoa(client_addr.sin_addr));
PRINTNUSERS
/* Вызов нового потока для обслуживания клиента */
DWORD thID;
CreateThread(NULL, NULL, ToClient, &client_socket, NULL, &thID);
}
}
/* Эта функция создается в отдельном потоке и обсуживает
очередного подключившегося клиента независимо от остальных. */
DWORD WINAPI ToClient(LPVOID client_socket)
{
SOCKET my_sock;
my_sock = ((SOCKET *)client_socket)[0];
char buff[1024];
#define sHELLO "Hello, Student\r\n"
/* отправляем клиенту приветствие */
send(my_sock, sHELLO, sizeof(sHELLO), 0);
/* цикл эхо-сервера: прием строки от клиента и возвращение ее клиенту */
int bytes_recv;
while ((bytes_recv = recv(my_sock, &buff[0], sizeof(buff), 0)) && bytes_recv != SOCKET_ERROR) send(my_sock, &buff[0], bytes_recv, 0);
/* если мы здесь, то произошел выход из цикла по причине
возращения функцией recv ошибки – соединение с клиентом разорвано */
nclients--; /* уменьшаем счетчик активных клиентов */
cout << "-disconnect" << endl;
PRINTNUSERS
/* закрываем сокет */
closesocket(my_sock);
return 0;
}
Клиент:
#pragma comment(lib, "Ws2_32.lib")
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#define PORT 777
#define SERVERADDR "127.0.0.1"
using namespace std;
void freeWsaAndSocket(SOCKET socket)
{
closesocket(socket);
WSACleanup();
}
void main()
{
setlocale(LC_ALL, "rus");
system("color 1A");
char buff[1024];
cout << "TCP-Client" << endl;
/* Шаг 1 - инициализация библиотеки Winsock */
if (WSAStartup(0x202, (WSADATA *)&buff[0]))
cout << "WSAStart error: " << WSAGetLastError() << endl
/* Шаг 2 - создание сокета */
SOCKET my_sock;
my_sock = socket(AF_INET, SOCK_STREAM, 0);
if (my_sock<0)
cout << "Socket() error: " << WSAGetLastError() << endl
/* Шаг 3 - установка соединения
заполнение структуры sockaddr_in – указание адреса и порта сервера */
sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
HOSTENT *hst;
/* преобразование IP адреса из символьного в сетевой формат */
if (inet_addr(SERVERADDR) != INADDR_NONE)
dest_addr.sin_addr.s_addr = inet_addr(SERVERADDR);
else
/* попытка получить IP адрес по доменному имени сервера */
if (hst = gethostbyname(SERVERADDR))
/* hst->h_addr_list содержит не массив адресов, а массив указателей на адреса */
((unsigned long *)&dest_addr.sin_addr)[0] = ((unsigned long **)hst->h_addr_list)[0][0];
else
{
cout << "Invalid address: " << SERVERADDR << endl;
freeWsaAndSocket(my_sock);
}
/* адрес сервера получен – пытаемся установить соединение */
if (connect(my_sock, (sockaddr *)&dest_addr, sizeof(dest_addr)))
cout << "Connect error: " << WSAGetLastError() << endl
cout << "Соединение с " << SERVERADDR << " успешно установлено\n Type quit for quit\n" << endl;
/* Шаг 4 - чтение и передача сообщений */
int nsize;
while ((nsize = recv(my_sock, &buff[0], sizeof(buff) - 1, 0)) != SOCKET_ERROR)
{
/* ставим завершающий ноль в конце строки */
buff[nsize] = 0;
/* выводим на экран */
cout << "Server => Client: " << buff << endl;
/* читаем пользовательский ввод с клавиатуры */
cout << "Server <= Client: " << endl;
fgets(&buff[0], sizeof(buff) - 1, stdin);
/* проверка на "quit" */
if (!strcmp(&buff[0], "quit\n"))
{
/* корректный выход */
cout << "Exit..." << endl;
freeWsaAndSocket(my_sock);
}
/* передаем строку клиента серверу */
send(my_sock, &buff[0], nsize, 0);
}
cout << "Recv error: " << WSAGetLastError() << endl;
freeWsaAndSocket(my_sock);
}
Запускаем сервер, клиент и получаем следующий результат:
Закроем клиент:
Отследим передаваемую информацию:
На передачу данных мы потратили 0.000865 секунд.