• 7908
  • 0
  • 1
Нравится блог?
Подписывайтесь!

Клиент-сервер на WinSock

Привет всем юным кодерам. Сегодня я расскажу о написании клиент серверного приложения на winapi библиотеке Winsock.
Как известно клиент-серверное приложение состоит из клиента и сервера. Клиент у нас будет программой визуальной, т.е. это центр управление, с которого мы будет посылать команды не визуальному серверу, который будет из анализировать и выполнять.
Что касается компилятора то я буду использовать Borland c++. (Я уже вижу, как в меня летят тухлые помидоры =)).
Начнем с простого – клиент.
Как ты помнишь это программа визуальная. На главной форме должны присутствовать такие компоненты:
Текстовое поле для ввода IP адреса(Edit).
Кнопки для подключение и отключения сервера(Button).
Кнопки для управлением сервера (Button). (На ваш вкус)
Еще можно добавить одно многострочное поле для информирования пользователя о состоянии соединения(Memo).

http://stranger.nextmail.ru/ex.html

Да, и не забудь подключить библиотеку:

#include

Первое что бы сделаем это подключение к серверу.

{
WSADATA wsd;
If (WSAStartup(MAKEWORD(1,1), &wsd) != 0) // загрузка библиотеки и проверка на //ошибки
{
// если ошибки есть, то проинформировать юзера
Form1->Memo1->Lines->Add("Error load WinSock");
return ;
}
// создание нового потока 
HANDLE hThread;
DWORD idThread;
hThread = CreateThread(NULL, 0, Thread, 0, 0, & idThread);
}

Что тут происходит? Да пока ничего. Мы просто загрузили библиотеке функцией 
WSAStartUp и создали новый поток, в нем мы уже будет создавать сокет и соединяться с сервером. В первом аргументе функции WSAStartUp мы указали MAKEWORD(1,1) т.е. версия библиотеки 1. Второй аргумент это указатель на структуру WSADATA. В ней будет храниться информация о библиотеки.
Итак, поток создан, теперь можно работать с ним.
Сначала нужно объявить глобально следующие переменные
SOCKET sClient;
int ret, i;
struct sockaddr_in server;
struct hostent *host = NULL;
bool status;

По ходу дела мы разберемся, что к чему.
А вот и сам поток, что бы программа правильно проинициализировала его, поток нужно добавить до того кода, что я привел выше.

DWORD WINAPI Thread(LPVOID lpParam) 
{

char* szServerName= new char;
szServerName="12345";
szServerName=strcpy(szServerName,(Form1->Edit1->Text.c_str()));

//создание сокета
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
MessageBox(0, "Can't create socket", "Error", 0);
return 1;
}
//заполненеие структуры sockaddr_in
server.sin_family = AF_INET;
server.sin_port = htons(7070);
server.sin_addr.s_addr = inet_addr(szServerName);

//само соеденение

if (connect(sClient, (struct sockaddr *)&server,
sizeof(server)) == SOCKET_ERROR)
{

Form1->Memo1->Lines->Add("connect failed");
return 1;
}
char szRecvBuff[1024];
//принимаем данные
ret = recv(sClient, szRecvBuff, strlen(szRecvBuff), 0);
if (ret == SOCKET_ERROR)
{

Form1->Memo1->Lines->Add("recv failed");
}
// выводим данные
String q=szRecvBuff;
Form1->Memo1->Lines->Add(q);
status=true;

}
Перед основным кодом мы заносим в переменную szServerName значение текстового поля, в который пользователь введет ip адрес.
Сначала создаем сокет функцией socket.
Первый аргумент это семейство протоколов.
Нам нужен TCP, так что указываем AF_INET.
Второй аргумент этот спецификация для сокета, т.е. что мы с ним будем делать.
Нам нужно установить соединение и передать данные, поэтому указываем SOCK_STREAM.
Третий аргумент собственно сам протокол. IPPROTO_TCP соответствуют протоколу TCP.
Теперь нам нужно заполнить структуру типа sockaddr_in. В ней храниться информация о созданном сокете. Напомню что переменую (server) данного типа (sockaddr_in) мы объявили глобально. В процессе заполнения структуры нам встречается функция htons.
Она осуществляет перевод целого короткого числа из порядка байт, принятого на компьютере, в сетевой порядок байт.
Ну и само соединение. Функция connect. Первый параметр это созданный сокет.
Второй – указатель на структуру типа sockaddr_in третий размер этой структуры.
Если все пройдет успешно, то можно принять данные функцией recv и вывести в текстовое поле. Первый аргумент функции recv это созданный сокет, второй – буфер который мы предварительно создали, третий аргумент это размер буфера (функция strlen возвращает размер строки). И, наконец, последний аргумент это флаги, определяющие метод получения. Они нам не нужны, поэтому указываем 0.
В конце кода мы приводим логическую переменную status в значение true. Это нужно чтобы впоследствии избежать ненужного повторного подключения.
Кстати, так как мы работаем с классно string в начале файла нужно добавить 

#include .
Мы научились соеденяться с сервером, теперь нужно добавить функцию отправки команд.
Для этого мы напишам функцию GetComand, ее единственным аргументом будет команда которую нужно отправить.
/
void GetCommand(char* str){ /
//если мы подлючены то…
if(status==true)
{
char* szMessage= new char;
szMessage="0000";
// копируем в буферв вписаную нами команду
strcpy(szMessage, str);
// отправка команды
ret = send(sClient, szMessage, strlen(szMessage), 0);
if (ret == SOCKET_ERROR)
{
} Form1->Memo1->Lines->Add("send failed");

//получение ответа
char szRecvBuff[1024];
ret = recv(sClient, szRecvBuff, 1024, 0);
if (ret == SOCKET_ERROR)
{

Form1->Memo1->Lines->Add("recv failed");
}
String q=szRecvBuff;
//вывод ответа
Form1->Memo1->Lines->Add(q);
}
else
{
//если мы не подключены то осведомить пользователя
Form1->Memo1->Lines->Add("The server is not connected");

}
}

Сначала происходит проверка переменной status. Если она равна true то мы подключены и можно выполнять дальнейший код.
А далее мы копируем в буфер szMessage значение переменной str. 
И потом отправляем это значение серверу функцией send;
Первый ее аргумент это сокет второй это буфер третий размер буфера.
После этого мы получаем ответ функцией recv он аналогична send.
После этого выводим ответ в текстовое поле.
Ответы мы будем формировать сами при разработке сервера.
Замечу, что в коде есть проверка на ошибки.
Функция готова к использованию.
Например при нажатии на кнопку «Перезагрузка» нужно выполнить такой код:

{
GetCommand("RB");
}

Кстати смотри не запутайся в командаъ т.к. в сервера из нужно будет анализировать.
Вот мои:
«Поменять кнопки мыши» -«AMB»
«Блокировать стол» - «BT»
«Сообщение» - «MSG»
Итак, простейший клиент готов. Подведем итог.
Клиент может подключаться к серверу отправлять и принимать команды. Пока это все.

Теперь можно приступить к разработке сервера.
Как я уже говорил сервер это программа не визуальная.
В нем, как и в клиенте нужно загрузить бибилиотеку создать сокет и подключиться.
Так же мы встретимся с привязкой к локльному адресу (функция bind) и прослушиванию порта (функция listen). 
Опять же глобально нужно объявить следущие переменные:

SOCKET sServerListen, sClient;
struct sockaddr_in localaddr,
clientaddr;
HANDLE hThread;
DWORD dwThreadId;
int iSize;
WSADATA wsaData;

Итак начнем вот код главной функции:

{
//загрузка библиотеки
WSAStartup(MAKEWORD(1, 1), &wsaData);
Создание сокета
sServerListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
заполнение струтуры адреса
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(7070);
//привязка адреса к сокету
bind(sServerListen, (struct sockaddr *)&localaddr,sizeof(localaddr));
//простушиваниче порта 
listen(sServerListen, 2);
while (1)
{
iSize = sizeof(clientaddr);
//разрешение на соеденение
sClient = accept(sServerListen, (struct sockaddr *)&clientaddr,&iSize);
//создание потока для приема и отправки данных
hThread = CreateThread(NULL, 0, ClientThread,(LPVOID)sClient, 0, &dwThreadId);
CloseHandle(hThread);
}
closesocket(sServerListen);
return 0;
}

До заполнения структуры адреса все идет так же. После этого вызываеться функция bind.
Она служит для связи сокета с адресом.
Т.е. первым аргументом мы передали сокет, вторым указатель на структуру с адресом, третим – размер структуры.
Теперь сокет готов к работе и можно прослушивать порт на соеденение со стороны клиента.
Функция listen. У нее два параметра. Сокет и кол-во клиентов которые могут подключиться к серверу. Т.к. сервер должен постоянно находиться в памяти и принимать соеденения, то мы запускаем бесконечный цикл.
Функция accert проверяет подключающийся клиент и разрешает соеденения.
Первый параметр это сокет. Второйуказатель на структуру типа sockaddr ну и третий размер структуры. sClient будет указателем на новый сокет.
После этого создаем новый поток для обмена данными.
Вот этот поток:

DWORD WINAPI ClientThread(LPVOID lpParam)
{

SOCKET sock=(SOCKET)lpParam;

string a="";
char szRecvBuff[1024],szSendBuff[1024] ;
int ret;
strcpy(szSendBuff,"Server connect!");
send(sock, szSendBuff, sizeof(szSendBuff), 0);

while(1)
{
//Получаем данные
ret = recv(sock, szRecvBuff, 1024, 0);

if (ret == 0)
break;
else if (ret == SOCKET_ERROR)
{
MessageBox(0, "Recive data filed", "Error", 0);
break;
}
szRecvBuff[ret] = 'слеш0';
//записываем в стринговую переменную для дальнейшей обработки
a=szRecvBuff;
//Проверка команд 
//если команда перезагрузки то…
if(a=="RB")
{
ExitWindowsEx(EWX_REBOOT, 0);
strcpy(szSendBuff,"Computer reboot =) ");
send(sock, szSendBuff, sizeof(szSendBuff), 0);

}
else
//если команда поменять кнопки мышки то…
if(a=="AMB")
{

SwapMouseButton(false);

strcpy(szSendBuff,"The buttons on the mouse were displaced");
send(sock, szSendBuff, sizeof(szSendBuff), 0);
}
Else
//если команда для вывода сообщения то…
if(a=="MSG")
{
MessageBox(0, " It is time to you to be hung up", "Error", 0);
strcpy(szSendBuff," The message is sent");
send(sock, szSendBuff, sizeof(szSendBuff), 0);

}
Else
//если команда для блокирования стола
if(a=="BT")
{
HWND h=GetDesktopWindow(); 
EnableWindow(h, FALSE);
strcpy(szSendBuff,"The working table is blocked");
send(sock, szSendBuff, sizeof(szSendBuff), 0);

}

}
Сначала мы передаем клиенту сообщение о том, что сервер успешно подключен и готов к работе. Далее мы получаем команды и записываем полученную команду в стринговую переменную (не забудь добавить #include ) для того, что бы дальше ее проанализировать. Команд у нас не много поэтому здесь происходит проверка условием.
Надеюсь, смысл команд понятен. Замечу, что после выполнения каждой команды мы посылаем клиенту уведомление об успешности выполнения. Например, вот участок кода:

if(a=="BT")
{
HWND h=GetDesktopWindow(); 
EnableWindow(h, FALSE);
strcpy(szSendBuff,"The working table is blocked");
send(sock, szSendBuff, sizeof(szSendBuff), 0);

}

После того как стол заблокирован мы отправляем клиенту сообщение ,"The working table is blocked" – что означает рабочий стол заблокирован.
Все мы подготовили простейший макет клиент – сервера и даже внедрили некоторые функции. Чтое еще можно зделать? Все информация которую мы передаем в winsock передаеться байтами поэтому можно передать любой файл. Например скриншот экрана.
Если подумать, то можно организовать даже потоковое видео. Вот примерный алгоритм

на стороне сервера храним текущий кадр и прошлый, сверяем разницу между ними, получаем битовую маску, она сжимается нефигово, потом передаем изменившиеся части(только их, сплошным потоком) клиент уже смотря по маске подставляет эти части в нужные места
Правда программно я это не проверял. Может ты зделаешь?
Это все. До свидания.

©StraNger
Cпециально для hackzona.ru
03.02.2009

 

Уроки для хакеров и программистов

huzrus
3 февраля 2013, 21:50
1234

Загрузка...
Loading...

Комментарии

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

Спасибо за открытие блога в Yvision.kz! Чтобы убедиться в отсутствии спама, все комментарии новых пользователей проходят премодерацию. Соблюдение правил нашей блог-платформы ускорит ваш переход в категорию надежных пользователей, не нуждающихся в премодерации. Обязательно прочтите наши правила по указанной ссылке: Правила

Также можно нажать Ctrl+Enter

Популярные посты

Школа High Tech High – дети здесь самостоятельны так же, как и профессионалы в офисах

Школа High Tech High – дети здесь самостоятельны так же, как и профессионалы в офисах

Известный казахстанский бизнесмен становится первопроходцем и создает школу, о которой можно только мечтать. То, что мы, как взрослые, делаем в бизнесе, дети будут делать в этой школе.
Zhumanova
24 апр. 2017 / 16:29
  • 21700
  • 5
Кому в Казахстане жить хорошо? Почему мы остаёмся в топ-5 стран мира по числу самоубийств

Кому в Казахстане жить хорошо? Почему мы остаёмся в топ-5 стран мира по числу самоубийств

Всё ли так хорошо у жителей Казахстана? Почему-то наша страна сохраняет твёрдые позиции в первых строчках мировых рейтингов по числу самоубийств.
openqazaqstan
24 апр. 2017 / 16:54
  • 4255
  • 20
«Казпочта» отжигает. Редкий шанс вспомнить агрессивные советские очереди

«Казпочта» отжигает. Редкий шанс вспомнить агрессивные советские очереди

Люди старшего и среднего поколений помнят шумные, недобрые, грубо ругающиеся очереди советских лет. Увидеть, как это было, можно теперь разве что в каком-нибудь фильме. Хотя не только.
openqazaqstan
26 апр. 2017 / 16:14
  • 2955
  • 33
Президент велел делиться. Почему бы казахстанским миллиардерам не послушаться?

Президент велел делиться. Почему бы казахстанским миллиардерам не послушаться?

Президент Назарбаев призвал крупных бизнесменов делиться с народом, следуя примеру своих коллег из развитых стран. В Казахстане, действительно, сегодня много богатых людей.
openqazaqstan
27 апр. 2017 / 14:09
  • 2497
  • 26
Юный алматинец покорил Первый канал на шоу Максима Галкина

Юный алматинец покорил Первый канал на шоу Максима Галкина

Житель Алматы по имени Марк Усачев недавно оказался на телепрограмме "Лучше всех", с успехом идущей на Первом канале России. 9-летний алматинец покорил публику своими недюжинными знаниями.
Seattle
24 апр. 2017 / 16:59
  • 2594
  • 2
Любовница. «Мне часто доставались мужчины, поломанные браком»

Любовница. «Мне часто доставались мужчины, поломанные браком»

Мне часто доставались мужчины, поломанные браком. Таких почти сразу видно – у них маска состоявшегося мужчины по швам трещит. И каждый из них реагирует по-своему. Поясню на паре примеров.
Jamiklisa
28 апр. 2017 / 14:21
Преподаватели и ЭКСПО: «Пока газеты пишут одно, нас заставляют покупать билеты на выставку»

Преподаватели и ЭКСПО: «Пока газеты пишут одно, нас заставляют покупать билеты на выставку»

Чтобы вы знали, чем занимаются в сфере образования - педагоги являются основой массовок. Какое отношение к учителям со стороны государства, такого же уровня и качество образования.
SaukovV
26 апр. 2017 / 16:05
  • 2412
  • 16
Инстаграм – это «рынок девушек» и он круче любой базы данных

Инстаграм – это «рынок девушек» и он круче любой базы данных

Для меня Инстаграм – это рынок. Почему? Ничего не изменилось, девушки все так же бьются в попытках наиболее выгодно себя продать, посредством привлечения внимания.
Annette_Scherer
24 апр. 2017 / 22:35
  • 2419
  • 5
Жуткие истории о рабстве – такие вещи творятся в стране, принимающей «ЭКСПО»

Жуткие истории о рабстве – такие вещи творятся в стране, принимающей «ЭКСПО»

Мы живём, возможно, уже совсем в другом обществе, а не в том, к которому привыкли. Не первый год Казахстан периодически потрясают жуткие истории о рабстве.
openqazaqstan
26 апр. 2017 / 9:39
  • 2191
  • 22