Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2011.09.11;
Скачать: [xml.tar.bz2];

Вниз

TSocketClient и TSocketServer работа с потоками   Найти похожие ветки 

 
Vladimir   (2009-03-01 10:27) [0]

Доброго времени суток всем! Заранее извиняюсь если данная тема уже поднималась, но в поиске ответа на свой вопрос я так и не нашел. Требуется написать клиент-серверное приложение. В данный момент написал пробные клиент и сервер на SocketClient и SocketServer соответсвенно работающие в синхронном режиме. Подскажите пожалуйста каким образом  организовать их работу в асинхронном режиме, чтобы сервер одновременно обслуживал несколько клиентов! И ещё есть такая проблема при посылке текста через SendText на сервер приходят иероглифы, причем  это только на Windows Vista, на Windows XP все работало нормально. Использую Delphi 2009. Из-за чего это может быть? Заранее спасибо.


 
Сергей М. ©   (2009-03-01 12:30) [1]

SocketServer в любом режиме способен обслуживать более одного клиента.
В режиме stNonBlocking обслуживание всех клиентов последовательное в одном потоке, в режиме stThreadBlocking каждое активное кл.соединение уже обслуживается в отдельном потоке.


 
Сергей М. ©   (2009-03-01 12:42) [2]

Режим работы ClientSocket м.б. любым и никаким образом не каксается режима работы ServerSocket


 
Vladimir   (2009-03-01 12:48) [3]

Спасибо конечно)) Но я и спрашиваю каким образом организовать работу сервера в режиме stThreadBlocking. Ведь для каждого клиента надо создавать отдельный поток, а когда клиент отключиться его надо уничтожать и т.д.


 
Сергей М. ©   (2009-03-01 12:53) [4]


> Но я и спрашиваю каким образом организовать работу сервера
> в режиме stThreadBlocking


Это и есть синхронный режим. Только не самого компонента, а сокетов, которые он создает и использует в ходе работы.


> для каждого клиента надо создавать отдельный поток, а когда
> клиент отключиться его надо уничтожать


TServerSocket все это делает сам


 
Vladimir   (2009-03-01 13:07) [5]

Сергей, видимо мы с вами друг друга немного не понимаем. Вы не могли бы выложить код самого простого многопоточного сервера и сделать пометки в тех местах где поток создаеться, где можно проделывать какие-либо действия с клиентом(принимать от него данные, посылать ему данные) и где поток уничтожаеться. Может быть тогда у меня получиться разобраться. И из-за чего может быть проблема с SendText?


 
Сергей М. ©   (2009-03-01 13:14) [6]

Вот не ахти какой, но достаточно показательный пример:

http://www.delphisources.ru/pages/faq/base/tserversocket.html


 
Slym ©   (2009-03-02 05:32) [7]

зачем далеко ходить? на этом форуме недалече второй страницы
http://delphimaster.net/view/6-1227604925/


 
Empleado ©   (2009-03-02 12:32) [8]


> И из-за чего может быть проблема с SendText?

Из-за Уникод?


 
Vladimir   (2009-03-03 12:09) [9]


> Из-за Уникод?

А как можно с этим разобраться? чтоб текст нормальный приходил?


 
Сергей М. ©   (2009-03-03 12:27) [10]


> Vladimir   (03.03.09 12:09) [9]


Что ты послал, то и получишь.
Данные при их транспортировке под управлением TCP доставляются в гарантированно неизменном виде.


 
Empleado ©   (2009-03-03 12:29) [11]


> А как можно с этим разобраться? чтоб текст нормальный приходил?

Например, отправлять Уникод и принимать Уникод.

Прочитать в хелпе об использовании Unicode в D2009. Там подробно написано, с примерами, как работать со строками.
Не использовать SendText, a SendBuf, например, либо TWinSocketStream.Read/Write.
При чтении из сокета, преобразовывать полученное в Unicode. Например с помощью класса TEncoding.Unicode.GetString [или же StringOf в случае telnet].


 
Vladimir   (2009-03-03 13:46) [12]

спасибо, попробую.


 
Vladimir   (2009-03-03 20:31) [13]

Спасибо, все получилось. Только появился ещё один вопрос. Когда клиент присоединяеться к серверу для него создаеться отдельный поток, а из потока вызываеться некая процедура которая работает с файлом(записывает в него данные) и закрывает файл... Дело в том что если сервер работает не в многопоточном режиме, то проблемы одновременного обращения к файлу не возникает, а как быть при моем раскладе с потоками? Как "объяснить" компьютеру  подождать пока один поток поработает с файлом и только потом самому приступать к работе с ним?


 
Сергей М. ©   (2009-03-03 20:46) [14]


> процедура которая работает с файлом(записывает в него данные)
> и закрывает файл


Уж не файл ли протокола ?


 
medved_68 ©   (2009-03-04 08:56) [15]


> Как "объяснить" компьютеру  подождать пока один поток поработает
> с файлом и только потом самому приступать к работе с ним?
>

Для этого придуманы объекты синхронизации и доступ к файлу в режиме ShareDenyNone


 
Vladimir   (2009-03-04 09:06) [16]


> Уж не файл ли протокола ?

нет, файл базы данных


> Для этого придуманы объекты синхронизации и доступ к файлу
> в режиме ShareDenyNone

я знаю... но хотел узнать нельзя ли каким то образом блокировать секцию кода, до тех пор пока она не будет выполнена... сделать что то вроде:

Lock;
выполняемый операции
UnLock;

чтобы если какой то поток уже начал обрабатывать этот участок кода, то другому потоку пришлось ждать пока первый закончит с ним работать.


 
Сергей М. ©   (2009-03-04 09:45) [17]


> нет, файл базы данных


И какая СУБД при этом тобой используется ?
Или ты валишь данные прямо в файл, называя при этом "базой данных" именно этот файл ?


 
Vladimir   (2009-03-04 10:14) [18]


> Или ты валишь данные прямо в файл, называя при этом "базой
> данных" именно этот файл ?


В чем то ты прав. СУБД я не использую, но и не валю все прямо в файл(есть некая структура)... но, думаю что сейчас объяснять все в подробностях ни к чему.


 
Сергей М. ©   (2009-03-04 10:22) [19]

Ясно.
Считай что валишь прямо в файл.
Ну тогда его надо бы защитить критической секцией (см. TCriticalSection).


 
Vladimir   (2009-03-04 10:43) [20]


> Ясно.
> Считай что валишь прямо в файл.
> Ну тогда его надо бы защитить критической секцией (см. TCriticalSection).
>


Хорошо, спасибо, это я сделаю. Но мне помнилось что можно как то секцию кода блокировать или может быть называеться это как то по другому. Просто давно как то писал простенький многопоточный чат и там тоже  необходимо было предотвратить одновременное обращение как к файлу, так и к общим переменным. Исходников того чата не осталось и как именно прописывал это не помню.


 
Сергей М. ©   (2009-03-04 11:05) [21]


> помнилось что можно как то секцию кода блокировать или может
> быть называеться это как то по другому


Вот как раз "критической секцией" это и называется.


 
Vladimir   (2009-03-04 11:13) [22]

спасибо Сергей. Буду вспоминать и разбираться.


 
Vladimir   (2009-03-08 10:26) [23]

С критическими секциями разобрался. Все ок. Но возникла новая проблема. ClientSocket должен автоматически входить в событие Read когда к нему приходят данные от сервера, но он почему то этого не делает. Пришлось сделать следующее. Создать глобальную переменную RegSocket: TWinSocketStream и на событие Connect клиента(RegClient) поставил следующий код RegSocket := TWinSocketStream.Create(Socket, 60000);

А в том месте, где необходимо получить ответ от сервера поставил следующий код

while not RegSocket.WaitForData(100) do
Application.ProcessMessages;
RegClient.OnRead(Sender, RegClient.Socket);

То есть вручную проверяю пришли ли данные от сервера и если пришли, то вызываю процедуру Read клиента. Хотя по идеи клиент сам должен понять что сервер послал ему данные и сам войти в событие Read. В чем может быть дело?


 
Сергей М. ©   (2009-03-09 15:00) [24]


> ClientSocket должен автоматически входить в событие Read
> когда к нему приходят данные


Нет, не должен.
Событие OnRead возбуждается только при условии ClientType = ctNonBlocking, а у тебя ctBlocking


 
Vladimir   (2009-03-12 20:59) [25]

И что же делать? Оставить тот вариант который я уже реализовал? Вроде он рабочий...


 
Сергей М. ©   (2009-03-12 21:22) [26]


> что же делать?


А что, на событиях свет клином сошелся ?


 
Vladimir   (2009-03-12 22:01) [27]

Нет) просто немного напрягает когда часть отправки данных пишеться в событиях клиента, а часть приема данных пишеться "где-то" причем ручками. Не знаю почему, но есть какое-то чувство, что то что я сам дописал возьмет и не сработает. Вот и ответ на вопрос "сошелся ли свет клином на событиях")


 
Тын-Дын ©   (2009-03-13 00:16) [28]


> Vladimir   (12.03.09 22:01) [27]


Раз у тебя Borland-сокеты работают в режиме st/ctBlockinkg, то и используй их возможности для обработки входящих данных.


 
Сергей М. ©   (2009-03-13 20:55) [29]


> часть отправки данных пишеться в событиях клиента


Каких конкретно ?


 
Zalm ©   (2009-04-29 02:05) [30]

Вот попытался собрать то что указано по ссылке
http://www.delphisources.ru/pages/faq/base/tserversocket.html
но ничего не получилось, выдает ошибки памяти.

procedure TForm1.ServerGetThread(Sender: TObject;
 ClientSocket: TServerClientWinSocket;
 var SocketThread: TServerClientThread);
begin
 SocketThread := CServerThread.Create( FALSE, ClientSocket );
end;

Procedure CServerThread.ClientExecute;
var
REQUESTSIZE : integer;
fRequest : array [0..1024] of char;
ac,readlen : integer;
begin
 inherited FreeOnTerminate := TRUE;
 try
   fSocketStream := TWinSocketStream.Create( ClientSocket, 1000 );
   // 100000 - это таймаут в миллисекундах.
   try
     while ( not Terminated ) and ( ClientSocket.Connected ) do
       try
         // В это место обычно помещается код,
         // ожидающий входных данных, читающий из сокета или пишущий в него
         // Пример, приведённый ниже, показывает, что можно добавить в данную
         // секцию программы.
          FillChar( fRequest, REQUESTSIZE, 0 );
          ac := 0;
          repeat
           readlen := fSocketStream.read( fRequest[ac], 1024 );
           // считываем блоки по 1024 байт, до тех пор, пока буфер
           // не заполнится
           ac := ac+readlen;
          until
          (readlen = 0) or (ac = REQUESTSIZE);
       except
         on e:exception do
         begin
           // Если произошла ошибка, то закрываем сокет и выходим
           ClientSocket.Close;
           Terminate;
         end;
       end;
   finally
     fSocketStream.Free;
   end;
 except
   on e:exception do
   begin
     // Если произошла ошибка, то закрываем сокет и выходим
     ClientSocket.Close;
     Terminate;
   end;
 end;
end;


Еще не понял как отправлять с клиента что-то на такой сервер...
Помогите пожалуйста


 
Сергей М. ©   (2009-04-29 09:16) [31]


> inherited FreeOnTerminate := TRUE;


Это убрать.


> FillChar( fRequest, REQUESTSIZE, 0 );


Чему в этот момент равно значение переменной REQUESTSIZE ?


> Terminate;


Это тоже убрать.


> не понял как отправлять с клиента что-то на такой сервер


Т.е. на какой-то другой ты понял, а вот именно на этот не понял ?


 
Zalm ©   (2009-04-29 17:46) [32]

обычних серверов я три штуки написал, в не блокирующем режиме, там всё просто, отправить и принять, а тут сложннее, либо же я просто пока не понял кк это делать :(

REQUESTSIZE походу ничему не равно, даже не инициализированно.

inherited FreeOnTerminate := TRUE; такого вроде у меня там и не было...


 
Сергей М. ©   (2009-04-29 19:28) [33]


> обычних серверов я три штуки написал


Значит пора прекращать задавать откровенно дилетантские вопросы)
"Три штуки"  - стаж как-никак солидный)


> в не блокирующем режиме, там всё просто, отправить и принять,
>  а тут сложннее


И здесь все тоже самое - "отправить и принять". Никакой разницы.


> REQUESTSIZE походу ничему не равно, даже не инициализированно


"Походу" ты эти даже гордишься)
Было бы чем ..


> inherited FreeOnTerminate := TRUE; такого вроде у меня там
> и не было


Значит это я сам придумал от нечего делать)


 
Zalm ©   (2009-04-29 20:27) [34]


Procedure CServerThread.ClientExecute;
var
REQUESTSIZE : integer;
fRequest : array [0..1024] of char;
ac,readlen : integer;
begin
try
  fSocketStream := TWinSocketStream.Create( ClientSocket, 1000 );
  try
    while ( not Terminated ) and ( ClientSocket.Connected ) do
      try
         FillChar( fRequest, REQUESTSIZE, 0 );
         ac := 0;
         repeat
          readlen := fSocketStream.read( fRequest[ac], 1024 );
          ac := ac+readlen;
         until
         (readlen = 0) or (ac = REQUESTSIZE);
      except
        on e:exception do
        begin
          ClientSocket.Close;
        end;
      end;
  finally
    fSocketStream.Free;
  end;
except
  on e:exception do
  begin
    ClientSocket.Close;
  end;
end;
end;


С исправлениями будет так, а REQUESTSIZE какое значение присвоить?


> "Три штуки"  - стаж как-никак солидный)

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


> Значит пора прекращать задавать откровенно дилетантские
> вопросы)

да всё плохо с этими потоками, всё страшно и не понятно xD
и ничего тут не так же... тут всё как-то по пакетам... ваще я пока не понимаю этого... клиет будет для такого блокирующего ервера будет еще одной бедой моей:(


 
Сергей М. ©   (2009-04-30 08:34) [35]


> REQUESTSIZE какое значение присвоить?


Размер буфера, который ты нулями заполняешь.


> тут всё как-то по пакетам


Что "всё" ? По каким таким "пакетам" ?


> клиет будет для такого блокирующего ервера


Клиент не может ничего знать о режиме сервера и об использовании им мультипоточности, равно как и сервер о режимах своих клиентов, среди которых м.б. как блокирующие, так и неблокирующие.


 
Zalm ©   (2009-04-30 20:27) [36]


> Что "всё" ? По каким таким "пакетам" ?

ну а что тут тогда делается?
readlen := fSocketStream.read( fRequest[ac], 1024 );


> Клиент не может ничего знать о режиме сервера


то есть sendtext точно так же и работает с клиента?


 
Сергей М. ©   (2009-04-30 20:34) [37]


> а что тут тогда делается?


Здесь предпринимается попытка чтения  очередных 1024 байт из потока входящих данных. Никакими пакетами здесь даже не пахнет.


> sendtext точно так же и работает с клиента?


sendtext"у абсолютно фиолетово кто ее вызывает.
sendtext предпринимает попытку отправки некимх данных партнеру по соединению.
Для клиентов партнером является сервер, для сервера партнерами являются клиенты.


 
Zalm ©   (2009-04-30 23:59) [38]

так а как прочитать одну комманду? если читать по 1024 сразу то можно и на следующий запрос взезть...

То есть то что я отправлю через сенд текст с клинета, прилетит на сервер как раз в тот самый СокетСтрим?

а переменную ас чем надо инициализировать?


 
Сергей М. ©   (2009-05-01 14:24) [39]


> а как прочитать одну комманду?


А какое отношение это имеет к режиму ? Никакого абсолютно.


> можно и на следующий запрос взезть


Ну и что ? "Остаток", если он был обнаружен, никуда не пропал, если ты его, конечно, не выбросил собственноручно.. При следующем чтении к "остатку" приклеишь то что будет в очередной раз прочитано


> переменную ас чем надо инициализировать?


Ты же ее уже проинициализировал

> ac := 0;


 
Zalm ©   (2009-05-01 18:45) [40]


> А какое отношение это имеет к режиму ? Никакого абсолютно.

как это никакого? у меня вобще проблема с пониманием этой процедуры, как она работает, то ли там крутится вечно в цикле, то ло еще не пойми как.
К какой момент мы что-то читаем из буфера и тд... :(



Страницы: 1 2 вся ветка

Форум: "Сети";
Текущий архив: 2011.09.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.005 c
15-1305712370
mefodiy
2011-05-18 13:52
2011.09.11
Размер exe файла в Дельфи 2010


15-1305707691
Пося
2011-05-18 12:34
2011.09.11
Помогите перевести на английский?


2-1306693281
Brutalis
2011-05-29 22:21
2011.09.11
смоделировать простого робота так чтобы он двигался по заданным з


2-1306583696
Delphi beginner
2011-05-28 15:54
2011.09.11
Где ошибка в программе?


15-1306012234
Германн
2011-05-22 01:10
2011.09.11
Настройки IDE Delphi2007





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский