Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> TClientSocket, TServerSocket, Клиент-серверное приложение 
:(
    Опции темы
Dayana
Дата 21.10.2002, 03:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 352
Регистрация: 6.10.2002
Где: Тель-Авив

Репутация: 1
Всего: 4



Пишу клиент-серверное приложение. Опыта в этом нет. Серверная часть выдает ошибку на методе чтения, когда клиент посылает серверу данные.
Ошибка:
Read Error 59: AN unexpected network error occurred;

По ходу вопрос: свойство Service классов TClienSocket и TServerSocket, что должно содержать в моем случае?

вот код:
Клиент:

var
 i : byte;
 ClientSocket1: TClientSocket;
 StreamSocket  : TWinSocketStream;
 CN : array[0..10] of char;
 LenCN: integer;
 AddCN: Pointer;
 strCN : string;

begin
 ClientSocket1 := TClientSocket.Create(nil);
 if ClientSocket1.Active then
   ClientSocket1.Close;
 ClientSocket1.Host := '10.10.100.24';
 ClientSocket1.Address := '10.10.100.24';
 ClientSocket1.Port := 7770;
 ClientSocket1.ClientType := ctBlocking;
 ClientSocket1.Open;
 Sleep(400);
 strCN := 'CompName';
 FillChar(CN, 11, 0);
 StrPCopy(CN, strCN);
 StreamSocket := TWinSocketStream.Create(ClientSocket1.Socket, 60000);
 StreamSocket.Write(CN, Length(CN));
 Sleep(1000);
 StreamSocket.Free;
 ClientSocket1.Socket.Close;
end.

Сервер:

var
 ServerSocket1: TServerSocket;
 StreamSocket  : TWinSocketStream;
 Buffer : array[0..10] of char;
 sRcvMsg : string;
 T : TDateTime;
 TimeInt : extended;
 LenMsg : integer;
begin
 sRcvMsg := 'Test Passed';
 ServerSocket1 := TServerSocket.Create(nil);
 if ServerSocket1.Active then
   ServerSocket1.Close;
 ServerSocket1.Port := 7770;
 ServerSocket1.ServerType := stThreadBlocking;
 ServerSocket1.ThreadCacheSize := 4;
 ServerSocket1.Socket.Listen('Имя сервера', '10.10.100.24', '', 7770, 4);
 T := Now;
 FillChar(Buffer, 11, 0);
 StreamSocket := TWinSocketStream.Create(ServerSocket1.Socket, 10000);
 repeat
   if not StreamSocket.WaitForData(10000) then
   begin
     Application.ProcessMessages;
     SaveToFile(FloatToStr((Now-T)*SecsPerDay));
   end
   else
   begin
     LenMsg := StreamSocket.Read(Buffer, 11);
     if LenMsg <> 0 then
     begin
       sRcvMsg := StrPas(Buffer);
       SaveToFile(sRcvMsg);
       Break;
     end
     else
       SaveToFile('Nothing read');
   end;
 until (Now - T)*SecsPerDay > 240;
 SaveToFile(sRcvMsg);
 TimeInt := (Now - T)*SecsPerDay;
 SaveToFile(FloatToStr(TimeInt));
 if ServerSocket1.Active then
   ServerSocket1.Close;

Заранее благодарю за ответ!
PM MAIL ICQ   Вверх
Fantasist
Дата 21.10.2002, 04:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: нет
Всего: 41



Прежде чем общаться, надо дождаться соеденения. Посмотри для сервера событие OnGetThread - его тебе нужно обработать. Для клиента тоже неплохо бы дождаться соеденения, а потом уж посылать.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Fantasist
Дата 21.10.2002, 04:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: нет
Всего: 41



Да, позволь пару реккомендаций.
Создай какой-нибудь класс типа сесии TSession - который будет описывать конкретное соеденение.
По возможности его лучше сделать максимально абстрактным - включить в него метод отсылки данных, событие сигнализирующие о приеме данных.
Я лично создавал в таком классе два TMemoryStream: StreamIn и StreamOut, виртуальный метод DataAccepted - вызывается когда принимается очередная порция данных, а также переменную типа TCustomWinSocket - значение которой задавалось при устонавлении соеденения и через нее сессия и обменивалась данными.
 Над таким классом удобнее определять наследников типа TClientSession и TServerSession - для описания твоего протокола.

Я помниться тоже начинал как-то без опыта клиент-сервера писать, со своим протоколом. Все оказалось не так просто, как казалось в начале. Одним из неприятных моментов было как раз то, что VCL-ные сокеты дают мало пространства для абстракции  плюс к этому  возникают в них какие-то непонятные глюки. Возможно лучше воспользоваться PowerSock от NetMasters - он такой более универсальный. Или TCPServer и TCPClient от Indy - в них никакой универсальности, но на вид гораздо более удобны.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Dayana
Дата 21.10.2002, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 352
Регистрация: 6.10.2002
Где: Тель-Авив

Репутация: 1
Всего: 4



Fantasist, спасибо большое за советы!
PM MAIL ICQ   Вверх
Dayana
Дата 21.10.2002, 21:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 352
Регистрация: 6.10.2002
Где: Тель-Авив

Репутация: 1
Всего: 4



Когда я устанавливаю ClientType и ServerType = ctNonBlocking, то клиент соединяется с сервером и сервер реагирует на событие OnClientConnect. Если же ставлю ClientType = ctBlocking и ServerType = ctThreadBlocking, то соединения не происходит. В чем проблема? Какая разница для самого соединения?
PM MAIL ICQ   Вверх
Fantasist
Дата 22.10.2002, 02:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: нет
Всего: 41



А ты уверена, что соеденения не происходит? Я клиента никогда блокирующим не делал - у меня блокирующий только сервер. В последний раз я, правда, так сделал, когда понял, что без блокирующего сервера не обойтись, а клиента переделывать не стал.
 Так вот разница есть, и есть она именно на уровне сокетов Windows. Для сервера VCL-ный сокет с ctThreadBlocking создает отдельный поток для каждого соеденения, но перед этим генерирует событие OnGetThread, в котором тебе и нужно подставить свой поток.  Правда соеденение в любом случае, по идее, должно устанавливаться. Попробу клиента сделать не блокирующим.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Serg
Дата 25.10.2002, 18:39 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Для примера можешь исходник борландовского сокета пощупать. Там все как на лодони. Но все что ты городила до этого можно немного упростить.
Сделай вот такую вещь:

На сервере для блокированного сокета:

procedure TForm1.ClientEvent(Sender: TObject; Socket: TCustomWinSocket;
 SocketEvent: TSocketEvent);
begin
 with ServerSocket1.Socket do begin
   case SocketEvent of
     seAccept,
     seLookup,
     seConnecting,
     seListen:
       begin end;
     seConnect: if Assigned(OnClientConnect) then OnClientConnect(Sender, Socket);
     seDisconnect: if Assigned(OnClientDisconnect) then OnClientDisconnect(Sender, Socket);
     seRead: if Assigned(OnClientRead) then OnClientRead(Sender, Socket);
     seWrite: if Assigned(OnClientWrite) then OnClientWrite(Sender, Socket);
   end;
 end;
end;

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
 Socket: TCustomWinSocket);
begin
 MessageBeep(0);
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
 ServerSocket1.Socket.OnSocketEvent := ClientEvent;
 ServerSocket1.Active := true;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
begin
 MessageBox(0,PChar(Socket.ReceiveText),'!!!', MB_OK);
end;

А это на клиенте:

procedure TForm1.Button1Click(Sender: TObject);
begin
 ClientSocket1.Socket.SendText('123456789');
end;

Работает изумительно, ничего дополнительно лепить не нужно.
Единственное неудобство- OnClientConnect не работает. Либо же включи в свой проект явно модуль ScktComp(скопируй в свою директорию) и замени
вот это

constructor TServerClientWinSocket.Create(Socket: TSocket; ServerWinSocket: TServerWinSocket);
begin
 FServerWinSocket := ServerWinSocket;
 if Assigned(FServerWinSocket) then
 begin
   FServerWinSocket.AddClient(Self);
   if FServerWinSocket.AsyncStyles <> [] then begin
     OnSocketEvent := FServerWinSocket.ClientEvent;
     OnErrorEvent := FServerWinSocket.ClientError;
   end
   else
     with FServerWinSocket do begin
       OnSocketEvent := ClientEvent;
       OnErrorEvent := ClientError;
     end;
 end;
 inherited Create(Socket);
 if FServerWinSocket.ASyncStyles <> [] then begin
   DoSetAsyncStyles;
   if FConnected then Event(Self, seConnect);
 end
 else
   if FConnected then FServerWinSocket.Event(Self, seConnect);
end;

Дальше пользуй просто обработчики событий.

procedure TForm1.FormActivate(Sender: TObject);
begin
 ServerSocket1.Socket.OnSocketEvent := ClientEvent;
^^^^^^^^^^
Это не понадобиться

 ServerSocket1.Active := true;
end;
  Вверх
Fantasist
Дата 26.10.2002, 02:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: нет
Всего: 41



То что написал Serg - это годиться для НЕ блокирующего сокета. Но для него схему можно и получше придумать, но даже с хорошой схемой, не блокирующий сервер не способен обслуживать множество соеденений.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Serg
Дата 26.10.2002, 23:31 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Могу спорить хоть на ящик шампанского, что работает. :)
Это действительно работало бы только для неблокируемых сокетов в стандартной реализации. Но, если ты внимательно читал сообщение, я предлагаю сделать некоторые изменения в исходнике сокета - поправить ScktComp, заменить реализацию конструктора TServerClientWinSocket
вот оригинальная редакция

constructor TServerClientWinSocket.Create(Socket: TSocket; ServerWinSocket: TServerWinSocket);
begin
 FServerWinSocket := ServerWinSocket;
 if Assigned(FServerWinSocket) then
 begin
   FServerWinSocket.AddClient(Self);
   if FServerWinSocket.AsyncStyles <> [] then
   begin
     OnSocketEvent := FServerWinSocket.ClientEvent;
     OnErrorEvent := FServerWinSocket.ClientError;
   end;
 end;
 inherited Create(Socket);
 if FServerWinSocket.ASyncStyles <> [] then DoSetAsyncStyles;
 if FConnected then Event(Self, seConnect);
end;

А это то чем необходимо заменить

constructor TServerClientWinSocket.Create(Socket: TSocket; ServerWinSocket: TServerWinSocket);
begin
FServerWinSocket := ServerWinSocket;
if Assigned(FServerWinSocket) then
begin
  FServerWinSocket.AddClient(Self);
  if FServerWinSocket.AsyncStyles <> [] then begin
    OnSocketEvent := FServerWinSocket.ClientEvent;
    OnErrorEvent := FServerWinSocket.ClientError;
  end
  else
    with FServerWinSocket do begin
      OnSocketEvent := ClientEvent;
      OnErrorEvent := ClientError;
    end;
end;
inherited Create(Socket);
if FServerWinSocket.ASyncStyles <> [] then begin
  DoSetAsyncStyles;
  if FConnected then Event(Self, seConnect);
end
else
  if FConnected then FServerWinSocket.Event(Self, seConnect);
end;

Заметь, разница существует.
Не буду распространяться на тему синхронизаций и иных мелочей.
Просто попробуй сделать как я посоветовал. Все работает.
  Вверх
Fantasist
Дата 27.10.2002, 02:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: нет
Всего: 41



Спасибо, но у меня и так все работает  :)
А поповоду неблокирующего сервера - он у меня тоже работал, для многих подключений пока надо было только принять запрос и отправить ответ. Ка только понадобилось вести, так сказать, диалог с клиентом, тут то он и обламался в сфере приема информации.

Всместо модератора:

Старайтесь заключать листинги в теги [CODE] [/CODE], для этого есть удобная кнопочка наверху.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Dayana
Дата 28.10.2002, 01:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 352
Регистрация: 6.10.2002
Где: Тель-Авив

Репутация: 1
Всего: 4



У меня сейчас все работает с неблокирующим сокетом. А с блокирующим еще пробовала...
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.0490 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.