![]() |
|
Модераторы: Snowy, Poseidon, MetalFan |
![]()
|
|
| Dayana |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 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; Заранее благодарю за ответ! |
|||
|
||||
| Fantasist |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
Прежде чем общаться, надо дождаться соеденения. Посмотри для сервера событие OnGetThread - его тебе нужно обработать. Для клиента тоже неплохо бы дождаться соеденения, а потом уж посылать.
-------------------- Волны гасят ветер... |
|||
|
||||
| Fantasist |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
Да, позволь пару реккомендаций.
Создай какой-нибудь класс типа сесии TSession - который будет описывать конкретное соеденение. По возможности его лучше сделать максимально абстрактным - включить в него метод отсылки данных, событие сигнализирующие о приеме данных. Я лично создавал в таком классе два TMemoryStream: StreamIn и StreamOut, виртуальный метод DataAccepted - вызывается когда принимается очередная порция данных, а также переменную типа TCustomWinSocket - значение которой задавалось при устонавлении соеденения и через нее сессия и обменивалась данными. Над таким классом удобнее определять наследников типа TClientSession и TServerSession - для описания твоего протокола. Я помниться тоже начинал как-то без опыта клиент-сервера писать, со своим протоколом. Все оказалось не так просто, как казалось в начале. Одним из неприятных моментов было как раз то, что VCL-ные сокеты дают мало пространства для абстракции плюс к этому возникают в них какие-то непонятные глюки. Возможно лучше воспользоваться PowerSock от NetMasters - он такой более универсальный. Или TCPServer и TCPClient от Indy - в них никакой универсальности, но на вид гораздо более удобны. -------------------- Волны гасят ветер... |
|||
|
||||
| Dayana |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 352 Регистрация: 6.10.2002 Где: Тель-Авив Репутация: 1 Всего: 4 |
Fantasist, спасибо большое за советы!
|
|||
|
||||
| Dayana |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 352 Регистрация: 6.10.2002 Где: Тель-Авив Репутация: 1 Всего: 4 |
Когда я устанавливаю ClientType и ServerType = ctNonBlocking, то клиент соединяется с сервером и сервер реагирует на событие OnClientConnect. Если же ставлю ClientType = ctBlocking и ServerType = ctThreadBlocking, то соединения не происходит. В чем проблема? Какая разница для самого соединения?
|
|||
|
||||
| Fantasist |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
А ты уверена, что соеденения не происходит? Я клиента никогда блокирующим не делал - у меня блокирующий только сервер. В последний раз я, правда, так сделал, когда понял, что без блокирующего сервера не обойтись, а клиента переделывать не стал.
Так вот разница есть, и есть она именно на уровне сокетов Windows. Для сервера VCL-ный сокет с ctThreadBlocking создает отдельный поток для каждого соеденения, но перед этим генерирует событие OnGetThread, в котором тебе и нужно подставить свой поток. Правда соеденение в любом случае, по идее, должно устанавливаться. Попробу клиента сделать не блокирующим. -------------------- Волны гасят ветер... |
|||
|
||||
| Serg |
|
|||
|
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 |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
То что написал Serg - это годиться для НЕ блокирующего сокета. Но для него схему можно и получше придумать, но даже с хорошой схемой, не блокирующий сервер не способен обслуживать множество соеденений.
-------------------- Волны гасят ветер... |
|||
|
||||
| Serg |
|
|||
|
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 |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: нет Всего: 41 |
Спасибо, но у меня и так все работает
А поповоду неблокирующего сервера - он у меня тоже работал, для многих подключений пока надо было только принять запрос и отправить ответ. Ка только понадобилось вести, так сказать, диалог с клиентом, тут то он и обламался в сфере приема информации. Всместо модератора: Старайтесь заключать листинги в теги [CODE] [/CODE], для этого есть удобная кнопочка наверху. -------------------- Волны гасят ветер... |
|||
|
||||
| Dayana |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 352 Регистрация: 6.10.2002 Где: Тель-Авив Репутация: 1 Всего: 4 |
У меня сейчас все работает с неблокирующим сокетом. А с блокирующим еще пробовала...
|
|||
|
||||
![]()
|
| Правила форума "Delphi: Сети" | |
|
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делится вскрытыми компонентами
Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Delphi: Сети | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |