-
Покажите (кому не жалко) грамотный код работы с TUDPSocket
-
Ты скажи что тебе конкретно не понятно или какие проблемы возникли при использовании этого класса ..
-
> Сергей М. © (21.10.10 09:21) [1]
Да собственно проблем не возникало :)
Нуна чтоб экземпляры приложения в сети знали друг о друге
т.е. раз в n-мин шлем датаграмму BroadCast. Если софтина поймала ее, значит добавили (обновили) в список, если последний пакет приходил раньше чем 10*n - удаляем из списка как усопшего...
Вообщем все тривиально, но велосипед писать не охота, т.к. UDP ни разу не юзал.
-
> Dennis I. Komarov © (21.10.10 11:38) [2]
Я бы не рекомендовал пользовать для этой цели TUDPSocket. Гораздо удобней, надежней и интуитивно понятней работать с TUDPBlockSocket в составе сторонней библиотеки Synapse.
-
Да, шарился по помойке - кругом полно WinSock. TUDPSocket никто не любит. Synapse тяжелая? Для такой мелкой задачи не охота тащить что-то. Чую что путь лежит к WinSock...
-
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Sockets, StdCtrls, IdBaseComponent, IdComponent,
IdUDPBase, IdUDPServer,Idglobal,IdSocketHandle;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Timer1: TTimer;
IdUDPServer1: TIdUDPServer;
procedure Timer1Timer(Sender: TObject);
procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
AData: TIdBytes; ABinding: TIdSocketHandle);
procedure FormShow(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
const
PS1='Ya tut';
PS2='Gde vse';
N=4;
procedure TForm1.FormShow(Sender: TObject);
begin
IdUDPServer1.Broadcast(PS2,IdUDPServer1.DefaultPort);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var i,t:integer;
begin
for i:=ListBox1.Items.Count-1 downto 0 do
begin
t:=StrToIntDef(ListBox1.Items.ValueFromIndex[i],0);
dec(t,Timer1.Interval div 1000);
if t<=0 then
ListBox1.Items.Delete(i)
else
ListBox1.Items.ValueFromIndex[i]:=IntToStr(t);
end;
IdUDPServer1.Broadcast(PS1,IdUDPServer1.DefaultPort);
end;
procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
AData: TIdBytes; ABinding: TIdSocketHandle);
var SData:string;
begin
SetString(SData,PChar(@AData[0]),Length(AData));
if SData=PS1 then
ListBox1.Items.Values[ABinding.PeerIP]:=IntToStr(Timer1.Interval*N div 1000);
if SData=PS2 then
begin
ListBox1.Items.Values[ABinding.PeerIP]:=IntToStr(Timer1.Interval*N div 1000);
IdUDPServer1.Send(ABinding.PeerIP,IdUDPServer1.DefaultPort,PS1);
end;
end;
end.
-
> Slym © (21.10.10 12:49) [5]
Индейцев религия не позволяет :) Только генофонд и API...
-
Поправьте если не прав, но мысля в сторону:
1. Создаем поток-нить. 2. Инициализируем сокет а-ля WSAStartUp 3. Пока поток жив пытаемся читать 3.1 Если что-то смогли прочитать сообщаем основному о чуде 4. Выйдя из "пока" чистим а-ля WSACleanUp
-
Dennis I. Komarov © (21.10.10 13:59) [7]да... вот консолька, консольке доп поток не нужен потому его и нет... program UDP;
uses
SysUtils,WinSock,Windows;
resourcestring
sWindowsSocketError = 'Windows socket error: %s (%d), on API ''%s''';
procedure RaiseSocketError(const Op: string);
var Error:integer;
begin
Error := WSAGetLastError;
raise Exception.CreateResFmt(@sWindowsSocketError, [SysErrorMessage(Error), Error, Op]);
end;
procedure WriteLnEx(const Text:string;color:byte=FOREGROUND_GREEN);
var
hStdOut:THandle;
BufferInfo:TConsoleScreenBufferInfo;
Result:DWORD;
Attrs: array of word;
i:integer;
begin
hStdOut:=GetStdHandle(STD_OUTPUT_HANDLE);
Win32Check(GetConsoleScreenBufferInfo(hStdOut,BufferInfo));
SetLength(Attrs, Length(Text));
for I:=low(Attrs) to high(Attrs) do Attrs[I]:=color;
Writeln(Text);
Win32Check(WriteConsoleOutputAttribute(hStdOut, @Attrs[0], Length(Text), BufferInfo.dwCursorPosition, Result));
end;
procedure RecvLoop(sock: TSocket);
const BufSize:integer=$ffff;
var
buf: PChar;
from: TSockAddr;
Size,fromlen: integer;
begin
fromlen:=SizeOf(TSockAddr);
GetMem(buf, bufsize);
try
while true do
begin
Size:=recvfrom(sock, buf^, BufSize, 0, from, fromlen);
if Size<> SOCKET_ERROR then
begin
WriteLnEx(inet_ntoa(from.sin_addr)+':'+inttostr(ntohs(from.sin_port))+' write:');
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, dword(Size), dword(Size), nil);
end else RaiseSocketError('recvfrom');
end;
finally
FreeMem(buf);
end;
end;
var
WSAData: TWSAData;
sock:TSocket;
addr:TSockAddrIn;
begin
WSAStartup(MakeWord(1, 0), WSAData);
sock:=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
addr.sin_family:= AF_INET;
addr.sin_addr.S_addr:= htonl(INADDR_ANY);
addr.sin_port:= htons(3052);
WriteLnEx('Listening '+inttostr(ntohs(addr.sin_port))+' port...',FOREGROUND_RED);
bind(sock, addr, SizeOf(addr));
RecvLoop(sock);
closesocket(sock);
WSACleanup;
end.
-
Мерси, сейчас подшаманю и ...
-
> Synapse тяжелая?
imho, в сравнении с индейским творчеством - легкое , довольно изящное перышко против большого тяжелого кривоватого бревна
-
отправляем: в Create WSAStartup($101,Init);
Sock:=Socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
SockOpt:=TRUE;
SetSockOpt(Sock,SOL_SOCKET,SO_BROADCAST,PChar(@SockOpt),SizeOf(SockOpt));
Target.sin_port:=htons(5353);
Target.sin_addr.S_addr:=INADDR_BROADCAST;
Target.sa_family:=AF_INET;
Таймер Data:='Any string';
SendTo(Sock,Data,Length(Data),0,Target,SizeOf(Target));
В Close CloseSocket(Sock);
WSACleanup;
Почему приходит не то? З.Ы. даже код [8] принимает не то
-
> Почему приходит не то?
Потому что отправил "не то".
> SendTo(Sock,Data,Length(Data)
Судя по оператору-фигуранту "Length", Data у тебя есть либо ларжстринг либо динам.массив. А раз так, то отправил ты партнеру не cfvb данные, а указательную галиматью
-
Dennis I. Komarov © (18.11.10 13:16) [11] SendTo(Sock,Data,Length(Data),0,Target,SizeOf(Target));навскидку SendTo(Sock,PChar(Data)^,Length(Data),0,Target,SizeOf(Target));
-
Да, спасибо. Я уже разглядел. Черт не туда глянул просто.
|