Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Непонятки с winSock


Автор: Castiel 21.1.2009, 11:08
Посмотрите в чем может быть проблема? По нажатию кнопки Button1 создается сокет, потом настраиваю адрес и пытаюсь провести коннект. Коннекта нет.... Хотя сервер на другой стороне ждет и слушает порт, всё нормуль. Для проверки добавил в каждую строчку GetLastError. Первые два раза выдает "0", а потом "5". Что за ошибка №5 и воообще откуда она может взяться???? Кстати, если вместо connect сделать bind, listen и поменять порт, то всё ок и приложение вешается слушать порт. Что за фигня??


Код


unit ClientMain; 
 
interface 
 
uses Windows, Classes, Graphics, Forms, Controls, Menus, 
  Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ImgList, StdActns, 
  ActnList, ToolWin, WinSock, MySocket, SysUtils; 
 
type 
    TMainForm = class(TForm) 
    DataMemo: TMemo; 
    SendButton: TButton; 
    SendMessage: TEdit; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
  end; 
 
var 
  MainForm: TMainForm; 
 
 
  Sock:TSocket; 
  Addr:TSockAddr; 
  Data:TWSAData; 
  Cnt,Flags:Cardinal; 
 
 
implementation 
 
uses about; 
 
{$R *.dfm} 
 
 
procedure TMainForm.Button1Click(Sender: TObject); 
begin 
 
  WSAStartup($0101,Data); 
  MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  Sock:=Socket(AF_Inet,Sock_Stream,0); 
    MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  Addr.sin_family:=AF_Inet; 
    MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  Addr.sin_port:=HToNS(3031); 
    MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  Addr.sin_addr.S_addr:=Inet_Addr('127.0.0.1'); 
    MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0); 
    MainForm.DataMemo.Lines.Add(InttoStr(GetLastError)); 
  if Connect(Sock,Addr,SizeOf(Addr))= 0 then  
MainForm.DataMemo.Lines.Add('Соединение успешно установлено!!!') 
 
  else MainForm.DataMemo.Lines.Add('Соединение установить не удалось (('); 
    MainForm.DataMemo.Lines.Add(InttoStr(WSAGetLastError)); 
  // 
 
end; 
 
end.


Автор: mrbrooks 21.1.2009, 11:23
Однозначно что то мутишь со структурой TSockAddr. 
Код

FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
Addr.sin_family:=AF_Inet; 
Addr.sin_port:=HToNS(3031); 
Addr.sin_addr.S_addr:=Inet_Addr(PChar('127.0.0.1')); 


Автор: Castiel 21.1.2009, 20:05
блииииин, не работает всё равно.... вооьще не могу понять в чем дело.... самое  главное что когда-то за 2 минуты написал работающего клиента, примерно такого же, исходники не сохранились, а вот экзешник есть и он коннектится отлично.... То есть сервер в порядке, а вот этот код не пашет. Причем пробовал собирать проекты-примеры, которые выложены на этом форуме. И везде одно и то же.... не пашет как и мой код.... даже не знаю где копать....

Автор: Virtuals 22.1.2009, 06:27
Castiel, а что ты пакеты сам формируеш? smile  и причем сдесь порт? в IP то протоколе тоsmile 
Код

Sock:=Socket(AF_Inet,Sock_Stream,0)
что есть
  IPPROTO_IP     =   0;             { dummy for IP }!!!


Код

 WSAStartup($0101, wData);
 sock := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if sock = INVALID_SOCKET then ...;
 addr.sin_family := AF_INET;
 addr.sin_port   := htons(80);
 addr.sin_addr   := LookupName(Server);;
 error := connect(sock, addr, sizeof(addr));
 if error = SOCKET_ERROR then ...;

так легче?

Автор: Virtuals 22.1.2009, 08:50
Цитата(Castiel @  21.1.2009,  11:08 Найти цитируемый пост)
Что за ошибка №5 и воообще откуда она может взяться????

на будущее
Код

Memo1.Lines.Add( SysErrorMessage(GetLastError));

думаю так удобней будет. smile 

Автор: Castiel 25.1.2009, 22:39
Советы- замечания учел, спасибо smile)) теперь другая проблема - где-то накосячил с буферами.... и отправляется вроде гладко, и сообщение приходит, но оно длины 0.... Я выложу исходники клиента и сервера, укажите плиз где ошибка

Автор: Virtuals 26.1.2009, 09:03
Castiel, 
Цитата


procedure TReadThread.Execute;
begin
  FreeOnTerminate := True;

  while not Terminated do
  begin
 //       ShowMessage(SysErrorMessage(GetLastError));
      Recv(FReadSocket.FSocket, FBuf, SizeOf(FBuf), 0); //где обработка результата Recv? там размер принятых данных
        ShowMessage(SysErrorMessage(GetLastError)); //ну это вообще нонсенс из потока вызывать ShowMessage
      Synchronize(DoRead);
  end; {while}
end;

procedure TReadThread.DoRead;
var
  arrBytes: array of Byte;
  i: Integer;
begin
if Assigned(FReadSocket.FReadEvent) then //зачем это сдесь?
  begin
    for i := Low(FBuf) to FRead - 1 do // а чему равен FRead? может хотел выше FRead:=Recv(... if FRead>0 then Synchronize ^)
      arrBytes[i] := FBuf[i]; // ага а память за вас кто выделять будет?

    FReadSocket.FReadEvent(Self, arrBytes); //ага передали наружу указатель на локальную переменную smile

    arrBytes := nil; //ну и забили на указатель, ничего не освободив, конечно зачем это, ведь ничего и не выделяли  smile  smile 
  end;
end;


 smile  smile  smile 
за теги не бить, нужна подсветка

Автор: Castiel 26.1.2009, 09:32
точно smile) я в шоке сам с себя.... поудалял кое-что, в том числе и FRead, а отсюда не убрал.... и выделение памяти снес случайно.... Showmessage только на время, чтобы посмотреть что действительно ошибок нет.. Но это то проблема по которой ничего не выдает в MainForm, но размер то принятого буфера ноль всё равно.... не зависимо от этих ошибок... я как раз этим ShowMessage размер принятого и проверял..

Код


if Assigned(FReadSocket.FReadEvent) then //зачем это сдесь?



как это зачем? а разве без этого вообще можно? а вдруг там пусто?


а обработка результатов Recv в DoRead....

Автор: Virtuals 26.1.2009, 09:40
Castiel, 
твой код легче переписать с нуля чем исправить, у тебя ошибок больше чем строк.
Код

procedure TMainForm.OnRead(Sender: TObject; ReadBytes: array of Byte;SizeR:LongInt);
var
  i: Integer;
begin

  MainForm.DataMemo.Lines.Add('Получили, длина :'+ IntToStr(SizeR));

if SizeR>0 then
  for i := 0 to SizeR-1 do
    MainForm.DataMemo.Text := MainForm.DataMemo.Text + IntToHex(ReadBytes[i], 2)+' ';
  MainForm.DataMemo.Lines.Add('');
  MainForm.DataMemo.Lines.Add('');
end;

procedure TReadThread.Execute;
begin
  FreeOnTerminate := True;

  while not Terminated do
  begin
      FRead:=Recv(FReadSocket.FSocket, FBuf, MAX_PACKET_SIZE, 0);
    if FRead>0 then Synchronize(DoRead);
  end; {while}
end;

procedure TReadThread.DoRead;
var
  arrBytes: array of Byte;
  i: Integer;
begin
getmem(arrBytes,FRead);
move(FBuf,arrBytes[0],FRead);
if Assigned(FReadSocket.FReadEvent) then
    FReadSocket.FReadEvent(Self, arrBytes,FRead);
freemem(arrBytes);
end;



это так чтобы показать что работает.
но!
1. у тебя поток даст 100% загрузку проца
2. память лучше выделять в основном потоке под arrBytes

Автор: Castiel 26.1.2009, 10:13
Цитата


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



ну ладно, не ругай сильно, я ещё совсем начинающий..... буду пробовать-разбираться, спасибо за советы!!!!!!!!!!!!!!!!!!!!


а почему поток даст 100% загрузку процессора? не понимаю.. и как избежать?

Автор: Virtuals 26.1.2009, 12:01
Castiel, 
Цитата(Castiel @  26.1.2009,  10:13 Найти цитируемый пост)
а почему поток даст 100% загрузку процессора? не понимаю.. и как избежать?

сдесь бесконечный цикл!
Код

  while not Terminated do
  begin
      FRead:=Recv(FReadSocket.FSocket, FBuf, MAX_PACKET_SIZE, 0);
    if FRead>0 then Synchronize(DoRead);
  end; {while}


Автор: Virtuals 26.1.2009, 12:20
Castiel, 
уф выкинь свой код, и посмотри пример в
DRKB "Создание сетевых приложений на Delphi с использованием Windows Sockets API"

Автор: Castiel 26.1.2009, 12:44
бесконечный цикл, ну да, я думал так и нужно....... ладно, полезу смотреть пример, видимо действительно проще всё с нуля переделать

Автор: Castiel 26.1.2009, 18:30
пример там конечно хороший, но я его как оказывается уже смотрел, правда в другом месте. Там всё отлично и понятно написано, за исключением нескольких "но". Во превых там прием-передача выполняются в одном потоке, а я хочу сделать прием в отдельном, а передачу в основном, и во вторых в тех примерах клиент например тупо подцепляется, что-то передает на сервер и отключается. А мне нужно принять-отправить, принять-отправить... до тех пор пока я не решу разорвать соединение.

Автор: Virtuals 26.1.2009, 18:55
Castiel, 
читай внимательней, а не через строчку. там есть и про многопоточность и про, самое главное events!!!

Автор: Virtuals 27.1.2009, 09:01
Castiel, 
а тебе точно обязательно изобретать велосипед на апи? может воспользоватся TServerSocket дельфовым в режиме stThreadBlocking?
все красиво работает, нормальный многопоточный сервер.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)