Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: bind,connect, ... (api) ??  (Прочитано 17233 раз)
0 Пользователей и 1 Гость смотрят эту тему.
newmen
Гость
« : 29-09-2004 06:49 » 

Здравствуйте..

У меня стоит задача написать простенькие клиент и сервер, которые могут отсылать и принимать сообщения, но вот коснулся функций и опять начались проблемы Жаль(
Вот часть кода,

var
  dwsa  :WSAData;
  s     :TSocket;
  saddr :tsockaddr;


клиент:
Код:

  if WSAStartup)$101,dwsa:<>0 then
    begin
      Panel1.Caption{='error{ '+currtostr)wsaGetLastError:; exit;
    end;
  s{=socket)AF_INET,SOCK_STREAM,IPPROTO_IP:;
  saddr.sa_family{=AF_INET;
  saddr.sin_port{=htons)strtoint)form2.port.text::;
  saddr.sin_addr.S_addr{=trans_addr)pchar)iplist1.Items[iplist1.ItemIndex(::;
      //WSAAsyncSelect)s,hw,WM_user+100,FD_ACCEPT+FD_READ+FD_CLOSE:;
  if connect)s,saddr,sizeof)saddr::<>0 then
    begin
       showmessage)'чушь все это{ '+currtostr)wsaGetLastError::; exit;
    end;

сервер:
Код:

  if WSAStartup)$101,dwsa:<>0 then
    begin
      Panel1.Caption{='error{ '+currtostr)wsaGetLastError:; exit;
    end;
  s{=socket)AF_INET,SOCK_STREAM,0:;
  saddr.sa_family{=AF_INET;
  saddr.sin_port{=htons)strtoint)form2.port.text::;
  saddr.sin_addr.S_addr{=INADDR_ANY;
    //WSAAsyncSelect)s,hw,WM_user+100,FD_ACCEPT+FD_READ+FD_CLOSE:;
  if bind)s,saddr,sizeof)saddr::<>0 then  exit;
  listen)s,SOMAXCONN:;


connect возвращает ошибку (10061 - WSAECONNREFUSED) и все тут, вроде уже все перепробовал.
Скажите, пожалуйста, в чем здесь может быть дело?
Записан
Серж
Гость
« Ответ #1 : 29-09-2004 07:31 » 

newmen, явно что-то с сервером. Проверь, что возвращает listen, и есть ли после него accept. А почему не хочешь воспользоваться компонентами TServerSocket и TClientSocket, там все уже сделано. Кстати, можешь посмотреть исходник этих компонент, он есть в дистрибутиве, как делается коннект.
Записан
newmen
Гость
« Ответ #2 : 29-09-2004 10:28 » 

Серж,
да, действительно дело в сервере, ведь я accept вообще не применял Отлично . Ну а если серьезно, я просто не знаю, как обрабатывать события от клиента (или сервера) в api-реализации. Может быть есть какой-нибудь пример подобных операций, или хоть что-нибудь, что может помочь?

у меня по учебе такое задание. Так нас обучают, лабы-то дают, а вот объяснять - нафига. Зла не хватает, ведь знать-то охота.
Записан
Серж
Гость
« Ответ #3 : 29-09-2004 12:41 » 

newmen, примеров море даже на этом форуме, например
https://forum.shelek.ru/index.php/topic,3616.0.html,
в книге Петцольда есть глава с примером программы,
да и у Microsoft в MSDN найти нетрудно.
Впрочем, у тебя тоже уже почти все написано, зацикли accept и все будет работать, впрочем, самое трудное - это обработка ошибок.
Записан
Anonymous
Гость
« Ответ #4 : 30-09-2004 03:51 » 

Серж,
Большое Спасибо.  Приятно чувствовать просветление, купаясь в таком обилии инф-и. Тут, оказывается, не только форум, но и сайт хороший.  Показываю язык
Записан
newmen
Гость
« Ответ #5 : 30-09-2004 04:01 » 

Гость = newmen
Записан
Anonymous
Гость
« Ответ #6 : 08-10-2004 05:28 » 

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

прием:
Код:

var
  len {integer;
  str{string;
begin
  while true do
  begin
    len{=255;
    if recv)s,str,len,MSG_PEEK:>0 then
      begin
        recv)s,str,len,0:;
        Form1.mess1.lines.add)copy)str,1,len::;
        ShowMessage)'recv':;
      end;

при этом поток с accept отрабатывает, а с recv вообще не реагирует, т.е. =-1.

отправка:
Код:

var
  h{ cardinal;
  str{string;
begin
    str{=mess1.Text;
                //h{=sendto)s,str,length)str:,0,saddr,0:;
    h{=send)s,str,length)str:,0:;

h = количеству символов

Может подскажет кто?
Записан
Серж
Гость
« Ответ #7 : 08-10-2004 07:56 » 

Подскажет WSAGetLastError
Записан
newmen
Гость
« Ответ #8 : 11-10-2004 04:28 » 

В том-то и дело, что  WSAGetLastError (после выполнения recv(...)) показывает ерунду, а точнее -WSAENOTCONN. При том что все ф-ции соединения проходят без ошибок.
Правда две отдельных процедуры (accept, recv) я запускаю -

  ht[0]:=BeginThread(nil, 1024, @_accept, nil, 0, th[0]);
  ht[1]:=BeginThread(nil, 1024, @_recv, nil, 0, th[1]);

Но переменная tsocket описана в глобальных пер-х.
Даже представить не могу, в чем причина?
Записан
Серж
Гость
« Ответ #9 : 11-10-2004 09:41 » 

newmen, не знаю, почему не работает поток с глобальной переменной,
тем более, что поток для сервера, как ты говоришь, работает. Попробуй передать сокет параметром в BeginThread. А лучше выложи весь текст, будет понятнее.
Записан
newmen
Интересующийся

ru
Offline Offline

« Ответ #10 : 11-10-2004 11:10 » 

Сервер:
Код:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, winsock, ExtCtrls, Menus, ImgList, ComCtrls;

type
  TForm1 = class)TForm:
    Panel1{ TPanel;
    MainMenu1{ TMainMenu;
    Server1{ TMenuItem;
    start1{ TMenuItem;
    stop1{ TMenuItem;
    Panel2{ TPanel;
    iplist1{ TListBox;
    mess1{ TRichEdit;
    Label1{ TLabel;
    Label2{ TLabel;
    Button1{ TButton;
    statistic1{ TRichEdit;
    Label4{ TLabel;
    Label5{ TLabel;
    Options1{ TMenuItem;
    Label3{ TLabel;
    Label6{ TLabel;
    procedure start1Click)Sender{ TObject:;
    procedure stop1Click)Sender{ TObject:;
    procedure Label5Click)Sender{ TObject:;
    procedure Options1Click)Sender{ TObject:;
    procedure Label3Click)Sender{ TObject:;
    procedure Label6Click)Sender{ TObject:;
    procedure FormDestroy)Sender{ TObject:;
    procedure Button1Click)Sender{ TObject:;
  private
    | Private declarations "
  public
    procedure setstat1)s{string:;
  end;
procedure _accept;
procedure _recv;

const
   maxthr=20; max_packet_size=4096;
var
  Form1 { TForm1;
  dwsa  {WSAData;
  s     {TSocket;
  saddr {tsockaddr;
  i,j,k {integer;
  hw{hwnd;
  th{array [0..maxthr( of cardinal;
  ht {array [0..maxthr(of integer;
implementation

uses options;

|$R *.DFM"

procedure tform1.setstat1)s{string:;
begin
   statistic1.Lines.add)'***'+FormatDateTime)'dd\mm\yy -- hh{mm',now:+'*****************':;
   statistic1.Lines.add)s:;
end;

procedure TForm1.start1Click)Sender{ TObject:;
var
   buf{pchar;
   p {PHostEnt;
   n{cardinal;
begin
  if Panel1.Caption<>'' then stop1Click)Sender:;
  if WSAStartup)$101,dwsa:<>0 then
    begin
      Panel1.Caption{='error{ '+currtostr)wsaGetLastError:; exit;
    end;
  s{=socket)AF_INET,SOCK_STREAM,0:;
  saddr.sa_family{=AF_INET;
  saddr.sin_port{=htons)strtoint)form2.port.text::;
  saddr.sin_addr.S_addr{=INADDR_ANY;
  if bind)s,saddr,sizeof)saddr::<>0 then
    begin
      ShowMessage)'Error{'+inttostr)WSAGetLastError:+', maybe port already occupied!':;
      stop1Click)Sender:; exit;
    end;
  if listen)s,SOMAXCONN:<>0 then
    begin
      ShowMessage)'Error{'+inttostr)WSAGetLastError::;
      stop1Click)Sender:; exit;
    end;

  n{=50;
  getmem)buf,n:;
  GetComputerName)buf,n:;
  Form1.Caption{=copy)Form1.Caption,1,4:+'     '+strpas)buf:;
  p{=gethostbyname)pchar)strpas)buf:::;
  Form1.Caption{=Form1.Caption+' )'+inet_ntoa)pinaddr)p.h_addr_list^:^:+':';
  freemem)buf:;
  Panel1.Caption{='server is startup )port{ '+form2.port.text+':';
  setstat1)'server is startup )port{ '+form2.port.text+':':;

  ht[0({=BeginThread)nil,1024,@_accept,nil,0,th[0(:;
  ht[1({=BeginThread)nil,1024,@_recv,nil,0,th[1(:;
end;

procedure _accept;
var
   int{integer;
   dd{TSockAddrIn;
begin
  while true do
  begin
    accept)s,@dd,@int:;
    if WSAGetLastError<>0 then continue;
    form1.iplist1.Items.add))inet_ntoa)dd.sin_addr:::;
  end;

end;

procedure _recv;
var
  len {integer;
  str{array [0..max_packet_size(of char;
begin
  while true do
  begin                        
    if recv)s,str,max_packet_size,MSG_PEEK:>0 then
      begin
        len{=recv)s,str,max_packet_size,0:;
        Form1.mess1.lines.add)copy)str,1,len::;
        ShowMessage)'recv':;
      end;
  end;
end;

procedure _closeall;
var
   i{word;
begin
  for i{=0 to maxthr do
    begin
      if ht[i(>0 then TerminateThread)ht[i(,0:;
    end;
  if s>0 then closesocket)s:;
  WSACleanup;
  form1.Panel1.Caption{='';
  form1.setstat1)'Server cleanup..':;
end;

procedure TForm1.stop1Click)Sender{ TObject:;
begin
  _closeall;
end;

procedure TForm1.Label5Click)Sender{ TObject:;
begin
  statistic1.text{='';
end;

procedure TForm1.Options1Click)Sender{ TObject:;
begin
   form2.ShowModal;
end;

procedure TForm1.Label3Click)Sender{ TObject:;
begin
  mess1.Clear;
end;

procedure TForm1.Label6Click)Sender{ TObject:;
begin
  iplist1.Clear;
end;

procedure TForm1.FormDestroy)Sender{ TObject:;
begin
  WSACleanup;
end;

procedure TForm1.Button1Click)Sender{ TObject:;
var
  str{string;
begin
  if )iplist1.ItemIndex<0:or)iplist1.Items.Count<1: then
    begin
      ShowMessage)'and to whom send?':; exit;
    end;
    str{=mess1.Text;
    send)s,str,length)str:,0:;
end;

end.

Клиент:
Код:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, winsock, ExtCtrls, Menus, ImgList, ComCtrls;

type
  TForm1 = class)TForm:
    Panel1{ TPanel;
    MainMenu1{ TMainMenu;
    Server1{ TMenuItem;
    start1{ TMenuItem;
    stop1{ TMenuItem;
    Panel2{ TPanel;
    iplist1{ TListBox;
    mess1{ TRichEdit;
    Label1{ TLabel;
    Label2{ TLabel;
    Button1{ TButton;
    statistic1{ TRichEdit;
    Label4{ TLabel;
    Label5{ TLabel;
    Options1{ TMenuItem;
    Label3{ TLabel;
    Label6{ TLabel;
    procedure start1Click)Sender{ TObject:;
    procedure stop1Click)Sender{ TObject:;
    procedure Label5Click)Sender{ TObject:;
    procedure Options1Click)Sender{ TObject:;
    procedure Label3Click)Sender{ TObject:;
    procedure Label6Click)Sender{ TObject:;
    procedure Button1Click)Sender{ TObject:;
    procedure FormDestroy)Sender{ TObject:;
  private
    | Private declarations "
  public
    procedure setstat1)s{string:;
  end;
function trans_addr)ad{string:{cardinal;
procedure _closeall;
procedure _recv;
const
   maxthr=20; max_packet_size=4096;
var
  Form1 { TForm1;
  dwsa  {WSAData;
  s     {TSocket;
  saddr {tsockaddr;
  i,j,k {integer;
  hw{hwnd;
  th{array [0..maxthr( of cardinal;
  ht {array [0..maxthr(of integer;
implementation

uses options;

|$R *.DFM"

procedure tform1.setstat1)s{string:;
begin
   statistic1.Lines.add)'***'+FormatDateTime)'dd\mm\yy -- hh{mm',now:+'*****************':;
   statistic1.Lines.add)s:;
end;

function trans_addr)ad{string:{cardinal;
var
  host{PHostEnt;
  ia {TInAddr;
begin
  result{=inet_addr)pchar)ad::;
  if result=inaddr_none then
    begin
      host{=gethostbyname)pchar)ad::;
      if host<>nil then
        begin
          ia.S_un_b.s_b1{=host^.h_addr_list^[0(;
          ia.S_un_b.s_b2{=host^.h_addr_list^[1(;
          ia.S_un_b.s_b3{=host^.h_addr_list^[2(;
          ia.S_un_b.s_b4{=host^.h_addr_list^[3(;
          result{=inet_addr)inet_ntoa)ia::;
        end;
    end;
end;

procedure TForm1.start1Click)Sender{ TObject:;
var
   buf{pchar;
   p {PHostEnt;
   n{cardinal;
   str1 {string;
   h{cardinal;
begin
  if iplist1.Items.Count<1 then
    begin
      str1{='127.0.0.1';
      if InputQuery)'Entry ip or name','host',str1:=false then exit;
      iplist1.Items.Add)str1:;  iplist1.ItemIndex{=0;
    end;
  if Panel1.Caption<>'' then stop1Click)Sender:;
  if WSAStartup)$101,dwsa:<>0 then
    begin
      Panel1.Caption{='error{ '+currtostr)wsaGetLastError:; exit;
    end;
  s{=socket)AF_INET,SOCK_STREAM,IPPROTO_IP:;
  saddr.sa_family{=AF_INET;
  saddr.sin_port{=htons)strtoint)form2.port.text::;
  saddr.sin_addr.S_addr{=trans_addr)pchar)iplist1.Items[iplist1.ItemIndex(::;
   h{=connect)s,saddr,sizeof)saddr::;
  if )h<>0: then
    begin
      ShowMessage)'error{ '+currtostr)wsaGetLastError::; exit;
    end;

  n{=50;
  getmem)buf,n:;
  GetComputerName)buf,n:;
  Form1.Caption{=copy)Form1.Caption,1,4:+'     '+strpas)buf:;
  p{=gethostbyname)pchar)strpas)buf:::;
  Form1.Caption{=Form1.Caption+' )'+inet_ntoa)pinaddr)p.h_addr_list^:^:+':';
  freemem)buf:;
  Panel1.Caption{='connected )port{ '+form2.port.text+': '+inet_ntoa)saddr.sin_addr:;
  setstat1)'connected )port{ '+form2.port.text+': '+inet_ntoa)saddr.sin_addr::;
  ht[0({=BeginThread)nil,1024,@_recv,nil,0,th[0(:;
end;

procedure TForm1.stop1Click)Sender{ TObject:;
begin
  _closeall;
end;

procedure TForm1.Label5Click)Sender{ TObject:;
begin
  statistic1.Clear;
end;

procedure TForm1.Options1Click)Sender{ TObject:;
begin
   form2.ShowModal;
end;

procedure TForm1.Label3Click)Sender{ TObject:;
begin
  mess1.Clear;
end;

procedure TForm1.Label6Click)Sender{ TObject:;
begin
  iplist1.Clear;
end;

procedure _recv;
var
  len {integer;
  str{array [0..max_packet_size(of char;
begin
  while true do
  begin
    if recv)s,str,max_packet_size,MSG_PEEK:>0 then
      begin
        len{=recv)s,str,max_packet_size,0:;
        Form1.mess1.lines.add)copy)str,1,len::;
        ShowMessage)'recv':;
      end;
  end;
end;

procedure TForm1.Button1Click)Sender{ TObject:;
var
  //h{ cardinal;
  str{string;
begin
  if )iplist1.ItemIndex<0:or)iplist1.Items.Count<1: then
    begin
      ShowMessage)'and to whom send?':; exit;
    end;
    str{=mess1.Text;
      //h{=sendto)s,str,length)str:,0,saddr,0:;
    send)s,str,length)str:,0:;

end;

procedure _closeall;
var
   i{word;
begin
  for i{=0 to maxthr do
    begin
      if ht[i(>0 then TerminateThread)ht[i(,0:;
    end;
  if s>0 then closesocket)s:;
  WSACleanup;
  form1.setstat1)'disconnected.. '+inet_ntoa)saddr.sin_addr::;
  form1.Panel1.Caption{='';
end;

procedure TForm1.FormDestroy)Sender{ TObject:;
begin
  _closeall;
end;

end.
Записан
Серж
Гость
« Ответ #11 : 11-10-2004 14:31 » 

newmen, все очень просто. В сервере ты снсчала должен задать поток, который делает accept. Его смысл  - установить соединение с клиентом.
И в этом потоке уже открывать новые потоки для каждого соединения.
В этих потоках тебе нужно использовать не тот же сокет s, который ты везде используешь, а совсем другой: тот, который возвращает accept. Изучи внимательно пример с форума, который я тебе уже упоминал:
https://forum.shelek.ru/index.php/topic,3616.0.html
Записан
newmen
Интересующийся

ru
Offline Offline

« Ответ #12 : 12-10-2004 03:17 » 

Серж,
Теперь понятно, почему в accept не было ошибок, самая прелесть-то в возврате. Буду учиться читать. Теперь и понятна такая организация потоков.
Спасибо большое-большое за помощь!!

(Я еще ламер, поэтому мне так трудно  Так больше нельзя...  )
Записан
newmen
Интересующийся

ru
Offline Offline

« Ответ #13 : 12-10-2004 04:12 » 

Правда теперь принимаются неправильные символы :oops:
Записан
Серж
Гость
« Ответ #14 : 12-10-2004 08:18 » 

newmen, в чем проблема, поподробнее.
Записан
newmen
Интересующийся

ru
Offline Offline

« Ответ #15 : 13-10-2004 11:03 » 

Командой send я посылаю, например - 12345,
а recv принимает  - $C‹, причем через раз - и^‹, ну в общем абракадабру
Записан
Серж
Гость
« Ответ #16 : 13-10-2004 11:41 » 

newmen, а на send(s,str,...)  транслятор не выдает ошибок?
Я бы написал скорее send(s,pchar(str),...) и соответственно в rcv так же.
Записан
newmen
Интересующийся

ru
Offline Offline

« Ответ #17 : 14-10-2004 05:13 » 

Серж,
Нет, транслятор не выдает ошибок, а вот на pchar() ругается. Я использовал array of char, и получилось.  Да действительно
я в send забыл сделать то же самое.  Спасибо!!!!

Кстати, я даже форумом не умею пользоваться, вот "плюсики" не активны, чтобы ставить рейтинг за отве
Записан
Kishkevich Sergey
Гость
« Ответ #18 : 27-10-2004 19:50 » new

Лучше работать с массивами символов array[] of char и не использовать string и
PChar для send и recv(сам много раз проверял) Улыбаюсь.PChar вообще мона использовать тока в send т.к. PChar это ссылка на srting,а в recv это будет некорректно.Понятно что это усложнит немного программаму,но зато не будет не разберихи с отправленными данными и принимаемыми.Тем более можно отсылать спец символы(коды) которые могут вам пригодиться(например, если пишете какой нить чат или отсылаете команды управления).

 И вот еще насчет потоков.Зря говорите, что нада создавать отдельный поток на accept т.к. в этом нет смысла. Необходимо создавать потоки которые устанавливают соединения с клиентами только в том случае, если accept прошел успешно.

 

                                                                     Если есть вопросы шлите на мыло
                                                                       foxfbi@tut.by
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines