| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Сети > TClientSocket, TServerSocket |
| Автор: Dayana 21.10.2002, 03:18 |
| Пишу клиент-серверное приложение. Опыта в этом нет. Серверная часть выдает ошибку на методе чтения, когда клиент посылает серверу данные. Ошибка: 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 21.10.2002, 04:01 |
| Прежде чем общаться, надо дождаться соеденения. Посмотри для сервера событие OnGetThread - его тебе нужно обработать. Для клиента тоже неплохо бы дождаться соеденения, а потом уж посылать. |
| Автор: Fantasist 21.10.2002, 04:39 |
| Да, позволь пару реккомендаций. Создай какой-нибудь класс типа сесии TSession - который будет описывать конкретное соеденение. По возможности его лучше сделать максимально абстрактным - включить в него метод отсылки данных, событие сигнализирующие о приеме данных. Я лично создавал в таком классе два TMemoryStream: StreamIn и StreamOut, виртуальный метод DataAccepted - вызывается когда принимается очередная порция данных, а также переменную типа TCustomWinSocket - значение которой задавалось при устонавлении соеденения и через нее сессия и обменивалась данными. Над таким классом удобнее определять наследников типа TClientSession и TServerSession - для описания твоего протокола. Я помниться тоже начинал как-то без опыта клиент-сервера писать, со своим протоколом. Все оказалось не так просто, как казалось в начале. Одним из неприятных моментов было как раз то, что VCL-ные сокеты дают мало пространства для абстракции плюс к этому возникают в них какие-то непонятные глюки. Возможно лучше воспользоваться PowerSock от NetMasters - он такой более универсальный. Или TCPServer и TCPClient от Indy - в них никакой универсальности, но на вид гораздо более удобны. |
| Автор: Dayana 21.10.2002, 18:27 |
| Fantasist, спасибо большое за советы! |
| Автор: Dayana 21.10.2002, 21:28 |
| Когда я устанавливаю ClientType и ServerType = ctNonBlocking, то клиент соединяется с сервером и сервер реагирует на событие OnClientConnect. Если же ставлю ClientType = ctBlocking и ServerType = ctThreadBlocking, то соединения не происходит. В чем проблема? Какая разница для самого соединения? |
| Автор: Fantasist 22.10.2002, 02:17 |
| А ты уверена, что соеденения не происходит? Я клиента никогда блокирующим не делал - у меня блокирующий только сервер. В последний раз я, правда, так сделал, когда понял, что без блокирующего сервера не обойтись, а клиента переделывать не стал. Так вот разница есть, и есть она именно на уровне сокетов Windows. Для сервера VCL-ный сокет с ctThreadBlocking создает отдельный поток для каждого соеденения, но перед этим генерирует событие OnGetThread, в котором тебе и нужно подставить свой поток. Правда соеденение в любом случае, по идее, должно устанавливаться. Попробу клиента сделать не блокирующим. |
| Автор: Serg 25.10.2002, 18:39 |
| Для примера можешь исходник борландовского сокета пощупать. Там все как на лодони. Но все что ты городила до этого можно немного упростить. Сделай вот такую вещь: На сервере для блокированного сокета: 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 |
| То что написал Serg - это годиться для НЕ блокирующего сокета. Но для него схему можно и получше придумать, но даже с хорошой схемой, не блокирующий сервер не способен обслуживать множество соеденений. |
| Автор: Serg 26.10.2002, 23:31 |
| Могу спорить хоть на ящик шампанского, что работает. Это действительно работало бы только для неблокируемых сокетов в стандартной реализации. Но, если ты внимательно читал сообщение, я предлагаю сделать некоторые изменения в исходнике сокета - поправить 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 |
| Спасибо, но у меня и так все работает А поповоду неблокирующего сервера - он у меня тоже работал, для многих подключений пока надо было только принять запрос и отправить ответ. Ка только понадобилось вести, так сказать, диалог с клиентом, тут то он и обламался в сфере приема информации. Всместо модератора: Старайтесь заключать листинги в теги [CODE] [/CODE], для этого есть удобная кнопочка наверху. |
| Автор: Dayana 28.10.2002, 01:27 |
| У меня сейчас все работает с неблокирующим сокетом. А с блокирующим еще пробовала... |