![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как правильно послать файл через TcpServer & TcpClient ? [D7, WinXP]
Andrewtitoff © (2008-01-18 10:57:00)Пытаюсь послать файл, файл посылается, но прога все время вываливается с ошибками:
Access violation, Canvas does not allow drawing... =(((
И как при приеме узнать размер пересылаемого файла что бы засунуть его в ReceiveBuf.., SizeOf(Buf) возвращает все время 4 ... =(((
Вот текст моей программы:
================================================
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Sockets, StdCtrls;
type
TMyChat = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
RemoteHost: TEdit;
RemotePort: TEdit;
LocalPort: TEdit;
Display: TMemo;
Edit: TEdit;
Connect: TButton;
TcpServer1: TTcpServer;
TcpClient1: TTcpClient;
SendFile: TButton;
procedure TcpServer1Accept(Sender: TObject; ClientSocket: TCustomIpClient);
procedure SendClick(Sender: TObject);
procedure ConnectClick(Sender: TObject);
procedure SendFileClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MyChat: TMyChat;
implementation
{$R *.dfm}
procedure TMyChat.ConnectClick(Sender: TObject);
begin
TcpServer1.LocalPort := LocalPort.Text;
TcpServer1.Active := True;
TcpClient1.RemotePort := RemotePort.Text;;
TcpClient1.RemoteHost := RemoteHost.Text;;
TcpClient1.Active := True;
end;
procedure TMyChat.FormClose(Sender: TObject; var Action: TCloseAction);
begin
TcpServer1.Active := False;
TcpClient1.Active:= False;
TcpClient1.Disconnect;
end;
procedure TMyChat.SendFileClick(Sender: TObject);
var
asd:Tmemorystream;
begin
asd := TMemoryStream.Create;
asd.Position:=0;
asd.LoadFromFile('c:\1.txt');
asd.Position:=0;
TcpClient1.Active := True;
try
if TcpClient1.Connect then
begin
TcpClient1.SendStream(asd);
end;
finally
TcpClient1.Disconnect;
end;
asd.free;
end;
procedure TMyChat.TcpServer1Accept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
s:string;
asd:tmemorystream;
len:integer;
buf:pointer;
begin
asd:=TMemoryStream.Create;
asd.Position:=0;
len:= ClientSocket.ReceiveBuf(buf,192,0);
asd.WriteBuffer(buf,len);
asd.SaveToFile('c:\000.txt');
asd.Free;
FreeMem(Buf);
clientsocket.Close;
ShowMessage('clientsocket.Close');
end;
end.
================================================
Andrewtitoff (2008-01-21 15:33:00) [21]Ну вот вроде как заработало, тока чет я переменных по моему лишку напихал.... =)))
procedure TMyChat.TcpServer1Accept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
asd:tmemorystream;
len:integer;
LenRes1:integer;
LenRes2:integer;
buf:pointer;
begin
len:=68096;
LenRes1:=Len;
LenRes2:=0;
asd:=TMemoryStream.Create;
GetMem(buf,len);
asd.Position:=0;
Repeat
LenRes1:=ClientSocket.ReceiveBuf(buf^,lenRes1);
asd.WriteBuffer(buf^,lenRes1);
LenRes2:=LenRes2+LenRes1;
if LenRes1 <> len then lenRes1 := len-LenRes2;
Until LenRes2 = len;
asd.SaveToFile('c:\000.doc');
asd.Free;
FreeMem(Buf);
end;
Сергей М. (2008-01-21 15:15:00) [22]Да.
Andrewtitoff (2008-01-21 15:05:00) [23]>Повторно вызывать ReceiveBuf, запрашивая оставшиеся данные.
Так это что ли вычитать из размера файла то что передалось и вызывать ReceiveBuf уже с Buf = FileSize - ReceiveSize ?
Сергей М. (2008-01-21 14:31:00) [24]
> что делать ели размер несовпал?
Повторно вызывать ReceiveBuf, запрашивая оставшиеся данные.
> надо писать Application
Не надо.
> с MessageBox виснет
Отладчик тебе в руки
Andrewtitoff (2008-01-21 14:25:00) [25]Не.., с MessageBox виснет так же как и с ShowMessage... =((((
Andrewtitoff (2008-01-21 14:20:00) [26]Ой, эт я опять туплю... =)))
Просто надо писать Application.MessageBox(Text, Caption: PChar; Flags: Longint): Integer;
Andrewtitoff (2008-01-21 14:12:00) [27]Ясно, так а что делать ели размер несовпал?
Во блин приехали....
Всю жизнь было так:
function MessageBox(Text, Caption: PChar; Flags: Longint): Integer;
а теперь:
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)Странно как то... =((((
Сергей М. (2008-01-21 14:10:00) [28]
> Ошибка размера
Ошибкой может считаться только LenRes = -1.
Если LenRes = 0, это означает что партнер закрыл соединение по своей иниативе, считать это ошибкой нельзя.
Если 0 < LenRes <= Len, то это не ошибка, а вполне штатная ситуация.
Сергей М. (2008-01-21 14:00:00) [29]
> чем можно тогда выводить сообщения?
Не надо их ничем выводить.
Для пошагового контроля за ходом выполнения программы в Делфи существует встроенный отладчик. Только не говори, что первый раз про него слышишь.
А если все же приспичило выводить, пользуй MessageBox
Сергей М. (2008-01-21 13:58:00) [30]Ты по-русски читать умеешь ?
Сказано же - убирай к чертовой бабушке все свои ShowMessage !)
Нельзя в доп.потоке обращаться визуальным VCL-контролам !
Andrewtitoff (2008-01-21 13:55:00) [31]Опять ShowMessage?, а почему, при чем тут оно?, и чем можно тогда выводить сообщения?
Andrewtitoff (2008-01-21 13:53:00) [32]А точно, гдето я не там высмотрел, все верно integer... =)))
>А дело в том, что результат выполнения ReceiveBuf вовсе не обязан быть равным значению Len - он может быть и меньшим чем Len, вплоть до 0 или -1. Ты этот факт в своем коде никак не учитываешь, потому и грабли тебе обеспечены. Я же сказал тебе - анализируй результат !
Вот блин я написал
var
asd:tmemorystream;
len:integer;
LenRes:integer;
buf:pointer;
begin
len:=68096;
asd:=TMemoryStream.Create;
GetMem(buf,len);
LenRes:=ClientSocket.ReceiveBuf(buf^,len);
asd.Position:=0;
asd.WriteBuffer(buf^,len);
if LenRes <> len then
ShowMessage('Ошибка размера : '+Inttostr(LenRes))
else
begin
asd.SaveToFile('c:\000.doc');
ShowMessage('Файл принят')
end;
asd.Free;
FreeMem(Buf);
end;
Теперь прога виснет и неодного мессаджа не показывает... =((((
Сергей М. (2008-01-21 13:14:00) [33]
> Canvas does not allow drawing
Убирай ShowMessage.
Сергей М. (2008-01-21 13:12:00) [34]
> Len в ReceiveBuf(buf^,len,0); имеет тип word
Ничего подобного.
В твоей декларации он integer и в прототипе oн тоже integer, так что верхний предел 2гб.
Да и не в этом дело.
А дело в том, что результат выполнения ReceiveBuf вовсе не обязан быть равным значению Len - он может быть и меньшим чем Len, вплоть до 0 или -1. Ты этот факт в своем коде никак не учитываешь, потому и грабли тебе обеспечены. Я же сказал тебе - анализируй результат !
Andrewtitoff (2008-01-21 12:40:00) [35]>Теперь разнеси своего клиента и сервера по разным углам Тырнета и попытайся передать файл размером более 8 кб
Вот блин точно..., Len в ReceiveBuf(buf^,len,0); имеет тип word, а он равен 2 байтам т.е. от 0 до 65535... =((( , а что что бы послать файл побольше его нужно разбивать, или есть какой нить способ?
>Или попытайся обслужить более чем одного клиента одновременно
А как сделать то??, хотя для задачи которая на данный момент передомной стоит мне вполне хватит две пары клиент-сервер, но все таки хотелось бы знать и как сделать с несколькими клиентами... =(((
Сергей М. (2008-01-21 11:50:00) [36]
> Кстати вот так заработало
Теперь разнеси своего клиента и сервера по разным углам Тырнета и попытайся передать файл размером более 8 кб. Или попытайся обслужить более чем одного клиента одновременно. Грабли тебе гарантированы.
> у меня во первых с английским не очень
Печально. Ничего путного у тебя не получится, пока не выучишь.
> все что есть в справке
Это говорит как раз о том, что Борланд прекратил поддержку этих компонентов.
Продолжай зарабатывать себе геморрой.
Andrewtitoff (2008-01-21 11:41:00) [37]Кстати вот так заработало...:
procedure TMyChat.TcpServer1Accept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
s:string;
asd:tmemorystream;
len:word;
buf:pointer;
begin
len:=192;
asd:=TMemoryStream.Create;
GetMem(buf,len);
ClientSocket.ReceiveBuf(buf^,len,0);
asd.Position:=0;
asd.WriteBuffer(buf^,len);
asd.SaveToFile('c:\000.txt');
asd.Free;
FreeMem(Buf);
TcpServer1.Close;
end;
Andrewtitoff (2008-01-21 11:37:00) [38]Нет, с Receiveln, SendLn я вроде разобрался, покрайне мере пример чата из 7-ых дельфей переделанный мною под TcpServer и TcpClient нормально работает.., буду пересылать размер...
>Справку к этому методу ты проштудировал ? Что тебе там непонятно ?
Так а где ее взять то?, у меня во первых с английским не очень, а во вторых все что есть в справке:
Delphi 2007 VCL Win32 Reference
TCustomWinSocket.ReceiveBuf Method
TCustomWinSocket Class | TCustomWinSocket Members | ScktComp Namespace | Description | See Also
Collapse AllReads up to Count bytes from the socket connection into the Buf parameter.
Pascal
function ReceiveBuf(var Buf; Count: Integer): Integer;
Description
Use ReceiveBuf to read from the socket connection in the OnSocketEvent event handler of a Windows socket object or in the OnRead or OnClientRead event handler of a socket component. ReceiveBuf returns the number of bytes actually read. If no bytes are read, ReceiveBuf returns –1.
ReceiveBuf only works in response to a read notification to a non-blocking windows socket. Blocking sockets must use a TWinSocketStream for reading. The TWinSocketStream object waits for the remote socket to be ready before transferring information.
Note: While the ReceiveLength method can return an estimate of the size of buffer required to retrieve information from the socket, the number of bytes it returns is not necessarily accurate.
Сергей М. (2008-01-21 11:34:00) [39]У и зачем использовать компоненты, для которых отсутствует справка ?
Не ты ли тут трындел про поддержку компонентов в последующих версиях ?
Отсутствие (частичное или полное) справки к этим компонентам в D2007 должно навести на мысль, что поддержка в будущем этих компонентов под большим вопросом.
Сергей М. (2008-01-21 11:25:00) [40]
> 192 - это просто размер пересылаемого мною файла.
А если файл будет другого размера ? Что, править и перекомпилировать проект будешь ?
> можно поподробнее про анализ результата вызова ReceiveBuf
Справку к этому методу ты проштудировал ? Что тебе там непонятно ?