to greenwaterbluesky(我的家在碧水蓝天)
我用本地IP是可以的。一用动态IP就不行了。
to larky(睡仙)
我做的有点像QQ,服务器端和客户端用的都是TNMUDP控件。服务器端的任务主要是用来接收客户端的在线情况(上线人的IP和端口,把上线人的IP和端口告诉所有在线的人)和离线情况,具体通信是客户端之间的事,不通过服务器。在局域网中是可以通信的。
procedure TForm1.BtClearClick(Sender: TObject);
begin
MemoReceive.Clear;
end;
procedure TForm1.BtSaveClick(Sender: TObject);
begin
if SaveDialog1.Execute then MemoReceive.Lines.SaveToFile(SaveDialog1.FileName);
end;
procedure TForm1.EditMyTxtKeyPress(Sender: TObject; var Key: Char);
begin
if Key=#13 then BtSend.Click;
end;
end.
上面的程序跟OICQ相比当然差之甚远,因为OICQ利用的是Socket5通信方式。它上线时先从服务器取回好友信息和在线状态,发送超时还会将信息先保存在服务器,等对方下次上线后再发送然后把服务器的备份删除。你可以根据前面学的概念来完善这个程序,比如说再添加一个NMUDP控件来管理在线状态,发送的信息先转换成ASCII码进行与或运行并加上一个头信息,接收方接收信息后先判断信息头正确与否,如果正确才把信息解密显示出来,这样就提高了安全保密性。
另外,UDP协议还有一个很大的好处就是可以广播,就是说处于一个网段的都可以接收到信息而不必指定具体的IP地址。网段一般分A、B、C三类,
1~126.XXX.XXX.XXX (A类网) :广播地址为XXX.255.255.255
128~191.XXX.XXX.XXX(B类网):广播地址为XXX.XXX.255.255
192~254.XXX.XXX.XXX(C类网):广播地址为XXX.XXX.XXX.255
比如说三台计算机192.168.0.1、192.168.0.10、192.168.0.18,发送信息时只要指定IP地址为192.168.0.255就可以实现广播了。下面给出一个转换IP为广播IP的函数,快拿去完善自己的OICQ吧^-^.
Function Trun_ip(S:string):string;
var s1,s2,s3,ss,sss,Head:string;
n,m:integer;
begin
sss:=S;
n:=pos('.',s);
s1:=copy(s,1,n);
m:=length(s1);
delete(s,1,m);
Head:=copy(s1,1,(length(s1)-1));
n:=pos('.',s);
s2:=copy(s,1,n);
m:=length(s2);
delete(s,1,m);
n:=pos('.',s);
s3:=copy(s,1,n);
m:=length(s3);
delete(s,1,m);
ss:=sss;
if strtoint(Head) in [1..126] then ss:=s1+'255.255.255'; //1~126.255.255.255 (A类网)
if strtoint(Head) in [128..191] then ss:=s1+s2+'255.255';//128~191.XXX.255.255(B类网)
if strtoint(Head) in [192..254] then ss:=s1+s2+s3+'255'; //192~254.XXX.XXX.255(C类网)
Result:=ss;
end;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
NMUDP1: TNMUDP;
procedure Button1Click(Sender: TObject);
procedure NMUDP1BufferInvalid(var handled: Boolean;
var Buff: array of Char; var length: Integer);
procedure NMUDP1DataReceived(Sender: TComponent; NumberBytes: Integer;
FromIP: String; Port: Integer);
procedure NMUDP1DataSend(Sender: TObject);
procedure NMUDP1Status(Sender: TComponent; status: String);
procedure NMUDP1InvalidHost(var handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
C: Array [1..3] of Char;
begin
C := 'cat';
NMUDP1.RemoteHost := '192.100.100.1';
NMUDP1.ReportLevel := Status_Basic;
NMUDP1.LocalPort := 6668;
NMUDP1.RemotePort := 6668;
NMUDP1.SendBuffer(C, 3);
end;
procedure TForm1.NMUDP1BufferInvalid(var handled: Boolean;
var Buff: array of Char; var length: Integer);
begin
ShowMessage('Buffer Invalid: Buffer contains no data');
end;
procedure TForm1.NMUDP1DataReceived(Sender: TComponent;
NumberBytes: Integer; FromIP: String; Port: Integer);
var
C: array [1..3] of Char;
I: Integer;
str:string;
begin
if NumberBytes <= 3 then
begin
NMUDP1.ReadBuffer(C, I);
str:=c[1]+c[2]+c[3];
showmessage(str);
Memo1.Lines.Add(C+': received '+IntToStr(I)+' bytes from '+FromIP+' on port '+IntToStr(Port));
end
else
Memo1.Lines.Add(IntToStr(I)+' bytes incoming, buffer too small');
end;
procedure TForm1.NMUDP1DataSend(Sender: TObject);
begin
Memo2.Lines.Add('Data sent');
end;
procedure TForm1.NMUDP1Status(Sender: TComponent; status: String);
begin
Memo2.Lines.Add(status);
end;
procedure TForm1.NMUDP1InvalidHost(var handled: Boolean);
var
S: String;
begin
S := NMUDP1.RemoteHost;
if InputQuery('Invalid host', 'Specify valid hostname: ', S) then
begin
NMUDP1.RemoteHost := S;
handled := TRUE;
end;
end;