Севастопольский национальный технический университет
Кафедра ИС
Лабораторная работа №6
Исследование средств обмена, предоставленных библиотекой Winsock для взаимодействия клиент - серверных приложений
Выполнил:
Проверил:
Севастополь
2014
ЦЕЛЬ РАБОТЫ
Исследовать средства обмена, предоставленные библиотекой WinSock для взаимодействия клиент - серверных приложений.
ВАРИАНТ ЗАДАНИЯ
Вариант 2.
Реализовать “клиент – серверное” приложение, таким образом, чтоб сервер поддерживал как минимум три соединения. Сервер рассылает сообщения одновременно всем клиентам.
ХОД РАБОТЫ
Текст программы клиентской части
#pragma argsused
#include <vcl.h>
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#pragma hdrstop
#include "fMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
SOCKET my_sock;
//---------------------------------------------------------------------------
__fastcallTfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
// ведёмлог
void Log(AnsiString text){
frmMain->memLog->Lines->Add(text);
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::btnConnectClick(TObject *Sender)
{
char buff[1024];
// инициализациябиблиотеки Winsock
if (WSAStartup(0x202,(WSADATA *)&buff[0])){
Log("ОшибкаWSAStartup "+IntToStr(WSAGetLastError()));
return;
}
Log("Структура WSAStartup заполнена");
// созданиесокета
my_sock = socket(AF_INET,SOCK_STREAM,0);
if (!my_sock){
Log("Ошибка создания сокета
");
return;
}
Log("Сокет создан");
// установка соединения
// заполнение структуры sockaddr_in
// указание адреса и порта сервера
sockaddr_indest_addr;
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(StrToInt(edtPort->Text));
dest_addr.sin_addr.s_addr=inet_addr(edtAddress->Text.c_str());
// пытаемсяустановитьсоединение
Log("Пытаемся установить соединение...");
if (connect(my_sock,(sockaddr *)&dest_addr, sizeof(dest_addr))){
Log("Ошибкаподключения к серверу: "+IntToStr(WSAGetLastError()));
return;
}
// Неблокирующийрежим
unsigned long *argp=(u_long FAR*)malloc(sizeof(u_long));
*argp=1;
ioctlsocket(my_sock,FIONBIO,argp);
Log("Неблокирующийрежимвключён");
Log("Подключение установлено =)");
frmMain->Timer1->Enabled=true;
btnConnect->Enabled = false;
btnDisconnect->Enabled = true;
}
// создание потока для обработки подключившихся клиентов
DWORD WINAPI TestClient(LPVOID client_socket) {
return 0;
}
void Disconnect()
{
if(closesocket(my_sock)!=SOCKET_ERROR){
Log("Закрытиесокета...OK");
if(WSACleanup()!=SOCKET_ERROR){
Log("WSACleanup...OK");
} else {
Log("Ошибка: командаWSACleanupвернулаошибку: "+IntToStr(WSAGetLastError()));
}
} else {
Log("Ошибка: командаclosesocketвернулаошибку: "+IntToStr(WSAGetLastError()));
}
Log("Отключение... OK");
}
void __fastcallTfrmMain::btnDisconnectClick(TObject *Sender)
{
frmMain->Timer1->Enabled=false;
Log("Отключение...");
char buffer[1024];
memset(buffer,0,1024);
strcat(buffer,"#disconn");
if(send(my_sock,buffer,1024,0)!=SOCKET_ERROR){
Log("Посылказапросанаотключение");
}else{
Log("Ошибка: "+IntToStr(WSAGetLastError()));
}
Disconnect();
btnConnect->Enabled = true;
btnDisconnect->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::Timer1Timer(TObject *Sender)
{
//char cl_ip[20];
intbytes_recv = 0;
char buff[1024];
AnsiStringrecvBuf;
bytes_recv = recv(my_sock,&buff[0],sizeof(buff),0);
if((bytes_recv) && (bytes_recv != SOCKET_ERROR)){
recvBuf = buff;
if (recvBuf.AnsiCompare("#disconn") == 0) {
Log(">Cерверпринудительноразорвал соединение...");
char mess[1] = "1";
send(my_sock,mess,1,0);
btnConnect->Enabled = true;
btnDisconnect->Enabled = false;
Disconnect();
} else {
Log(">"+recvBuf);
}
memset(buff, 0, sizeof(buff));
}
Application->ProcessMessages();
}
//---------------------------------------------------------------------------
Текстпрограммысервернойчасти
#include <vcl.h>
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#pragma hdrstop
#include "fMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
// созданиесокета
SOCKET mysocket;
// прототипфункции, обслуживающей
// подключившихсяпользователей
DWORD WINAPI TestClient(LPVOID client_socket);
// глобальнаяпеременная - количество
// активных пользователей
intnclients = 0;
charclient_ip[20];
int shut=0;
sockaddr_inclient_addr; // адресклиента
// махколичествоклиентов
SOCKET users[255];
//---------------------------------------------------------------------------
__fastcallTfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
// выводинформации
void Log(AnsiString text){
frmMain->memLog->Lines->Add(text);
}// end of
//---------------------------------------------------------------------------
void __fastcallTfrmMain::btnConnectClick(TObject *Sender)
{
char buff[1024];
nclients=0;
// инициализациябиблиотеки Winsock
if (WSAStartup(0x202,(WSADATA *)&buff[0])){
Log("WSAStart error "+IntToStr(WSAGetLastError()));
return;
}
Log("Структура WSAStartup заполнена");
// созданиесокета
mysocket=socket(AF_INET,SOCK_STREAM,0);
if (!mysocket){
Log("Ошибкасозданиясокета: "+IntToStr(WSAGetLastError()));
return;
}
Log("Сокет создан");
// Не блокирующий режим
unsigned long *argp=(u_long FAR*)malloc(sizeof(u_long));
*argp=1;
ioctlsocket(mysocket,FIONBIO,argp);
Log("Неблокирующийрежимвключён");
// связывание сокета с локальным адресом
Log("Связывание сокета с локальным адресом");
sockaddr_inlocal_addr;
local_addr.sin_family=AF_INET;
local_addr.sin_port=htons(StrToInt(edtPort->Text));
local_addr.sin_addr.s_addr=0;
// вызываем bind длясвязывания
if (bind(mysocket,(sockaddr *) &local_addr, sizeof(local_addr))){
Log("Ошибкасвязывания "+IntToStr(WSAGetLastError()));
closesocket(mysocket); // закрываемсокет
WSACleanup();
return;
}
// ожиданиеподключений
if (listen(mysocket,5)){
Log("Ошибкарежимапрослушивания: "+IntToStr(WSAGetLastError()));
closesocket(mysocket);
WSACleanup();
return;
}
Log("Ожиданиеподключений...");
Timer1->Enabled = true;
btnConnect->Enabled = false;
btnDisconnect->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::btnDisconnectClick(TObject *Sender)
{
Timer1->Enabled = false;
Log("Отключение...");
char buff[1024];
memset(buff,0,1024);
strcat(buff,"#disconn");
for(int i = 0; i <nclients; i++){
if (send(users[i],buff,1024,0) != SOCKET_ERROR) {
Log("Уведомление об отключении клиенту №"+IntToStr(i+1)+" отправлено");
Sleep(1000);
} else {
Log("Уведомление об отключении клиенту №"+IntToStr(i+1)+" не отправлено");
}
}
if(closesocket(mysocket)!=SOCKET_ERROR){
Log("Сокетзакрыт...OK");
if(WSACleanup()!=SOCKET_ERROR){
Log("WSACleanup...OK");
}else{
Log("Ошибка: командаWSACleanupвернулаошибку: "+IntToStr(WSAGetLastError()));
}
}else{
Log("Ошибка: командаclosesocketвернулаошибку: "+IntToStr(WSAGetLastError()));
}
Log("Отключение...OK");
btnConnect->Enabled = true;
btnDisconnect->Enabled = false;
}
//---------------------------------------------------------------------------
// создание потока для обработки подклю-чившихся клиентов
DWORD WINAPI TestClient(LPVOID client_socket) {
charcl_ip[20];
SOCKET my_sock;
my_sock=((SOCKET *) client_socket)[0];
char buff[1024];
intsh=0;
intbytes_recv;
AnsiStringclientIP(inet_ntoa(client_addr.sin_addr));
// отправляемклиентуприветствие
//send(my_sock,MES,sizeof(MES),0);
// цикл эхо-сервера: прием строки от кли-ента и
// возвращение ее клиенту
while (1){
bytes_recv = recv(my_sock,&buff[0],sizeof(buff),0);
if(bytes_recv)
if(bytes_recv != SOCKET_ERROR){
Log("Отключение: "+clientIP);
if (!strcmp(buff, "#disconn")){
sh=1;
break;
}
memset(buff, 0, sizeof(buff));
//ShowMessage((AnsiString)buff);
}
Application->ProcessMessages();
Sleep(200);
}
if (sh){
// соединение клиентом разорвано
nclients--; // уменьшаем счетчик актив-ных клиентов
Log("Произошло отключение");
if (nclients){
Log(IntToStr(nclients) + " пользователей он-лайн");
}else{
Log("Нет пользователей в он-лайне");
}
// закрываемсокет
closesocket(my_sock);
}
return 0;
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::Timer1Timer(TObject *Sender)
{
// извлекаем сообщение из очереди
SOCKET client_socket; // сокет для кли-ента
// функции accept необходимо передать размер
// структуры
intclient_addr_size=sizeof(client_addr);
// циклизвлечениязапросов на подклю-чение из очереди
if ((client_socket=accept(mysocket, (sockaddr *) &client_addr, &client_addr_size))!=INVALID_SOCKET){
// увеличиваемсчетчикподключив-шихся клиентов
// вывод сведений о клиенте
Log("Новое подключение: " + (AnsiString)inet_ntoa(client_addr.sin_addr));
//Log(inet_ntoa(client_addr.sin_addr));
nclients++;
if (nclients){
Log(IntToStr(nclients) + " пользователейон-лайн");
DWORD thID;
CreateThread(NULL,NULL,TestClient, &client_socket,NULL,&thID);
users[nclients-1]=client_socket;
}else{
Log("Нет пользователей в он-лайне");
}
}
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::btnSendClick(TObject *Sender)
{
AnsiString temp = edtMessage->Text;
char buffer[1024];
char * message = temp.c_str();
memset(buffer,0,1024);
strcat(buffer,message);
for(int i=0; i <nclients; i++){
send(users[i],buffer,1024,0);
}
}
//---------------------------------------------------------------------------
void __fastcallTfrmMain::Button1Click(TObject *Sender)
{
memLog->Clear();
}
//---------------------------------------------------------------------------
Рисунок 1 – Начало работы серверной части
Рисунок 2 – Подключение клиентов к серверу
Рисунок 3 – Отправка сервером сообщения
Рисунок 4 – Получение клиентом серверного сообщения
Рисунок 5 – Отключение клиента
ВЫВОДЫ
В ходе выполнения лабораторной работы изучена библиотека WinSockдля взаимодействия клиент- серверных приложений.
Написаны две программы. Одна моделирует серверное приложение, вторая клиентское.
Исследование средств обмена, предоставленных библиотекой Winsock
Лабораторная работа по предмету «Программирование»