博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Delphi中TUDPSocket的使用
阅读量:6039 次
发布时间:2019-06-20

本文共 3145 字,大约阅读时间需要 10 分钟。

        按照Delphi文档上所说,欲在两个socket之间通信,必须一个为client,一个为server。这个概念在TCP上还好说,但是用在UDP上就不大合适了。borland提供的UDP组件只有一个TUDPSocket,按照borland的说法,TUDPSocket即可以作为client也可以作为server使用(UDP下,server与client的区别并不明显,但为了方便我们不妨这么称呼)(参考 turbo delphi win32 developer's guide里的Using Client Sockets和Using Server Sockets)。但是通过源码我们不难发现,TUDPServer是继承于TCustomIPClient的。它被设计为只能当作一个客户端来用。

        通过参考vc++的范例程序得知UDP通信时,server端要做的工作有:open->bind->send/recv->close,其中bind这步很重要,它将一个socket绑定到一个本地地址。document上的原话是:

    This routine is used on an unconnected connectionless or connection-oriented socket, before subsequent connects or listens. When a socket is created with socket, it exists in a name space (address family), but it has no name assigned. bind establishes the local association of the socket by assigning a local name to an unnamed socket.

“这个例程在连接(无连接)与监听(面向连接)之前调用...bind把一个本地的名字绑定到了一个socket上”

        监听是TCPServer的动作,那么相对应的,在UDP中作为Server使用的socket也应当调用bind()。可是在borland提供的socket.pas中bind一共出现了5次,4次在TIPSocket,还有一次出现在TCustomTCPServer。前四次是对socket API的封装,最后一次也是这个.pas中唯一的一次对bind的调用。就是这个bind使TUDPSocket“沦为”了一个客户端。

      TUDPSocket的Open方法会依次建立一个socket,设置好远端地址和端口,然后就自动连接了。没有bind。而唯一的会调用bind的TTCPServer,它在bind后则自动进入了监听状态。对于UDP来说,我们不希望它监听,要达到这个目的,除了写自己的类以外,我们只能从它们的父类入手。

通过观察发现,TIPSocket实现了bind的封装,并且它的open方法继承于TBaseSocket——只完成了socket的创建,这恰恰是我们所需要的。我们只需要手动bind这个socket即可。

 

源码如下,turbo delphi 2006(ver100)调试通过:

 

 {server端设置}program UDPServer;{$APPTYPE CONSOLE}uses  SysUtils,  Sockets,  WinSock;const  DefaultPort='827';var  aUDPServer  : TIPSocket;  addr        : TSockAddr;  rv,i        : integer;  quit        : boolean;  buf         : array [0..255] of byte;begin  { TODO -oUser -cConsole Main : Insert code here }  quit:=false;  aUDPServer:=TIPSocket.Create(nil);  aUDPServer.LocalHost:=aUDPServer.LocalHostName;  aUDPServer.LocalPort:=DefaultPort;  aUDPServer.Protocol:=IPPROTO_UDP;  aUDPServer.SockType:=stDgram;  //aUDPServer.BlockMode:=bmNonBlocking;  aUDPServer.Active:=true;  addr:=aUDPServer.GetSocketAddr(aUDPServer.LocalHost,aUDPServer.LocalPort);  bind(aUDPServer.Handle,addr,sizeof(addr));  while not quit do  begin    fillchar(buf,255,0);    rv:=aUDPServer.Receivebuf(buf,sizeof(buf));    if rv<>Socket_Error then    begin      for i:=0 to rv do write(inttohex(buf[i],2),' ');      writeln;      for i:=0 to rv do write(chr(buf[i]));      writeln;    end;  end;  if assigned(aUDPServer) then    aUDPServer.Free;end.
{client端}unit UUDPClient;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls, Sockets;type  TForm1 = class(TForm)    UdpSocket1: TUdpSocket;    Button1: TButton;    Edit1: TEdit;    procedure FormCreate(Sender: TObject);    procedure Button1Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  Form1: TForm1;implementation{$R *.dfm}const  DefaultPort = '827';procedure TForm1.FormCreate(Sender: TObject);begin  with UdpSocket1 do  begin    RemoteHost:='121.195.43.77';    RemotePort:=DefaultPort;    Active:=true;  end;end;procedure TForm1.Button1Click(Sender: TObject);var  buf : array [1..256] of byte;  i:integer;begin  fillchar(buf,length(buf),0);  if length(edit1.Text)

 

转载地址:http://qlrhx.baihongyu.com/

你可能感兴趣的文章
Scrum 简介
查看>>
Windows批处理 调用程序后 不等待子进程 父进程继续执行命令
查看>>
[BZOJ 4551][Tjoi2016&Heoi2016]树(并查集)
查看>>
smartcar.urdf.xacro
查看>>
C#设计模式学习笔记-单例模式
查看>>
BaseActivity
查看>>
django 使用mysql数据库的流程
查看>>
Java基础之String类
查看>>
数据库--释放mysql数据库资源
查看>>
jQueryUI Repeater 无刷新删除 新建 更新数据 - JQueryElement [7]
查看>>
FOJ有奖月赛-2015年11月 Problem A
查看>>
电商网站中添加商品到购物车功能模块2017.12.8
查看>>
android 模拟器 hardWare 属性说明
查看>>
六款值得推荐的android(安卓)开源框架简介
查看>>
max_element( )
查看>>
CSS Grid 布局
查看>>
接口的幂等性
查看>>
java中的类
查看>>
android 自定义文字跑马灯 支持拖拽,按住停止滚动,自定义速度
查看>>
SpringMVC完成文件上传的基本步骤
查看>>