Исходник клиент-сервера с авторизацией для передачи сообщений и файлов

Всем привет! Не говорил, да и повода не было, что я ранее немного программировал. Для себя. И собирал разные исходники, доделывал, изменял. Не знаю как сейчас обстоят дела с языками, что пишут на C#, а что на Котлине, но остались у меня некоторые наработки и черновики. На специализированных ресурсах выкладывать неохота — не люблю форумы с их больше болтовнёй чем делом. Решил для начала выложить здесь исходник клиент-сервера с авторизацией для передачи сообщений и файлов, может кому поможет.

Клиент-сервер на основе сокетов

Итак, представляю вам простой рабочий клиент-сервер с авторизацией на основе сокетов (ServerSocket и ClientSocket) написанный на Паскале и скомпилированный под Delphi 2009. Та версия Delphi была с ошибками, так что код своеобразный, да и такой — на коленке. Окончательного варианта нет, увы.



Ниже исходник сокетного клиента и сервера на Delphi. Особенности программ:

Клиент подключается к серверу и отправляет пароль. При совпадении пароля сервер с клиентом могут отправлять друг другу сообщения. Сервер может отправлять файлы выбранным клиентам.

За код прошу не судить, в комментариях укажите на ошибки.

Компоненты для сервера: ServerSocket1, IdIPWatch1

Определена глобальная переменная — MS: TMemoryStream, добавьте ее.

Сервер отсылает файл 000.txt из той же директории где находится. Нет сложности добавить выбор произвольного файла. Клиент сохраняет файл в свою директорию как 002.txt .

Код сервера

var
  Form1: TForm1;
  MS: TMemoryStream;                                                             // Буфер для файла
implementation

{$R *.dfm}

////////////////////////////////////////////////////////////////////////////////
//  запускаем сервер
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button1Click(Sender: TObject);
var
port:Integer;
begin
  port:=StrToInt(Edit1.Text);
  ServerSocket1.Port:=port;
   if ServerSocket1.Active = True then
    begin
      ServerSocket1.Active:=False;
      Button1.Caption:='Запустить';
      StatusBar1.SimpleText := 'Сервер остановлен ';
      Memo1.Lines.Add('[Server]:  Сервер остановлен');
      ListBox1.Clear;
    end
      else
        begin
          ServerSocket1.Active:=True;
          Button1.Caption:='Остановить';
          StatusBar1.SimpleText := 'Сервер запущен ';
          Memo1.Lines.Add('[Server]:  Сервер запущен');
        end;
end;

////////////////////////////////////////////////////////////////////////////////
//  посылаем сообщение клиенту
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button2Click(Sender: TObject);
var
A: array[0..159] of Char;                                                       // максимальная длина сообщения
  S,SL: string;
begin
S:=Edit6.Text;
StrPCopy(A, S);
if ListBox1.ItemIndex <> -1 then  begin                                         // если есть подключенные клиенты
  SL:= ListBox1.Items.Strings[ListBox1.ItemIndex];                              // SL =  выбранной записи
    if SL > '' then                                                             // если строка не пустая
      begin
        ServerSocket1.Socket.Connections[ListBox1.ItemIndex].SendText(S);       // послать сообщение адресату
        Memo1.Lines.Add('['+TimeToStr(Time)+'][Server]['+ SL+']:  '+Edit6.Text);// записать в лог
      end;
    end
      else
        Memo1.Lines.Add('[Server]:  не выбран адресат');                        // записать в лог, что адресат не установлен
end;

////////////////////////////////////////////////////////////////////////////////
//  посылаем файл клиенту
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button3Click(Sender: TObject);
var
  Size: integer;
SL:string;
  P: ^Byte;
begin
 if ListBox1.ItemIndex <> -1 then  begin                                        // если есть подключенные клиенты
  SL:= ListBox1.Items.Strings[ListBox1.ItemIndex];                              // SL =  выбранной записи
    if SL > '' then                                                             // если строка не пустая
      begin
        MS := TMemoryStream.Create;                                             // Создаём буфер для файла
        MS.LoadFromFile('000.txt');                                             // Загружаем файл в буфер

        ServerSocket1.Socket.Connections[ListBox1.ItemIndex].SendText(
        'file#'+'000.pdf'+'#'+IntToStr(MS.Size)+'#');                           // Посылаем информацию о файл (команда # название # размер)
        MS.Position := 0;                                                       // Переводим каретку в начало файла
        P := MS.Memory;                                                         // Загружаем в переменную "P" файл
        Size := ServerSocket1.Socket.Connections[ListBox1.ItemIndex].SendBuf(
        P^, MS.Size);                                                           // Посылаем файл
        ProgressBar1.Position := Size*100 div MS.Size;                          // Выводим прогресс
        StatusBar1.SimpleText := 'Отправлено '+IntToStr(Size)+' из '+IntToStr(  // Выводим отчёт
        MS.Size)+' байт';
      end;
    end
      else
       Memo1.Lines.Add('[Server]:  не выбран адресат');                         // записать в лог, что адресат не установлен
end;

////////////////////////////////////////////////////////////////////////////////
//  отключаем клиента
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button4Click(Sender: TObject);
var
 SL: string;
 i:integer;
begin
 if ListBox1.ItemIndex <> -1 then  begin                                        // если есть подключенные клиенты
  SL:= ListBox1.Items.Strings[ListBox1.ItemIndex];                              // SL =  выбранной записи
    if SL > '' then                                                             // если строка не пустая
      begin
        ServerSocket1.Socket.Connections[ListBox1.ItemIndex].Close;             // отключаем выбранного клиента
      end;
   end
     else
     Memo1.Lines.Add('[Server]:  не выбран адресат');                           // иначе записать в лог, что адресат не установлен
end;

////////////////////////////////////////////////////////////////////////////////
//  создание формы
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormCreate(Sender: TObject);
begin
  StatusBar1.SimpleText := 'Сервер остановлен ';                                // выводим в статус
  Edit5.Text:=IdIPWatch1.LocalIP;                                               // получаем локальный IP
end;

////////////////////////////////////////////////////////////////////////////////
//  уничтожение формы
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ServerSocket1.Close;                                                            // Закрываем сокет
end;

////////////////////////////////////////////////////////////////////////////////
//  клиент подключился
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
    ListBox1.Items.Add(Socket.RemoteHost+'  '+Socket.RemoteAddress+':  '+IntToStr(// Добавляем имя клиента в список
    Socket.SocketHandle));
    ServerSocket1.Socket.Connections[ListBox1.Count-1].SendText(                  // Отправляем клиенту приветствие
    IntToStr(  Socket.SocketHandle));
    Memo1.Lines.Add('['+TimeToStr(Time)+'] Сlient ['+Socket.RemoteHost+ // Добавляем имя клиента в список
    '  '+Socket.RemoteAddress+':'+IntToStr(Socket.SocketHandle)+'] подключился');
    StatusBar1.SimpleText := 'Соединение установлено';
end;

////////////////////////////////////////////////////////////////////////////////
//  отключился клиент
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
  var
 i,P,j:integer;
 s:string;
begin
   Memo1.Lines.Add('['+TimeToStr(Time)+'] Сlient ['+Socket.
   RemoteHost+'  '+Socket.RemoteAddress+':'+IntToStr(Socket.SocketHandle)+'] отключился'); // Выводим отключившегося клиента в лог
   s:= inttostr(Socket.SocketHandle);
   for i := 0 to ListBox1.Count-1 do
     begin
       P:=Pos(AnsiLowerCase(s),AnsiLowerCase(ListBox1.Items[i]));               // Проверяем есть ли запись соотв. логу
       if P>0  then j:=i;
     end;
   ListBox1.Items.Delete(j);                                                    // Если есть, то удаляем из списка
end;

////////////////////////////////////////////////////////////////////////////////
//  получаем подтверждение пароля от клиента
//  получаем сообщение от клиента
//  получаем подтверждение получения файла от клиента
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
 s,ss: AnsiString;
 ps:string;
 bb:integer;
begin
  SetLength(s, Socket.ReceiveLength);
  SetLength(s, Socket.ReceiveBuf(Pointer(s)^, Length(s)));
  ss:=string(s);
      if Copy(ss, 1, 10) ='#password#' then                                     // Если это пароль, то...
          begin
           Delete(ss, 1, 10);                                                   // удаляем ключевое слово #password#
            if ss = Edit2.Text then                                             // если оставшееся равно действующему паролю, то
              begin
                  Memo1.Lines.Add('['+TimeToStr(Time)+'] Сlient ['+Socket.RemoteHost+ // Добавляем имя клиента в список
                  '  '+Socket.RemoteAddress+':'+IntToStr(Socket.SocketHandle)+'] авторизован');
                  Exit;                                                         // выходим без показа пароля
              end
                else
              begin
                  Memo1.Lines.Add('['+TimeToStr(Time)+'] Не верный пароль: ['+Socket.RemoteHost+ // Добавляем имя клиента в список
                  '  '+Socket.RemoteAddress+':'+IntToStr(Socket.SocketHandle)+']');
                  ServerSocket1.Socket.Connections[ListBox1.Items.Count-1].Close;  //если чат, то печатаем сразу
               end;
         end;
    if s <> 'Клиент получил файл' then Memo1.Lines.Add('['+TimeToStr(Time)+']['+Socket.RemoteHost+'  '+Socket.
  RemoteAddress+':'+IntToStr(Socket.SocketHandle)+']:  '+ String(s));            // записать в лог сообщение
   if s = 'Клиент получил файл' then                                            // Если получили сообщение, то...
     begin
        Memo1.Lines.Add('['+TimeToStr(Time)+'] Сlient ['+Socket.RemoteHost+     // Добавляем имя клиента в список
        '  '+Socket.RemoteAddress+':'+IntToStr(Socket.SocketHandle)+'] получил файл');
        StatusBar1.SimpleText := 'Клиент '+Socket.RemoteHost+' получил файл';   // Выводим информацию о результате
        MS.Free;                                                                // Убиваем буфер
      end;
end;
end.


Код клиента

Компоненты для клиента: СlientSocket1, IdIPWatch1

  private
    { Private declarations }
  Name: string;                                                                 // Имя файла
  Size: integer;                                                                // Размер файла
  Receive: boolean;                                                             // Режим клиента
  MS: TMemoryStream;                                                            // Буфер для файла
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

////////////////////////////////////////////////////////////////////////////////
//   сохранение полученного файла
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Writing(Text: ansistring);
begin
  if MS.Size < Size then                                                        // Если принято байт меньше размера файла, то...
    MS.Write(Text[1], Length(Text));                                            // Записываем в буфер
    ProgressBar1.Position := MS.Size*100 div Size;                              // Выводим прогресс закачки файла
    StatusBar1.SimpleText := 'Принято '+IntToStr(MS.Size)+' из '+IntToStr(Size);
  if MS.Size = Size then                                                        // Если файл принят, то...
      begin
        Receive := false;                                                           // Переводим клиента в нормальный режим
        MS.Position := 0;                                                           // Переводим каретку в начало буфера
        MS.SaveToFile('002.txt');                                                   // Сохраняем файл
        ClientSocket1.Socket.SendText('Клиент получил файл');                                       // Посылаем команду "end", то есть файл принят
        MS.Free;                                                                    // Убиваем буфер
        StatusBar1.SimpleText := 'Файл принят.'+'Размер файла: '+IntToStr(Size)+' байт';
      end;
end;

////////////////////////////////////////////////////////////////////////////////
//   подключиться к серверу
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button1Click(Sender: TObject);
begin
  ClientSocket1.Host:=Edit1.Text;
  ClientSocket1.Port:=StrToInt(Edit2.Text);

  if ClientSocket1.Active = True then
    begin
      ClientSocket1.Active:=False;
      Button1.Caption:='Подключиться';
    end
      else
        begin
        Button1.Caption:='Отключиться';
          ClientSocket1.Open;
        end;
end;

////////////////////////////////////////////////////////////////////////////////
//   отправить сообщение
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.Button2Click(Sender: TObject);
begin
  if ClientSocket1.Active = True then
  begin
    ClientSocket1.Socket.SendText(Edit5.Text);
    Memo1.Lines.Add('['+ClientSocket1.Socket.LocalHost+']['+ClientSocket1.Socket.RemoteHost+']:  '+edit5.Text);
  end;
end;

////////////////////////////////////////////////////////////////////////////////
//   подключение к серверу
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Memo1.Lines.Clear;
  Edit4.Text:=ClientSocket1.Socket.LocalHost;
  StatusBar1.SimpleText := 'Соединение установлено';
  ClientSocket1.Socket.SendText('#password#'+Edit6.Text);Код
end;

////////////////////////////////////////////////////////////////////////////////
//   отключение от сервера
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Button1.Caption:='Подключиться';
  StatusBar1.SimpleText := 'Соединение прервано';
  ClientSocket1.Active:=False;
end;

////////////////////////////////////////////////////////////////////////////////
//   ошибка подключения к серверу
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  Button1.Caption:='Подключиться';
  StatusBar1.SimpleText := 'Сервер не найден. '+'Ошибка ' + IntToStr(ErrorCode);
  ErrorCode:=0;                                                                 // убиваем ошибку
  ClientSocket1.Socket.Close;                                                   // закрываем сокет
end;

////////////////////////////////////////////////////////////////////////////////
//   получение файла от сервера
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
var
 s: AnsiString;                                                                 // Принятый текст
begin
 SetLength(s, Socket.ReceiveLength);                                            //это от глюка компонентов делфи 2009
 SetLength(s, Socket.ReceiveBuf(Pointer(s)^, Length(s)));                       //это от глюка компонентов делфи 2009
   if Receive =true then                                                        // Если клиент в режиме приёма файла, то...
      Writing(s)                                                                // Записываем данные в буфер
       else                                                                     // Если клиент не в режиме приёма файла, то...
      begin
       if Copy(s, 0, (Pos('#', s) -1)) = 'file' then                            // Если это файл, то...
         begin
           MS:= TMemoryStream.Create;                                           // Создаём буфер для файла
           Delete(s, 1, Pos('#', s));                                           // Определяем имя файла
           Name:= Copy(s, 0, Pos('#', s) -1);                                   // Определяем имя файла
           Delete(s, 1, Pos('#', s));                                           // Определяем размер файла
           Size:= StrToInt(Copy(s, 0, Pos('#', s) -1));                         // Определяем размер файла
           Delete(s, 1, Pos('#', s));                                           // Удаляем последний # разделитель
           Receive:= true;                                                      // Переводим сервер в режим приёма файла
           Writing(s);                                                          // Записываем данные в буфер
         end
          else
            Memo1.Lines.Add (String(s));                                        //если чат, то печатаем сразу
       end;
end;

////////////////////////////////////////////////////////////////////////////////
//   закрытие формы
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ClientSocket1.Close;
end;

////////////////////////////////////////////////////////////////////////////////
//   начальные данные
////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit3.Text:=IdIPWatch1.LocalIP;                                               // установить вручную
  Edit1.Text:=IdIPWatch1.LocalIP;
  Edit2.Text:='1001';                                                           // установить вручную
  Receive := false;
  StatusBar1.SimpleText := 'Соединение не установлено';                         // Режим клиента - приём команд
end;
end.

В принципе и всё. Будут вопросы — отвечу. Если найду исходник, то выложу.


Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 Оценили 3
Загрузка...

Поделитесь, пожалуйста, ссылкой





Войдите с помощью вашего аккаунта: 
avatar
2000
1 Цепочка комментария
1 Ответы по цепочке
0 Последователи
 
Популярнейший комментарий
Цепочка актуального комментария
2 Авторы комментариев
Антон ТретьякИлья Авторы недавних комментариев
Илья
Илья

Спасибо! Первый полный рабочий исходник в интернете! А как сделать автоматическое подключение и передачу файла? У тебя кнопкой сделано. И как автоматически подключаться если сервер пока не работает, таймером?