急,急,急,急。请帮忙:TNMUDP控件发送数据流的问题。

J.Duke 2002-04-05 03:08:49
本人想做一个程序实现两台在互联网上发消息。现我已知道这两台机子在网上的动态IP。TNMUDP的RemoteHost我已设置为它们的动态IP。发送消息没有出错。但收不到消息。请帮我。如分不够可以另起贴子送分。
...全文
134 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
tongdings 2002-09-16
  • 打赏
  • 举报
回复
欢迎到:

http://www.csdn.net/expert/topic/1026/1026938.xml?temp=5.489528E-03

讨论,送分题,超easy
谢谢...
tongdings 2002-09-13
  • 打赏
  • 举报
回复
gzyx
J.Duke 2002-04-08
  • 打赏
  • 举报
回复
一个IP地址。现在的问题是我客户端的发送。
dcrwy 2002-04-08
  • 打赏
  • 举报
回复
你的服务器程序所在机器是不是有2个IP???
一块调制解调器一快网卡?
给分
J.Duke 2002-04-08
  • 打赏
  • 举报
回复
to rwdx(任我独行)
我没有使用代理上网,况且我发到服务器的消息能收到,就是点对点的发消息不能收到。
rwdx 2002-04-08
  • 打赏
  • 举报
回复
如果你用了代理上网的话,看看代理服务器有没有开通你所使用的端口
hch_d 2002-04-08
  • 打赏
  • 举报
回复
关注………………
J.Duke 2002-04-08
  • 打赏
  • 举报
回复
to all:
大家可以到http://www.csdn.net/expert/topic/631/631213.xml?temp=.4621851看我的源代码,帮我解决一下两台在互联网上进行点对点的问题。
J.Duke 2002-04-08
  • 打赏
  • 举报
回复
to greenwaterbluesky(我的家在碧水蓝天)
请到http://www.csdn.net/expert/topic/631/631213.xml?temp=.4621851
看我的源代码。
GreenWaterBlueSky 2002-04-08
  • 打赏
  • 举报
回复
建议你用NetXRay监听一下,是否收到数据包,假如收不到,我想你应该看看你的
IP地址是怎么写的,是否有误。如果收到了,那我也不明白了
另外有一点我想说:UDP是非面向连接的协议,所以数据包丢失了,它不会重发,也
就是说也可能是丢包了,不过感觉不象
J.Duke 2002-04-08
  • 打赏
  • 举报
回复
to greenwaterbluesky(我的家在碧水蓝天)
我用本地IP是可以的。一用动态IP就不行了。
to larky(睡仙)
我做的有点像QQ,服务器端和客户端用的都是TNMUDP控件。服务器端的任务主要是用来接收客户端的在线情况(上线人的IP和端口,把上线人的IP和端口告诉所有在线的人)和离线情况,具体通信是客户端之间的事,不通过服务器。在局域网中是可以通信的。
Larky 2002-04-08
  • 打赏
  • 举报
回复
能说说你系统的结构吗?
不在一个局域网内,有一个服务器多个客户端类似QQ是吗?
如果在一个局域网内侧是的话可以通信吗?
GreenWaterBlueSky 2002-04-08
  • 打赏
  • 举报
回复
怀疑是IP不正确,你先不要用动态IP试试
J.Duke 2002-04-06
  • 打赏
  • 举报
回复
非常感谢suary(小船)和sforever(人在江湖飘,谁能不挨刀.) 两位提供如此详细的源代码资料。我试过了,在局域网上设它们的固定IP是可以发消息的,但是如果把RemoteHost设成上网的动态IP,RemotePort设置也是对的时,发消息没有提示出错,另外一个程序就是收不到发来的消息。不知原因何在。是不是IP和Port设置有所讲究??还望解答。谢谢。
Sforever 2002-04-05
  • 打赏
  • 举报
回复
实际应用之三:利用流制作自己的OICQ

OICQ是深圳腾讯公司的一个网络实时通讯软件,在国内拥有大量的用户群。但OICQ必须连接上互联网登陆到腾讯的服务器才能使用。所以我们可以自己写一个在局部网里面使用。
OICQ使用的是UDP协议,这是一种无连接协议,即通信双方不用建立连接就可以发送信息,所以效率比较高。Delphi本身自带的FastNEt公司的NMUDP控件就是一个UDP协议的用户数据报控件。不过要注意的是如果你使用了这个控件必须退出程序才能关闭计算机,因为TNMXXX控件有BUG。所有nm控件的基础 PowerSocket用到的ThreadTimer,用到一个隐藏的窗口(类为TmrWindowClass)处理有硬伤。
出问题的地方:
Psock::TThreadTimer::WndProc(var msg:TMessage)
if msg.message=WM_TIMER then
他自己处理
msg.result:=0
else
msg.result:=DefWindowProc(0,....)
end
问题就出在调用 DefWindowProc时,传输的HWND参数居然是常数0,这样实际上DefWindowProc是不能工作的,对任何输入的消息的调用均返回0,包括WM_QUERYENDSESSION,所以不能退出windows。由于DefWindowProc的不正常调用,实际上除WM_TIMER,其他消息由DefWindowProc处理都是无效的。
解决的办法是在 PSock.pas
在 TThreadTimer.Wndproc 内
Result := DefWindowProc( 0, Msg, WPARAM, LPARAM );
改为:
Result := DefWindowProc( FWindowHandle, Msg, WPARAM, LPARAM );
早期低版本的OICQ也有这个问题,如果不关闭OICQ的话,关闭计算机时屏幕闪了一下又返回了。
好了,废话少说,让我们编写我们的OICQ吧,这个实际上是Delphi自带的例子而已:)
新建一个工程,在FASTNET面版拖一个NMUDP控件到窗口,然后依次放上三个EDIT,名字分别为EditIP、EditPort、EditMyTxt,三个按钮BtSend、BtClear、BtSave,一个MEMOMemoReceive,一个SaveDialog和一个状态条StatusBar1。当用户点击BtSend时,建立一个内存流对象,把要发送的文字信息写进内存流,然后NMUDP把流发送出去。当NMUDP有数据接收时,触发它的DataReceived事件,我们在这里再把接收到的流转换为字符信息,然后显示出来。
注意:所有的流对象建立后使用完毕后要记得释放(Free),其实它的释构函数应该为Destroy,但如果建立流失败的话,用Destroy会产生异常,而用Free的话程序会先检查有没有成功建立了流,如果建立了才释放,所以用Free比较安全。
在这个程序中我们用到了NMUDP控件,它有几个重要的属性。RemoteHost表示远程电脑的IP或者计算机名,LocalPort是本地端口,主要监听有没有数据传入。而RemotePort是远程端口,发送数据时通过这个端口把数据发送出去。理解这些已经可以看懂我们的程序了。

全部代码如下:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, ComCtrls,NMUDP;

type
TForm1 = class(TForm)
NMUDP1: TNMUDP;
EditIP: TEdit;
EditPort: TEdit;
EditMyTxt: TEdit;
MemoReceive: TMemo;
BtSend: TButton;
BtClear: TButton;
BtSave: TButton;
StatusBar1: TStatusBar;
SaveDialog1: TSaveDialog;
procedure BtSendClick(Sender: TObject);
procedure NMUDP1DataReceived(Sender: TComponent; NumberBytes: Integer;
FromIP: String; Port: Integer);
procedure NMUDP1InvalidHost(var handled: Boolean);
procedure NMUDP1DataSend(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtClearClick(Sender: TObject);
procedure BtSaveClick(Sender: TObject);
procedure EditMyTxtKeyPress(Sender: TObject; var Key: Char);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.BtSendClick(Sender: TObject);
var
MyStream: TMemoryStream;
MySendTxt: String;
Iport,icode:integer;
Begin
Val(EditPort.Text,Iport,icode);
if icode<>0 then
begin
Application.MessageBox('端口必须为数字,请重新输入!','信息',MB_ICONINFORMATION+MB_OK);
Exit;
end;
NMUDP1.RemoteHost := EditIP.Text; {远程主机}
NMUDP1.LocalPort:=Iport; {本地端口}
NMUDP1.RemotePort := Iport; {远程端口}
MySendTxt := EditMyTxt.Text;
MyStream := TMemoryStream.Create; {建立流}
try
MyStream.Write(MySendTxt[1], Length(EditMyTxt.Text));{写数据}
NMUDP1.SendStream(MyStream); {发送流}
finally
MyStream.Free; {释放流}
end;
end;


procedure TForm1.NMUDP1DataReceived(Sender: TComponent;
NumberBytes: Integer; FromIP: String; Port: Integer);
var
MyStream: TMemoryStream;
MyReciveTxt: String;
begin
MyStream := TMemoryStream.Create; {建立流}
try
NMUDP1.ReadStream(MyStream);{接收流}
SetLength(MyReciveTxt,NumberBytes);{NumberBytes为接收到的字节数}
MyStream.Read(MyReciveTxt[1],NumberBytes);{读数据}
MemoReceive.Lines.Add('接收到来自主机'+FromIP+'的信息:'+MyReciveTxt);
finally
MyStream.Free; {释放流}
end;
end;

procedure TForm1.NMUDP1InvalidHost(var handled: Boolean);
begin
Application.MessageBox('对方IP地址不正确,请重新输入!','信息',MB_ICONINFORMATION+MB_OK);
end;

procedure TForm1.NMUDP1DataSend(Sender: TObject);
begin
StatusBar1.SimpleText:='信息成功发出!';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
EditIP.Text:='127.0.0.1';
EditPort.Text:='8868';
BtSend.Caption:='发送';
BtClear.Caption:='清除聊天记录';
BtSave.Caption:='保存聊天记录';
MemoReceive.ScrollBars:=ssBoth;
MemoReceive.Clear;
EditMyTxt.Text:='在这里输入信息,然后点击发送.';

StatusBar1.SimplePanel:=true;
end;

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;
suary 2002-04-05
  • 打赏
  • 举报
回复
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
NMUDP, StdCtrls;

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;


end.
J.Duke 2002-04-05
  • 打赏
  • 举报
回复
没人知道吗???

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧