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
Интересующийся
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
Интересующийся
Offline
|
|
« Ответ #12 : 12-10-2004 03:17 » |
|
Серж, Теперь понятно, почему в accept не было ошибок, самая прелесть-то в возврате. Буду учиться читать. Теперь и понятна такая организация потоков. Спасибо большое-большое за помощь!! (Я еще ламер, поэтому мне так трудно )
|
|
|
Записан
|
|
|
|
newmen
Интересующийся
Offline
|
|
« Ответ #13 : 12-10-2004 04:12 » |
|
Правда теперь принимаются неправильные символы :oops:
|
|
|
Записан
|
|
|
|
Серж
Гость
|
|
« Ответ #14 : 12-10-2004 08:18 » |
|
newmen, в чем проблема, поподробнее.
|
|
|
Записан
|
|
|
|
newmen
Интересующийся
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
Интересующийся
Offline
|
|
« Ответ #17 : 14-10-2004 05:13 » |
|
Серж, Нет, транслятор не выдает ошибок, а вот на pchar() ругается. Я использовал array of char, и получилось. Да действительно я в send забыл сделать то же самое. Спасибо!!!!
Кстати, я даже форумом не умею пользоваться, вот "плюсики" не активны, чтобы ставить рейтинг за отве
|
|
|
Записан
|
|
|
|
Kishkevich Sergey
Гость
|
|
« Ответ #18 : 27-10-2004 19:50 » |
|
Лучше работать с массивами символов array[] of char и не использовать string и PChar для send и recv(сам много раз проверял) .PChar вообще мона использовать тока в send т.к. PChar это ссылка на srting,а в recv это будет некорректно.Понятно что это усложнит немного программаму,но зато не будет не разберихи с отправленными данными и принимаемыми.Тем более можно отсылать спец символы(коды) которые могут вам пригодиться(например, если пишете какой нить чат или отсылаете команды управления). И вот еще насчет потоков.Зря говорите, что нада создавать отдельный поток на accept т.к. в этом нет смысла. Необходимо создавать потоки которые устанавливают соединения с клиентами только в том случае, если accept прошел успешно. Если есть вопросы шлите на мыло foxfbi@tut.by
|
|
|
Записан
|
|
|
|
|