Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 17.12.2012, 04:02   #1
Rin
Негодник
Форумчанин
 
Аватар для Rin
 
Регистрация: 10.11.2009
Сообщений: 880
По умолчанию Клиент-серверный чат на неблокируемых сокетах (winsock 1)

Здравствуйте, Форумчане! Прошу помощи. Не могу вкурить я в winsock никак. Общарил интернет, читал статьи, но до конца так и не понял. Нужно было создать чат. Клиент посылает, сервер принимает и выводит. Но при отправке почему-то приложение-клиент подвисает, а функция recv в приложении-сервере возвращает "-1".
Не пойму в чем дело.
Вот коТ сервера:
PHP код:
type
  TMyThread 
= class(TThread)
  private
    { Private 
declarations }
  protected
  
procedure Executeoverride;   
  
end;
......
TForm1 = class(TForm)
    
Memo1TMemo;
    
Listen1TButton;
    
Stop1TButton;
    
Timer1TTimer;
    
procedure Listen1Click(SenderTObject);
    
procedure Stop1Click(SenderTObject);
    
procedure FormCreate(SenderTObject);
...
var 
Sockets:array of TSocket;
    
Addr:TSockAddr;
    
Data:TWSAData;
    
I,J:Integer;
    
FDSet:TFDSet;
    
sizee:integer;
    
buf: array of char;
    
TimeoutTTimeVal;
    
My_threadTMyThread;
    
my_lock:u_long=0;
    
my_unlock:u_long=1;
   
vbuf string;
   
vsize integer=50;
...
procedure TMyThread.Execute;
begin
    select
(0,@FDSet,nil,nil,@TimeOut);
    if 
FDSet.fd_count>0 then
    
for := 0 to FDSet.fd_Count do
     
begin
     inc
(i);
     
setlength(sockets,i+1);
     
sockets[i]:=FDSet.fd_array[j];
     
setlength(buf,vsize);
     
sizee := recv(sockets[i],buf[0],vsize,0);
     
form1.caption:=inttostr(sizee);
     
setlength(vbuf,vsize);
     
lstrcpyn(@vbuf[1],@abuf[0],vsize);
     
Form1.Memo1.Lines.Add(vbuf);
     
setlength(abuf,0);
     
end;
end;

procedure TForm1.Listen1Click(SenderTObject);
begin
  WSAStartup
($101,Data);
  
SetLength(Sockets,i+1);
  
Sockets[i]:=Socket(AF_Inet,Sock_Stream,0);
  if 
sockets[i]=invalid_socket then exit;

  
ioctlsocket(sockets[0],
  
fionbio,
  
my_unlock);

  
Addr.sin_family:=AF_Inet;
  
Addr.sin_port:=HToNS(25);
  
Addr.sin_addr.S_addr:=InAddr_Any;
  
FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
 If 
Bind(Sockets[i],Addr,SizeOf(TSockAddr))<>0 then exit;

  
Listen(Sockets[i],SoMaxConn);
  
Listen1.Enabled:=False;
  
Stop1.Enabled:=True;

  
fd_zero(FDSet);

  For 
j:=High(Socketsdownto 0 do
  
begin
    fd_set
(sockets[j],FDSet);
  
end;

     
My_Thread:=TMyThread.Create(true);
   
with My_Thread do
   
Begin
    Priority 
:= tpLower;
    
Resume;
   
end;
end;

procedure TForm1.Stop1Click(SenderTObject);
begin
  
For I:=High(Socketsdownto 0 do
  
begin
    ioctlsocket
(sockets[i],fionbio,my_lock);
    
// Связь разорвана, надо закрыть сокет
     
CloseSocket(Sockets[I]);
  
end;
//Сначала остановим поток.
  
My_Thread.suspend;

  
Stop1.Enabled:=False;
  
Listen1.Enabled:=True;
end;

procedure TForm1.FormCreate(SenderTObject);
begin
I
:=0;
TimeOut.tv_sec:=5;
TimeOut.tv_usec:=0;

end
Вот коТ клиента:
PHP код:
  TForm1 = class(TForm)
    
Button1TButton;
    
Memo1TMemo;
....
const 
maxdata=50;
 
type mytype= array [1..maxdataof char;
 var
   
connboolean;
   
S:TSocket;
   
Addr:TSockAddr;
   
Data:TWSAData;
   
i,j,Was_send:integer;
   
bufMytype;
   
Otpravka:String;
....
procedure TForm1.Button1Click(SenderTObject);
 
begin
 
if not conn  then
 begin
    WSAStartup
($101,Data);
    
S:=Socket(AF_Inet,Sock_Stream,0);
    
Addr.sin_family:=AF_Inet;
    
Addr.sin_port:=HToNS(25);
    
Addr.sin_addr.S_addr:=Inet_Addr('127.0.0.1');
    
FillChar(Addr.Sin_Zero,SizeOf(Addr.Sin_Zero),0);
    If 
Connect(S,Addr,SizeOf(TSockAddr))=0 then
    begin
      conn
:=true;
      
Memo1.lines.Add('Connect ok');
    
end
  end
  
else
  
begin
     otpravka
:=TimeToStr(Now);
     for 
J:=1 to Length(otpravka) do
      
buf[j]:=otpravka[j];
      
Was_send:=send(S,buf,sizeof(buf),0);
      
memo1.Lines.Add(IntToStr(was_send)+' bytes was sent');

      if 
Recv(S,buf,Sizeof(buf),0)<=0 then
      Begin
         showMessage
('');
            
// ничего не получено сервер "упал"
         
CloseSocket(S);
         
conn:=false;
      
End
      
else // что-то вернулось
         
memo1.Lines.Add('answered: '+buf);
      for 
i:=1 to maxdata do
       
buf[i]:=' ';

  
end;
end
У всех мимопроходящих прошу прощения за отнятое время.
Заранее благодарен за помощь всем, кто откликнется.
Если помог, проси поставить минус. Будь оригинален!

Последний раз редактировалось Rin; 17.12.2012 в 04:18. Причина: В 4 утра, не спав сутки, становишься бескулюторным. Исправил сие недоразумение.
Rin вне форума Ответить с цитированием
Старый 17.12.2012, 07:26   #2
Кольша
Далеко не
Участник клуба
 
Аватар для Кольша
 
Регистрация: 11.08.2011
Сообщений: 1,512
По умолчанию

Код:
showmessage(booltostr(true));
Не?
Кольша вне форума Ответить с цитированием
Старый 17.12.2012, 10:41   #3
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

1. Клиент у тебя в блокирующем режиме, он по дефолту, а иначе ты не указал
2. У тебя сервер ничего не отправляет (нету Send), вот клиент и подвисает (т.к. в блокирующем режиме) на if Recv(S,buf,Sizeof(buf),0)<=0 then
сервер -котгавно... клиент на тройку
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 17.12.2012, 12:25   #4
Rin
Негодник
Форумчанин
 
Аватар для Rin
 
Регистрация: 10.11.2009
Сообщений: 880
По умолчанию

А зачем серверу что-то отправлять, если он просто ждет данных клиентов? Брал пример из Delphi Russian Knowledge Base 3, пример был для консольки, но работал!
То, что мои коты-выкидыши попахивают, знаю. Первый блин всегда комом. Но мне кажется, что не из-за этого виснет, т.к. в примере из Delphi Russian Knowledge Base 3 нет никаких send на сервере, есть только recv.

Код:
showmessage(booltostr(true));
Как я сразу не догадался, но думаю, красивее будет MessageBox, ага.
Если помог, проси поставить минус. Будь оригинален!

Последний раз редактировалось Rin; 17.12.2012 в 12:34.
Rin вне форума Ответить с цитированием
Старый 17.12.2012, 12:45   #5
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

если сервер ничего не отправляет зачем клиенту Recv?
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 17.12.2012, 12:51   #6
Rin
Негодник
Форумчанин
 
Аватар для Rin
 
Регистрация: 10.11.2009
Сообщений: 880
По умолчанию

Спасибо, Slym. Вот моя невнимательность и невыспанность. Перестало виснуть. Но все равно recv на сервере возвращает -1 (Socket_error).

Update
Есть предположение, что блкирующий и неблокирующий сокеты не взаимодействуют друг с другом. Но в клиенте при переводе сокета в неблокирующий режим при коннекте возникает ошибка 10035 (WSAEWOULDBLOCK).
Если помог, проси поставить минус. Будь оригинален!

Последний раз редактировалось Rin; 17.12.2012 в 14:10.
Rin вне форума Ответить с цитированием
Старый 17.12.2012, 14:40   #7
Rin
Негодник
Форумчанин
 
Аватар для Rin
 
Регистрация: 10.11.2009
Сообщений: 880
По умолчанию

Все, разобрался, не хватало функции Accept для создания обслуживающего соединение сокета. Теперь все передает. Slym, благодарю за наводку по recv в клиенте.
Если помог, проси поставить минус. Будь оригинален!
Rin вне форума Ответить с цитированием
Старый 17.12.2012, 17:29   #8
xoodoo
Форумчанин
 
Регистрация: 11.04.2012
Сообщений: 212
По умолчанию

Цитата:
блкирующий и неблокирующий сокеты не взаимодействуют друг с другом
Никогда и ни при каких условиях.
Взаимодействующие стороны ничего не знают, знать не могут и знать не обязаны о режиме работы сокетов друг у друга.
xoodoo вне форума Ответить с цитированием
Старый 17.12.2012, 17:44   #9
Rin
Негодник
Форумчанин
 
Аватар для Rin
 
Регистрация: 10.11.2009
Сообщений: 880
По умолчанию

Это я уже понял. Но возникла другая проблема. Соединение рушится после того как произошла отсылка данных от клиента и принятие данных сервером. Почему это может быть?
Если помог, проси поставить минус. Будь оригинален!
Rin вне форума Ответить с цитированием
Старый 17.12.2012, 17:50   #10
xoodoo
Форумчанин
 
Регистрация: 11.04.2012
Сообщений: 212
По умолчанию

Оно "рушится" потому что одна из сторон по собственной инициативе его "рушит"
xoodoo вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Telnet клиент на сокетах an1s1 Общие вопросы .NET 1 19.07.2012 17:38
Статья: Низкоуровневое сетевое программирование. Пишем клиент/серверное приложение на сокетах Беркли oleg kutkov C/C++ Сетевое программирование 42 22.01.2011 00:35
Чат на сокетах yandzee Общие вопросы C/C++ 6 11.12.2010 14:50
Простейшие клиент-сервер на сокетах: почему ошибка 10060 kolchakA Общие вопросы C/C++ 7 01.12.2009 08:14