![]() |
|
Модераторы: Snowy, Poseidon, MetalFan |
![]()
|
|
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
какого типа должен быть Buff
|
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
не работает то принимает то нет, если размер структуры больше 1000 уже не принимает
|
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
разобрался немного еще отпишусь
|
|||
|
||||
| Чучмек |
|
||||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
-------------------- умную мысль держи при себе, а дурной - поделись с другими |
||||
|
|||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
какой сервер лучше? многопоточный? синхронный асинхронный? синхронный и асинхронный это однопоточные? Могу ли я мспользовать WSAAsyncSelect в многопоточном сервере?
Добавлено через 12 минут и 1 секунду система асинхронных сокетов прикольная и удобная. вобще мне нужно разработать так, чтобы сервер максимально быстро реагировал на входящие события сокетов и так же быстро рассылал им ответное сообщение, на данный момент, могу использовать 8 ядерный Core i7 или серверный комп |
|||
|
||||
| Чучмек |
|
|||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
Сколько одновременных подключений ожидается? Сколько времени будет занимать обработка данных от клиента + подготовка ответа? Все что ниже - лишь мое мнение. Если несколько подключений - однозначно многопоточный в блокирующем режиме (простота,распределение нагрузки по ядрам процессора, быстрота реакции) Если большое количество подключений - асинхронный. Если важна максимально быстрая реакция сервера на запросы клиента или процессорозатраты на обработку всех соединений не влезают в один поток (в производительность одного ядра), то необходим многопоточный (число потоков равно числу ядер) асинхронный. На каждый поток должно быть свое окно со своей очередью сообщений. Соединения должны распределятся между потокам. Окна придется создавать на WinAPI. Или используй другой способ работы с сокетами в неблокирующем режиме. Это сообщение отредактировал(а) Чучмек - 17.4.2013, 23:09 -------------------- умную мысль держи при себе, а дурной - поделись с другими |
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
сейчас пытаюсь сделать так
создал класс Tserver=class (TWinControl) //окно? окно! в нем создал слушающий serversocket, и событие WSAAsyncSelect, передающее FD_Accept в это же окно TServer при обработке сообщения внутри тела TServer, создается дополнительный класс TConnection = class(TWinControl), и в неё заполняются все данные о подключенном сокете, далее указатель на PConnection добавляется в список TList и связывает WSAAsyncSelect с окном TConnection как такой подход?
Добавлено через 1 минуту и 15 секунд получается типа многопоточности? Добавлено через 3 минуты и 51 секунду если учитывать что AsyncSelect переводит сокет в отдельный поток получается при каждом подключении создается сокет и заполняется в класс TWinControl и переводится в отдельный поток, получая в свою очередь события в виде сообщений Добавлено через 4 минуты и 36 секунд или это не так |
|||
|
||||
| Чучмек |
|
|||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
А где сами потоки? Нет? Какая тогда многопоточность? В Delphi отдельную очередь сообщений для окон с объектной оберткой (TWinControl) можно сделать только через Ж., и то, не уверен. -------------------- умную мысль держи при себе, а дурной - поделись с другими |
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
ну сообщения приходят нормально и программа работает без ошибок
Добавлено через 44 секунды былы конечно проблемы с CreateWnd, но они решились перекрытием метода |
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
вроде работает хорошо вот полный код
unit ServerSock; interface uses Dialogs, Classes, WinSock, Errunit, Controls, Forms, Messages, Windows, SysUtils; const WM_ACCEPTMESSAGE = WM_USER + 1; WM_SOCKETMESSAGE = WM_USER + 2; type TServer = class; TWMSocketMessage = packed record Msg: Cardinal; Socket: TSocket; SockEvent: Word; SockError: Word; end; TTransportPhase = (tpReceiveLength, tpReceivestring, tpSendstring); PConnection = ^TConnection; TConnection = class(TWinControl) private Owner: TServer; procedure WMSocketMessage(var Msg: TWMSocketMessage); message WM_SOCKETMESSAGE; public ClientSocket: TSocket; ClientAddr: AnsiString; MsgSize: Integer; Msg: AnsiString; Phase: TTransportPhase; Offset: Integer; BytesLeft: Integer; SendRead: Boolean; constructor Create(AOwner: TServer); destructor Destroy; override; end; TServer = class(TWinControl) private vWSAData: TWSAData; FHost: AnsiString; procedure Startup; //разрешить сокетное использование function Cleaned: Boolean; //запретить сокетн. использование procedure ClearConnections; procedure WMAcceptMessage(var Msg: TWMSocketMessage); message WM_ACCEPTMESSAGE; public FPort: Word; //только чтение Connections: TList; vServerSocket: TSocket;//серверный сокет который принимает входящие подключения vServerAddr: TSockAddr; // Адрес, к которому привязывается слушающий сокет function Start_Server(Port: Word): Boolean; constructor Create; destructor Destroy; override; // Метод GetConnectionBySocket находит в списке FConnections // запсись, соответствующую данному сокету function GetConnectionBySocket(S: TSocket): PConnection; end; function GetErrorstring(Error: Integer = 0): string; implementation uses Mainunit; { TServer } function GetErrorstring(Error: Integer = 0): string; var Buffer: array[0..2047] of AnsiChar; begin FormatMessage(forMAT_MESSAGE_FROM_SYSTEM, nil, Error, $400, @Buffer, SizeOf(Buffer), nil); Result := Buffer; end; procedure TServer.ClearConnections; var I: Integer; begin for I := 0 to Connections.Count - 1 do begin closesocket(PConnection(Connections[I])^.ClientSocket); PConnection(Connections[I])^.Destroy; end; Connections.Clear; end; constructor TServer.Create; var Params:TCreateParams; begin inherited Create(Application.MainForm); Parent := Application.MainForm; HandleNeeded; CreateParentedControl(Application.MainFormHandle); Connections := TList.Create; Startup; end; destructor TServer.Destroy; var Res: Integer; begin if Assigned(Connections) then begin closesocket(vServerSocket); ClearConnections; Cleaned; Connections.Free; Connections := nil; end; DestroyHandle; inherited; end; function TServer.GetConnectionBySocket(S: TSocket): PConnection; var I: Integer; begin for I := 0 to Connections.Count - 1 do if PConnection(Connections[I]).ClientSocket = S then begin Result := Connections[I]; Exit; end; Result := nil; end; function TServer.Cleaned: Boolean; begin Result := False; if WSACleanup = SOCKET_ERROR then //Говорим что сокеты больше не будут использоваться begin Err_(WSAGetLastError); Exit; end; Logging('Сервер остановлен'); Result := True; end; procedure TServer.Startup; var Res: Integer; begin Res := WSAStartup($101, vWSAData); //Разрешаем использ. сокетов if Res <> 0 then //если ошибка передадим её в обработку ошибок Err_(Res); end; function TServer.Start_Server(Port: Word): Boolean; begin Result := False; FPort := 0; // Формируем адрес для привязки. FillChar(vServerAddr.sin_zero, SizeOf(vServerAddr.sin_zero), 0); vServerAddr.sin_family := AF_INET; vServerAddr.sin_addr.S_addr := INADDR_ANY; try vServerAddr.sin_port := htons(Port); if vServerAddr.sin_port = 0 then begin Logging('Номер порта должен лежать в диапазоне 1-65535'); //MessageDlg('Номер порта должен лежать в диапазоне 1-65535', mtError, [mbOK], 0); Exit; end; // Создание сокета vServerSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if vServerSocket = INVALID_SOCKET then begin Err_(WSAGetLastError); //MessageDlg(''#13#10 +InttoStr(WSAGetLastError), mtError, [mbOK], 0); Exit; end; // Привязка сокета к адресу if bind(vServerSocket, vServerAddr, SizeOf(vServerAddr)) = SOCKET_ERROR then begin Err_(WSAGetLastError); //MessageDlg('Ошибка при привязке сокета к адресу:'#13#10 + GetErrorstring, mtError, [mbOK], 0); closesocket(vServerSocket); Exit; end; // Перевод сокета в режим прослушивания if listen(vServerSocket, SOMAXCONN) = SOCKET_ERROR then begin Err_(WSAGetLastError); //MessageDlg('Ошибка при переводе сокета в режим прослушивания:'#13#10 + GetErrorstring, mtError, [mbOK], 0); closesocket(vServerSocket); Exit; end; // Связь слушающего сокета с событием FD_ACCEPT if WSAAsyncSelect(vServerSocket, Handle, WM_ACCEPTMESSAGE, FD_ACCEPT) = SOCKET_ERROR then begin Err_(WSAGetLastError); //MessageDlg('Ошибка при установке асинхронного режима слушающего сокета:'#13#10 + GetErrorstring, mtError, [mbOK], 0); closesocket(vServerSocket); Exit; end; // Перевод элементов управления в состояние "Сервер работает" Logging('Сервер работает'); FPort := Port; Result := True; except on EConvertError do // Это исключение может возникнуть только в одном месте - // при вызове StrToInt(EditPortNumber.Text) begin Logging('"' + InttoStr(Port) + '" не является целым числом'); //MessageDlg('"' + InttoStr(Port) + '" не является целым числом', mtError, [mbOK], 0); end; on ERangeError do begin // Это исключение может возникнуть только в одном месте - // при присваивании значения номеру порта Logging('Номер порта должен лежать в диапазоне 1-65535'); MessageDlg('Номер порта должен лежать в диапазоне 1-65535', mtError, [mbOK], 0); end; end; end; procedure TServer.WMAcceptMessage(var Msg: TWMSocketMessage); var NewConnection: PConnection; // Сокет, который создаётся для вновь подключившегося клиента ClientSocket: TSocket; ClientAddr: TSockAddr; // Адрес подключившегося клиента AddrLen: Integer; // Длина адреса begin // Стр###мся от "тупой" ошибки if Msg.Socket <> vServerSocket then begin Logging('Внутренняя ошибка сервера - неверный серверный сокет'); Exit; end; // Обрабатываем ошибку на сокете, если она есть. if Msg.SockError <> 0 then begin Logging('Ошибка при подключении клиента. Код:' + IntToStr(Msg.SockError) + ' Сервер будет остановлен.'); ClearConnections; closesocket(vServerSocket); on StopServer; Exit; end; // Стр###мся от ещё одной "тупой" ошибки if Msg.SockEvent <> FD_ACCEPT then begin Logging('Внутренняя ошибка сервера - неверное событие на сокете'); Exit; end; AddrLen := SizeOf(TSockAddr); ClientSocket := accept(vServerSocket, @ClientAddr, @AddrLen); if ClientSocket = INVALID_SOCKET then begin // Если произошедшая ошибка - WSAEWOULDBLOCK, это просто означает, // что на данный момент подключений нет, а вообще всё в порядке, // поэтому ошибку WSAEWOULDBLOCK мы просто игнорируем. Прочие же // ошибки могут произойти только в случае серьёзных проблем, // которые требуют остановки сервера. if WSAGetLastError <> WSAEWOULDBLOCK then begin Logging('Ошибка при подключении клиента. Сервер будет остановлен'); ClearConnections; closesocket(vServerSocket); on StopServer; end; end else begin // Создаём запись для нового подключения и заполняем её New(NewConnection); NewConnection^ := TConnection.Create(Self); NewConnection.ClientSocket := ClientSocket; NewConnection.ClientAddr := format('%u.%u.%u.%u:%u', [ Ord(ClientAddr.sin_addr.S_un_b.s_b1), Ord(ClientAddr.sin_addr.S_un_b.s_b2), Ord(ClientAddr.sin_addr.S_un_b.s_b3), Ord(ClientAddr.sin_addr.S_un_b.s_b4), ntohs(ClientAddr.sin_port)]); NewConnection.Phase := tpReceiveLength; NewConnection.Offset := 0; NewConnection.BytesLeft := SizeOf(Integer); NewConnection.SendRead := False; // Связываем сообщение с новым сокетом if WSAAsyncSelect(ClientSocket, NewConnection.Handle, WM_SOCKETMESSAGE, FD_READ or FD_WRITE or FD_CLOSE) = SOCKET_ERROR then begin Logging('Ошибка при установке асинхронного режима подключившегося сокета.'); closesocket(ClientSocket); Exit; end; // Добавляем запись нового соединения в список Connections.Add(NewConnection); Logging('Зафиксировано подключение с адреса ' + NewConnection.ClientAddr); end; end; { TConnection } constructor TConnection.Create(AOwner: TServer); begin inherited Create(Application.MainForm); Parent := Application.MainForm; HandleNeeded; Owner := AOwner; end; destructor TConnection.Destroy; begin DestroyHandle; inherited; end; procedure TConnection.WMSocketMessage(var Msg: TWMSocketMessage); var Connection: PConnection; Res: Integer; // Вспомогательная процедура, освобождающая ресурсы, связанные // с клиентом и удаляющая запись подключения из списка procedure RemoveConnection; begin closesocket(Connection.ClientSocket); Owner.Connections.Remove(Connection); Connection^.Destroy; //Dispose(Connection); end; begin // Ищем соединение по сокету Connection := Owner.GetConnectionBySocket(Msg.Socket); if Connection = nil then begin Logging('Внутренняя ошибка сервера - не найдено соединение для сокета'); Exit; end; // Проверяем, были ли ошибки при взаимодействии if Msg.SockError = 10050 then begin ShowMessage('1'); Logging('Ошибка при взаимодейсвии с клиентом ' + Connection.ClientAddr + ': ' + Inttostr(Msg.SockError)); RemoveConnection; Exit; end; // Анализируем, какое событие произошло case Msg.SockEvent of FD_READ: begin // Проверяем, на каком этапе находится взаимодействие с клиентом. if Connection.Phase = tpReceiveLength then begin // Этап получения от клиента длины строки. При выполнении этого // этапа сервер получает от клиента длину строки и размещает её // в поле Connection.MsgSize. Здесь приходится учитывать, что // теоретически даже такая маленькая (4 байта) посылка может // быть разбита на несколько пакетов, поэтому за один раз этот // этап не будет завершён, и второй раз его придётся продолжать, // загружая оставшиеся байты. Connection.Offset - количество // уже прочитанных на данном этапе байт - одновременно является // смещением, начиная с которого заполняется буфер. Res := recv(Connection.ClientSocket, (PAnsiChar(@Connection.MsgSize) + Connection.Offset)^, Connection.BytesLeft, 0); if Res > 0 then begin Logging('Клиент шлет данные...'); // Если Res > 0, это означает, что получено Res байт. // Соответственно, увеличиваем на Res количество прочитанных // на данном этапе байт и на такую же величину уменьшаем // количество оставшихся. Inc(Connection.Offset, Res); Dec(Connection.BytesLeft, Res); // Если количество оставшихся байт равно нулю, можно переходить // к следующему этапу. if Connection.BytesLeft = 0 then begin // Проверяем корректность принятой длины строки if Connection.MsgSize <= 0 then begin Logging('Неверная длина строки от клиента ' + Connection.ClientAddr + ': ' + IntToStr(Connection.MsgSize)); RemoveConnection; Exit; end; // Следующий этап - это чтение самой строки Connection.Phase := tpReceivestring; // Пока на этом этапе не прочитано ни одного байта Connection.Offset := 0; // Осталось прочитать Connection.MsgSize байт Connection.BytesLeft := Connection.MsgSize; // Сразу выделяем память под строку SetLength(Connection.Msg, Connection.MsgSize); end; end else if Res = 0 then begin logging('Клиент ' + Connection.ClientAddr + ' закрыл соединение'); RemoveConnection; Exit; end else // Ошибку WSAEWOULDBLOCK игнорируем, т.к. она говорит // только о том, что входной буфер сокета пуст, но в целом // всё в порядке - такое вполне возможно при ложных // срабатываниях сообщения if WSAGetLastError <> WSAEWOULDBLOCK then begin logging('Ошибка при получении данных от клиента ' + Connection.ClientAddr + ': ' + GetErrorstring); RemoveConnection; Exit; end; end else if Connection.Phase = tpReceivestring then begin // Следующий этап - чтение строки. Он практически не отличается // по реализации от этапа чтения длины строки, за исключением // того, что теперь буфером, куда помещаются полученные от клиента // данные, служит не Connection.MsgSize, а Connection.Msg. Res := recv(Connection.ClientSocket, Connection.Msg[Connection.Offset + 1], Connection.BytesLeft, 0); if Res > 0 then begin Inc(Connection.Offset, Res); Dec(Connection.BytesLeft, Res); // Если количество оставшихся байт равно нулю, можно переходить // к следующему этапу. if Connection.BytesLeft = 0 then begin Logging('От клиента ' + Connection.ClientAddr + ' получена строка: ' + Connection.Msg); // Преобразуем строку. В отличие от предыдущих примеров, здесь // мы явно добавляем к строке #0. Это связано с тем, что при // отправке, которая тоже может быть выполнена не за один раз, // мы указываем индекс того символа строки, начиная с которого // нужно отправлять данные. И (хотя теоретически вероятность // этого очень мала) может возникнуть ситуация, когда за // один раз будут отправлены все символы строки, кроме // завершающего #0, и тогда при следующей отправке начинать // придётся с него. Если мы будем использовать тот #0, который // добавляется к концу строки автоматически, то в этом случае // индекс выйдет за пределы диапазона. Поэтому мы вручную // добавляем ещё один #0 к строке, чтобы он стал законной // её частью. Connection.Msg := AnsiUpperCase(stringReplace(Connection.Msg, #0, '#0', [rfReplaceAll])) + ' (AsyncSelect server)'#0; // Следующий этап - отправка строки клиенту Connection.Phase := tpSendstring; // Отправлено на этом этапе 0 байт Connection.Offset := 0; // Осталось отправить Length(Connection.Msg) байт. // Единицу к длине строки, в отличие от предыдущих примеров, // не добавляем, т.к. там эта единица нужна была для того, // чтобы учесть добавляемый к строке автоматически символ #0. // Здесь мы ещё один #0 добавили к строке явно, поэтому // он уже учтён в функции Length. Connection.BytesLeft := Length(Connection.Msg); // Ставим в очередь сообщение с событием FW_WRITE. // Его получение заставит сервер отправить данные PostMessage(Handle, WM_SOCKETMESSAGE, Msg.Socket, FD_WRITE); end; end else if Res = 0 then begin Logging('Клиент ' + Connection.ClientAddr + ' закрыл соединение'); RemoveConnection; Exit; end else // Как обычно, "ошибку" WSAEWOULDBLOCK просто игнорируем if WSAGetLastError <> WSAEWOULDBLOCK then begin Logging('Ошибка при получении данных от клиента ' + Connection.ClientAddr + ': ' + GetErrorstring); RemoveConnection; Exit; end; end else if Connection.Phase = tpSendstring then // Если сервер находится на этапе отправки данных, // а событие FD_READ всё же произошло, отмечаем это Connection.SendRead := True; end; FD_WRITE: begin if Connection.Phase = tpSendstring then begin // При наступлении события FD_WRITE проверяем, находится ли // сервер на этапе отправки данных, и если да, отправляем их Res := send(Connection.ClientSocket, Connection.Msg[Connection.Offset + 1], Connection.BytesLeft, 0); if Res > 0 then begin Inc(Connection.Offset, Res); Dec(Connection.BytesLeft, Res); // Если Connections.BytesLeft = 0, значит, строка отправлена // полностью. if Connection.BytesLeft = 0 then begin Logging('Клиенту ' + Connection.ClientAddr + ' отправлена строка: ' + Connection.Msg); // Очищаем строку просто чтобы сэкономить память Connection.Msg := ''; // Следующий этап - снова получение длины строки от клиента Connection.Phase := tpReceiveLength; // Получено - 0 байт Connection.Offset := 0; // Осталось прочитать столько, сколько занимает целое число Connection.BytesLeft := SizeOf(Integer); // Если были промежуточные события FD_READ, вызываем их // снова искусственно if Connection.SendRead then begin PostMessage(Handle, WM_SOCKETMESSAGE, Msg.Socket, FD_READ); Connection.SendRead := False; end; end; end else if WSAGetLastError <> WSAEWOULDBLOCK then begin Logging('Ошибка при отправке данных клиенту ' + Connection.ClientAddr + ': ' + GetErrorstring); RemoveConnection; Exit; end; end; end; FD_CLOSE: begin // Клиент вызвал функцию shutdown. Закрываем соединение. Logging('Клиент ' + Connection.ClientAddr + ' закрыл соединение'); shutdown(Connection.ClientSocket, SD_BOTH); RemoveConnection; end; else begin Logging('Неверное событие при обмене с клиентом ' + Connection.ClientAddr); RemoveConnection; end; end; end; end. Это сообщение отредактировал(а) Antony41 - 18.4.2013, 17:12 |
|||
|
||||
| Чучмек |
|
|||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
Antony41, это однопоточный. Задержка в обработке одного соединения приведет к временной блокировке всех остальных.
Сколько??? -------------------- умную мысль держи при себе, а дурной - поделись с другими |
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
думаю одновременно 3-4 подключения (пока) обработка данных будет занимать минимум времени, короче клиент выполняет свою задачу локально, а подключается к серверу "лицензий" для того чтобы посмотреть в каком состоянии его лицензия
по сути сервер будет отсылать всего один пакет, который скажет что всё ОК или нет. |
|||
|
||||
| Чучмек |
|
|||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
Я в какой то момент подумал, что счет пойдет на тысячи постоянных соединений. Создавать отдельное окно на каждое соединение? Все можно обработать одним. -------------------- умную мысль держи при себе, а дурной - поделись с другими |
|||
|
||||
| Antony41 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 27.12.2008 Репутация: нет Всего: 1 |
ок с этим разобрались код который выше я привел, впринципе работает нормально, но там происходит при нескольких подключениях OutOfMemory, немогу отловить... еще выдается исключение InvalidPointer при уничтожении подкласса Connection точнее тут
тоже не могу понять, если убрать Connection^.Destroy; то всё ОК, остается только OutOfMemory Добавлено через 24 секунды помогите найти пож. время поджимает |
|||
|
||||
| Чучмек |
|
||||
|
НЭТ БИЛЭТ ![]() ![]() Профиль Группа: Участник Сообщений: 841 Регистрация: 11.5.2008 Где: СССР Репутация: 4 Всего: 41 |
Ищи где утечка памяти. Где память выделяется но не освобождается, объект создается но не уничтожается.
Какой длинны передаешь строки?
Это лишнее. Объект и так указатель. Достаточно
Это сообщение отредактировал(а) Чучмек - 19.4.2013, 15:41 -------------------- умную мысль держи при себе, а дурной - поделись с другими |
||||
|
|||||
![]()
|
| Правила форума "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. |