如何接收超2048字节的UDP数据(Delphi5/NMUDP)(100分)

  • 主题发起人 主题发起人 Admy
  • 开始时间 开始时间
A

Admy

Unregistered / Unconfirmed
GUEST, unregistred user!
如题,
procedure TForm1.NMUDP1DataReceived(Sender: TComponent;
NumberBytes: Integer;
FromIP: String;
Port: Integer);
begin
//当传入的upd数据长度超过2048时, NumberBytes返回-1
//传入的数据是另一个程序发出的,我无法控制
//只能在接收端想办法了
end;
 
这是个复杂一点的问题;
如果你的通讯是在内网(局域网内)进行, 就应该没有问题的;
如果是在互联网上进行的, 那就很难说了;
互联网上的网关很多(也就是你的数据包要经过的驿站很多), 每个网关为了性能考虑允许通行的单个包的大小也有差别的;
udp与tcp不同, tcp一般按流的方式通讯(允许中间重新分包组包, 但udp不是这样;
我大量测试过互联网上的udp包的传递, <1k 的udp包基本上是安全的, 超过了1K很多网网关是通行不了的.
所以最后的结果: 你只能要求对方改程序了, 重新组织数据的传送方式;
 
对方的程序我没法要求修改了!
现在暂且不考虑数据可靠性、稳定性....
只要能把超过2048字节的UDP数据收下来就行,
(有一个测试程序,有的UPD包大小有13K)
能用什么法子?
 
剩下下的办法: 从他的电脑拉根网线到你的电脑吧;
// 估计是不可能的;
还有一个有条件的办法: 你找个能接收到udp大数据包的中间IP作为中转站, 转换成tcp....
有些事情还是很难的, 勉强不了的, 例如: 让你去爬珠穆朗玛峰
 
TO:新世纪,
老大,你真会忽悠!不过还是要感谢你的关注。
在网上找资料,自己做了一个控件,搞定了。结贴。
 
代码贴出来,也许可以给有需要的人参考一下.
unit AdmyUdpReceiver;
interface
uses
Messages, Classes, Controls, WinSock;
const
WM_SOCK = WM_USER+1;
//自定义windows消息
type
TDataReceivedEvent = procedure(Sender: TComponent;
NumberBytes: Integer;Buffer:array of char) of object;
TAdmyUdpReceiver=class(TWinControl)
private
FSocket: TSocket;
FPort: u_short;
FSocketOK: boolean;
FDataReceived: TDataReceivedEvent;
procedure ReadData(var Message: TMessage);
message WM_SOCK;
published
property OnDataReceived: TDataReceivedEvent read FDataReceived write FDataReceived;
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
procedure InitSocket(port:integer);
end;

implementation
{ TAdmyUdpReceiver }
constructor TAdmyUdpReceiver.Create(AOwner: TComponent);
var
TempWSAData: TWSAData;
begin
inherited Create(AOwner);

FSocketOK:=false;
if WSAStartup($101, TempWSAData)=1 then
exit;
// showmessage('StartUp Error!');
FSocket := Socket(AF_INET, SOCK_DGRAM, 0);
if (FSocket = INVALID_SOCKET) then
//Socket创建失败
begin
// showmessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(FSocket);
end;

FSocketOK:=true;
end;

destructor TAdmyUdpReceiver.Destroy;
begin
if FSocketOK then
CloseSocket(FSocket);
inherited;
end;

procedure TAdmyUdpReceiver.InitSocket(port: integer);
var
addr: TSockAddr;
begin
if not FSocketOK then
exit;
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
FPort:=port;
addr.sin_port := htons(FPort);
if Bind(FSocket, addr, sizeof(addr)) <> 0 then
begin
exit;
//showmessage('bind fail');
end;
WSAAsyncSelect(FSocket, self.Handle , WM_SOCK, FD_READ);
end;

procedure TAdmyUdpReceiver.ReadData(var Message: TMessage);
var
buffer: Array [1..32768] of char;
//最大可接收字节数
len: integer;
flen: integer;
Event: word;
// value: string;
FSockAddrIn : TSockAddrIn;
begin
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Port := htons(FPort);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
try
len := recvfrom(FSocket, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
except
len:=-1;
end;

if assigned(FDataReceived) then
FDataReceived(self,len,buffer);
end;
end;

end.
 
后退
顶部