Гобелен - кликните для возврата на главную
Не прошло и месяца а Фурмановская ЦРБ в очередной раз попала в историю. На этот раз сотрудница клеветала на пациентов, а именно огласку получил случай когда сотрудница назвала пациента алкашём.
Ровно 3 года назад произошло событие, которое подарило жителям планеты Змеля новый чистый праздник 6 апреля - в этот замечательный день земля забрала гнить негодяя и СПАМера Жладимира Вольфовича Жириновского.
Как бы не обстояли дела в области культуры и IT-технологий, Самосвал писал статьи на связанные темы и планирует ещё написать.
Начал разбираться с информацией которая находится в HTTPS клиентском запросе рукопожатия.
Обратите внимание! Объект изображённый на гобилене может отличаться от общепринятого вида описанного объекта. Тут дело в том что художник видит именно так!
На форме находится Button1 - кнопка старта сервера, Button2 - кнопка остановки сервера, ListBox1 - список клиентов(которые в настоящий момент подключены к серверу), Memo1 - список сообщений(от клиентов и им), Edit1 - поле ввода сообщения для клиента, Button3 - кнопка отправки сообщения из Edit1 клиенту который выбран в ListBox1, Edit2 - поле для задания порта(применяется в момент старта сервера). TCP-сервер реализауется через WinSock.
Файл Unit1.h
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <winsock2.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:
TButton *Button1;
TButton *Button2;
TListBox *ListBox1;
TMemo *Memo1;
TEdit *Edit1;
TButton *Button3;
TLabel *Label1;
TEdit *Edit2;
TLabel *Label2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall Button3Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
void __fastcall ListBox1Click(TObject *Sender);
private:
SOCKET ListenSocket;
HANDLE ServerThread;
bool ServerRunning;
TList* ClientSockets;
CRITICAL_SECTION csClientList;
int ServerPort;
AnsiString LogMessage;
TStringList* ClientListItems;
bool EnableSendButton;
void AddToLog(AnsiString msg);
void UpdateClientList();
void RemoveClient(SOCKET clientSocket);
static DWORD WINAPI ServerThreadProc(LPVOID lpParam);
static DWORD WINAPI ClientThreadProc(LPVOID lpParam);
void SendToClient(SOCKET clientSocket, AnsiString message);
bool StartServer(int port);
void StopServer();
void __fastcall AddLogToMemo();
void __fastcall UpdateClientListBox();
void __fastcall EnableSendButtonProc();
public:
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Файл Unit1.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include <stdio.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
InitializeCriticalSection(&csClientList);
ClientSockets = new TList;
ListenSocket = INVALID_SOCKET;
ServerThread = NULL;
ServerRunning = false;
ServerPort = 12345;
ClientListItems = new TStringList;
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
StopServer();
DeleteCriticalSection(&csClientList);
delete ClientSockets;
delete ClientListItems;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
ShowMessage("Ошибка инициализации Winsock");
Button1->Enabled = false;
return;
}
Edit2->Text = "12345";
Button1->Enabled = true;
Button2->Enabled = false;
Button3->Enabled = false;
AddToLog("Сервер готов к запуску. Введите порт и нажмите 'Старт сервера'");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AddLogToMemo()
{
Memo1->Lines->Add(LogMessage);
}
//---------------------------------------------------------------------------
void TForm1::AddToLog(AnsiString msg)
{
LogMessage = FormatDateTime("hh:nn:ss", Now()) + " - " + msg;
TThread::Synchronize(NULL, AddLogToMemo);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::UpdateClientListBox()
{
ListBox1->Items->BeginUpdate();
ListBox1->Items->Assign(ClientListItems);
ListBox1->Items->EndUpdate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::EnableSendButtonProc()
{
Button3->Enabled = EnableSendButton;
}
//---------------------------------------------------------------------------
void TForm1::UpdateClientList()
{
EnterCriticalSection(&csClientList);
try
{
ClientListItems->Clear();
EnableSendButton = false;
for (int i = 0; i < ClientSockets->Count; i++)
{
SOCKET s = (SOCKET)ClientSockets->Items[i];
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
if (getpeername(s, (sockaddr*)&clientAddr, &addrLen) == 0)
{
AnsiString clientInfo = inet_ntoa(clientAddr.sin_addr) + AnsiString(":") + IntToStr(ntohs(clientAddr.sin_port));
ClientListItems->Add(clientInfo);
}
}
EnableSendButton = (ClientSockets->Count > 0 && ListBox1->ItemIndex >= 0);
}
__finally
{
LeaveCriticalSection(&csClientList);
}
TThread::Synchronize(NULL, UpdateClientListBox);
TThread::Synchronize(NULL, EnableSendButtonProc);
}
//---------------------------------------------------------------------------
bool TForm1::StartServer(int port)
{
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET)
{
AddToLog("Ошибка создания сокета: " + IntToStr(WSAGetLastError()));
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
if (bind(ListenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
AddToLog("Ошибка bind: " + IntToStr(WSAGetLastError()));
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
return false;
}
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
AddToLog("Ошибка listen: " + IntToStr(WSAGetLastError()));
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
return false;
}
ServerRunning = true;
ServerThread = CreateThread(NULL, 0, ServerThreadProc, this, 0, NULL);
return true;
}
//---------------------------------------------------------------------------
void TForm1::StopServer()
{
if (!ServerRunning) return;
ServerRunning = false;
if (ListenSocket != INVALID_SOCKET)
{
closesocket(ListenSocket);
ListenSocket = INVALID_SOCKET;
}
if (ServerThread)
{
WaitForSingleObject(ServerThread, INFINITE);
CloseHandle(ServerThread);
ServerThread = NULL;
}
EnterCriticalSection(&csClientList);
for (int i = 0; i < ClientSockets->Count; i++)
{
SOCKET s = (SOCKET)ClientSockets->Items[i];
closesocket(s);
}
ClientSockets->Clear();
LeaveCriticalSection(&csClientList);
}
//---------------------------------------------------------------------------
DWORD WINAPI TForm1::ServerThreadProc(LPVOID lpParam)
{
TForm1* form = (TForm1*)lpParam;
SOCKET listenSocket = form->ListenSocket;
while (form->ServerRunning)
{
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
SOCKET clientSocket = accept(listenSocket, (sockaddr*)&clientAddr, &addrLen);
if (clientSocket == INVALID_SOCKET)
{
if (form->ServerRunning)
form->AddToLog("Ошибка accept: " + IntToStr(WSAGetLastError()));
continue;
}
EnterCriticalSection(&form->csClientList);
form->ClientSockets->Add((void*)clientSocket);
LeaveCriticalSection(&form->csClientList);
AnsiString clientInfo = inet_ntoa(clientAddr.sin_addr) + AnsiString(":") + IntToStr(ntohs(clientAddr.sin_port));
form->AddToLog("Клиент подключен: " + clientInfo);
form->UpdateClientList();
form->SendToClient(clientSocket, "Добро пожаловать на сервер! Ваш ID: " + clientInfo);
HANDLE hThread = CreateThread(NULL, 0, ClientThreadProc, (LPVOID)new std::pair<TForm1*, SOCKET>(form, clientSocket), 0, NULL);
CloseHandle(hThread);
}
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI TForm1::ClientThreadProc(LPVOID lpParam)
{
auto params = (std::pair<TForm1*, SOCKET>*)lpParam;
TForm1* form = params->first;
SOCKET clientSocket = params->second;
delete params;
char buffer[1024];
int bytesReceived;
while (form->ServerRunning)
{
bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0)
{
if (bytesReceived == SOCKET_ERROR)
form->AddToLog("Ошибка чтения от клиента: " + IntToStr(WSAGetLastError()));
break;
}
buffer[bytesReceived] = '\0';
AnsiString message(buffer);
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
getpeername(clientSocket, (sockaddr*)&clientAddr, &addrLen);
AnsiString clientInfo = inet_ntoa(clientAddr.sin_addr) + AnsiString(":") + IntToStr(ntohs(clientAddr.sin_port));
form->AddToLog("[" + clientInfo + "]: " + message);
if (message.LowerCase() == "exit")
{
form->SendToClient(clientSocket, "До свидания!");
break;
}
form->SendToClient(clientSocket, "ECHO: " + message);
}
closesocket(clientSocket);
form->RemoveClient(clientSocket);
form->AddToLog("Клиент отключен");
form->UpdateClientList();
return 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int port = StrToIntDef(Edit2->Text, 0);
if (port <= 0 || port > 65535)
{
AddToLog("Неверный номер порта. Допустимый диапазон: 1-65535");
return;
}
ServerPort = port;
if (StartServer(ServerPort))
{
Button1->Enabled = false;
Button2->Enabled = true;
Edit2->Enabled = false;
AddToLog("Сервер запущен на порту " + IntToStr(ServerPort));
}
else
{
AddToLog("Не удалось запустить сервер на порту " + IntToStr(ServerPort));
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
StopServer();
Button1->Enabled = true;
Button2->Enabled = false;
Button3->Enabled = false;
Edit2->Enabled = true;
ListBox1->Clear();
AddToLog("Сервер остановлен");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if (ListBox1->ItemIndex < 0) return;
AnsiString message = Edit1->Text;
if (message.IsEmpty()) return;
EnterCriticalSection(&csClientList);
try
{
if (ListBox1->ItemIndex >= 0 && ListBox1->ItemIndex < ClientSockets->Count)
{
SOCKET clientSocket = (SOCKET)ClientSockets->Items[ListBox1->ItemIndex];
SendToClient(clientSocket, message);
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
getpeername(clientSocket, (sockaddr*)&clientAddr, &addrLen);
AnsiString clientInfo = inet_ntoa(clientAddr.sin_addr) + AnsiString(":") + IntToStr(ntohs(clientAddr.sin_port));
AddToLog("Сервер -> [" + clientInfo + "]: " + message);
Edit1->Clear();
}
}
__finally
{
LeaveCriticalSection(&csClientList);
}
}
//---------------------------------------------------------------------------
void TForm1::SendToClient(SOCKET clientSocket, AnsiString message)
{
if (send(clientSocket, message.c_str(), message.Length(), 0) == SOCKET_ERROR)
{
AddToLog("Ошибка отправки сообщения: " + IntToStr(WSAGetLastError()));
RemoveClient(clientSocket);
UpdateClientList();
}
}
//---------------------------------------------------------------------------
void TForm1::RemoveClient(SOCKET clientSocket)
{
EnterCriticalSection(&csClientList);
try
{
int index = ClientSockets->IndexOf((void*)clientSocket);
if (index >= 0)
{
ClientSockets->Delete(index);
}
}
__finally
{
LeaveCriticalSection(&csClientList);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
StopServer();
WSACleanup();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox1Click(TObject *Sender)
{
Button3->Enabled = (ListBox1->ItemIndex >= 0);
}
//---------------------------------------------------------------------------
Вы так же можете прочитать следующие статьи: