PB与Socket应用开发.docx

上传人:b****8 文档编号:10198718 上传时间:2023-02-09 格式:DOCX 页数:13 大小:22.48KB
下载 相关 举报
PB与Socket应用开发.docx_第1页
第1页 / 共13页
PB与Socket应用开发.docx_第2页
第2页 / 共13页
PB与Socket应用开发.docx_第3页
第3页 / 共13页
PB与Socket应用开发.docx_第4页
第4页 / 共13页
PB与Socket应用开发.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

PB与Socket应用开发.docx

《PB与Socket应用开发.docx》由会员分享,可在线阅读,更多相关《PB与Socket应用开发.docx(13页珍藏版)》请在冰豆网上搜索。

PB与Socket应用开发.docx

PB与Socket应用开发

PowerSocket程序设计

初学者指南

PowerBuilder是一个最重要的客户-服务器应用开发工具。

当Internet已经成为共同开发的重要部分,PowerBuilder编写 TCP/IP应用的能力也有所增强。

在PC平台上,有个叫WinSock的DLL提供TCP/IP功能。

PowerBuilder有能力访问DLL中的函数。

因而,调用WinSock.DLL应当不成问题。

但这只是片面的。

WinSock.DLL中大多数函数可以通过声明局部外部函数在PowerBuilder应用中调用。

但对这个方法有重要限制。

在WinSock.DLL中的某些函数与PowerBuilder中的保留字相冲突。

这可以通过在PowerBuilder中声明时给你的函数命别名的方法解决。

另外还有一个问题。

WinSock.DLL中某些函数引用了指针的指针,PowerBuilder不能处置这类型参数传递。

因而,创建了一个叫PowerSocket的DLL,以处理名字/保留字冲突,及处理指针的指针问题。

SCIENCE.ORG的科学家们发现PowerSocket库很有用,并创建了PowerBuilder用户对象使在应用中集成PowerSocket更加简单了。

这些用户对象使得TCP/IP程序设计更加简单。

不过仍然需要了解一些基本知识,以知道如何构造TCP/IP网络应用。

我们希望本初学指南能在你通向用PowerBuilder与PowerSocket成功构造Internet/Intranet应用的成功之路上给你帮助。

Sockets

TCP/IP程序设计也被称为socket程序设计。

编写TCP/IP应用的整体思想是计算机能在网络上相互通信。

这个通信策略使用Soket(插座)的思想。

当你要将设备连接到电源时,你把设备插入socket(插座)。

当两个计算机程序想要通讯时,它们也创建socket插座与另一个连接。

通过socket建立连接不是同时的。

首先,一台计算机建立监听socket。

已经建立监听socket的程序被称为服务器。

连接到监听socket的程序被称为客户。

一旦一个程序连接到另一个程序,服务器与客户之间就没有太大差别。

信息通过socket功能传递。

这些通信会话工作方式已经建立了许多成熟协议。

几乎所有socket程序的基本结构是相同的,它们的不同是通信会话如何进行(它们遵守什么协议)。

如同你在自己和另一个国家中某人之间建立电话连接那样。

用于建立电话连接的手段可能是同样的,但是,使用的语言,讨论的方式可能是不同的。

Socket编程已经使用了多年。

它是UNIX操作系统的一个嵌入部分。

UNIX已经成为Internet与许多自用Intranet事实上的的标准操作系统。

若干年前,由马丁霍尔领导的小组,现在的星团技术(Stardust Technologies),设计与创建了关于PC提供socket的能力。

(相似技术已经被设计于Macintosh,叫Mac TCP)。

这个小组设计了叫WinSock的DLL,它已经成为PC平台网络计算的标准。

PowerSocket

PowerSocket是一个中间DLL,允许PowerBuilder访问WinSockDLL中的所有函数。

目前,只支持PowerSocket版本2.0。

当前有PowerSocket的 16与32位版本。

关于PowerSocket的16与32位版本有些重要的事:

PowerBuilder 4.0 for Windows 3.1 and Windows 95是16位应用。

因而,当编写用于Windows 95的程序,即使它是32位操作系统,你仍然必须使用PowerSocket的16位版本。

在Windows 95上运行的PowerBuilder5.0是32位应用。

32位PowerSocket库目前在PowerBuilder 5.0不可用。

PowerSocket将在PowerBuilder 5.0的最后版本发行是被更新。

PowerSocket的 32位版本在Windows NT3.5与3.51上运行良好。

它没有在NT的其他版本上被测试过。

16与32位DLL都被命名为PSLIB2.DLL。

在你的路径中,只能有其中一个。

这种命名方案将在将来被校正。

PowerSocket具有完全功能参考(PSLIB2.HTM)。

你可以在你的Web浏览器中阅读该文件。

它也包括PSLIB2.DLL,该文件必须在你的路径中。

它还包含WINSOCK.PBD或WINSOCK.PBL中的一个。

该文件必须包含在你的PowerBuilder应用库路径列表中。

在你的库路径列表里包含PBD文件是个技巧。

强制包含它!

创建基本PowerSocket应用

在我们开始学习服务器与客户应用之间不同部分之前,所有PowerSocket应用有共同的部分。

跟随这些基本步骤,你将通向完成第一个soket应用之路。

由创建新应用开始。

你的应用是MDI或SDI应用无足轻重。

创建你的应用所需的用户界面。

如果你已经有了一个应用,你将要对现存应用进行下列修改。

声明全局变量:

winsock ws。

最好使用ws作为你的WinSock对象的名字。

本文档将直接适用。

而且,在某些PowerSocket的早期版本要求你使用该名字。

在你的应用的open事件中,创建你的WinSock对象实例:

ws=create winsock。

在你的PowerSocket代码中不要使用messageboxe!

Messagebox()函数会在你的应用的通讯部分产生临界定时错误(critical timing errors)。

在不涉及socket通信的部分使用messagebox()是允许的。

如果你需要从你的socket代码返回值,推荐你使用静态文本或多行编缉控件,填在它们的text值中。

创建PowerSocket服务器应用

在完成创建基本PowerSocket应用的步骤后,你将准备好开始创建服务器应用。

服务器与客户应用之间的主要差别是服务器监听传入的连接。

服务器应用在端口上监听传入的连接。

此处不是硬件端口,它是软件端口,更简单地或,一个数字。

软件端口与物理连接无关。

它是帮助socket程序决定当连接时使用什么的协议的设备。

socket在不同口上使用不同协议建立连接时。

每台计算机拥有一个物理地址,即IP地址。

你可以把端口认为是端口的扩展。

例如,我的服务器IP数是204.94.74.209。

如果我想要连接该及其的HTTP服务器,我包括一个端口号对应HTTP服务器,它是80。

看起来象这样:

204.94.74.209:

80。

下列是常用服务与协议及它们相关的端口号。

服务/协议端口号

echo            7

daytime         13

ftp-data        20

ftp             21

telnet          23

smtp            25

time            37

name            42

whois           43

gopher          70

http            80

finger          79

x400            103

x400-snd        104

pop-2           109

pop-3           110

uucp-path       117

nntp            119

NeWS            144

一个服务器应用必须完成五件事以成为一个服务器。

创建一个窗口

创建一个socket

在特定端口号绑定IP地址

监听

创建消息映射

除了这4步,其他事与协议有关。

创建socket

有两种类型的socket,Datagram和Stream。

Datagram socket用来创建无连接应用,有时称为UDP socket。

我们将在这指南中谈论Stream socket,用于应用建立连接保证信息传送。

Stream socket有时称为TCP socket。

如果你熟悉在C中socke编程,你将发现使用PowerSocket库已经使建立socket更简单。

PowerSocket库包含特殊用户对象叫socketstream。

你可以象这样创建stream:

socketstream sSock //declare a new socketstream object

sSock = create socketstream //create a new socketstream object

sSock只是对象名。

你可以将你的socketstream对象命名为任何你喜欢的名字。

绑定IP地址到特定端口号

捆绑是简单的,但是要求几个步骤。

绑定socket就是'关联'主机IP地址与特定端口号。

它此刻还未监听,只是将IP与端口联合起来。

bind()函数是socket对象的一个方法,要求两个参数,uladdr(unsignedlong表示要绑定的主机地址)和iPort(integer表示端口编号)。

下一步需要建立uladdr参数。

创建两个变量。

一个变量是无符号长整型,将保存uladdr参数。

第二个是串参数,我们已经任意命名为sHostName。

然后保存64个空格到sHostName 。

ulong ulAddr //create a new variable of type unsigned long

string sHostName //create a string variable to hold the host name

sHostName = space(64)

下一个步对PowerBuilder程序员陌生但对C程序员很普通。

我们将以“引用”方式传递sHostName参数。

这意味着将该变量初始化为无意义值,仅是存储值的地方。

这就是为何我们在sHostName中储存64个空格。

该函数将填一个值到变量中,代替返回一个值。

winsock对象有个叫gethostname()的方法。

该函数填写引用传递的sHostName变量为你的机器的主机名。

传入的第二个参数是我们创建的缓冲区的长度,我们储存了64个空格到sHostName中。

你将发现缓冲在WinSock程序设计中是很常见的。

你将经常需要知道创建的缓冲区的长度。

ws.gethostname(sHostName,len(sHostName))

现在,你有你的机器或服务器程序运行的机器的主机名,保存在变量sHostName中,我们将使用该信息填写非常重要的结构,它是WinSock对象的一部分。

pbhostent结构包含关于网络主机的重要值。

该结构通过调用WinSock对象的若干方法一些填充。

我们将使用的方法叫gethostbyname()。

首先,创建pbhostent的新实例。

在下面的例子中我们已经任意命名新结构为heTmp(hostent temporary的缩写)。

而后通过调用gethostbyname()函数填充它。

传入先前创建的变量sHostName。

pbhostent heTmp //create a new instance of the structure pbhostent

heTmp=ws.gethostbyname(sHostName)

我们现在已经做完所有“家务”。

我们有了绑定服务器并让它监听需要的所有信息!

下一块代码检查heTmp结构是否被gethostbyname()适当地填充。

如果它有值,ulAddr最后将从这结构中取得。

pbhostent结构(目前的heTmp)有个数组类型的成员h_addr_list。

在大多数情况下,该数组将只有一个元素,但是我们仍然必须用下标引用该成员,象这样,h_add_list[1]。

现在,开始令人兴奋的部分。

有了手头的ulAddr变量,你现在可以用socket的方法bind()绑定socket了。

如我们早先提及,bind()接受两个参数,ulAddr和端口号。

在本例子中我们将绑定HTTP端口(80)。

HTTP是WWW协议。

最后,使用socket方法listen()告诉绑定了的socket在端口80监听。

if isnull(heTmp) = FALSE then

ulAddr = heTmp.h_addr_list[1]

sSock.bind(ulAddr,80)

sSock.listen(5)

else

messagebox("Error","Could not determine IP address of local machine")

end if

你现在有了一个socket在端口80上监听。

要让你的socket在不同端口上监听,只需简单地改变bind()函数的第二个参数。

你就快完成一个通用服务器应用了。

下一步,创建一个消息映射,并学习有了它以后怎么做。

创建消息映射作为PowerBuilder程序员,你熟悉当Windows发生某事时触发事件的思想,每个对象都有一系列事件处理程序,当事件触发时被执行。

PowerBuilder为你准备好了一切。

你被惯坏了,承认吧?

现在,你将不得不做点儿工作。

你必须写几行代码来建立特定的消息映射来触发你的PowerBuilder应用中的事件。

这并不难,有专门的WinSock函数叫WSAAsyncSelect()来创建消息映射。

WSAASyncSelect()函数接受三个参数,第一个是处理事件的对象的窗口句柄(handle)。

为什么我们跳过了上面列的步骤中的“创建一个窗口”?

我们假设你知道在PowerBuilder中如何创建窗口。

现在你知道为什么要创建一个窗口:

为了创建消息映射,你需要一个窗口来处理。

在下面的例子中我们使用PowerBuilder handle()函数以返回当前窗口句柄。

第二个参数需要点儿说明。

每个Windows事件对应一个数。

窗口open事件,按钮的clicked事件均如此。

在我们的程序中,我们使用一个PowerBuilder用户定义事件。

PowerBuilder用户定义事件Custom_01对应Windows事件1024。

Custom_02对应1025等等。

WSAASyncSelect()的第三个参数决定Custom_01对应什么事件。

WinSock用户对象将所有WinSock事件定义成枚举数据类型。

这是在它们的一览表:

ws.FD_ACCEPT – 收到连接请求

ws.FD_READ – 读就绪

ws.FD_WRITE – 写就绪

ws.FD_CLOSE – 将要关闭

ws.FD_CONNECT – 连接完成

ws.OOB – 数据越界

经常会有这中情况,你希望多个事件发生时触发一个事件。

你可以象这样用加把它们'或'起来:

aEvents = ws.FD_READ + ws.FD_WRITE + ws.FD_CLOSE

在设置包含监听socket的窗口的消息映射时,你将触发Custom_01l来接收socket连接。

那么,代码如下:

aEvents = ws.FD_ACCEPT

sockSocket.WSAAsyncSelect(handle(this),1024,aEvents)

太棒了!

你现在有了监听socket,及一个消息映射,当收到socket连接时触发Custom_01事件。

现在只剩下让你的服务器程序在收到连接请求时做点什么。

接受连接

在前一节中你已经设置了消息映射,当你的服务器接收socket连接请求时,触发PowerBuilder的Custom_01事件。

你的下一个步是给你的窗口创建Custom_01事件。

这在PowerBuilder中通过选择Declare|User Events...菜单完成。

接受连接不费吹灰之力。

我们在现在向你展示让你的服务器接受多连接的方法。

该方法使你的服务器可以在同一时间处理若干socket通信会话。

这称为异步socket通信。

这正是你下面要做的,及其背后的原因。

停止编辑你的主窗口几分钟,创建一个Powerbuilder可视用户对象(visual user object)。

你创建可视用户对象而不是非可视用户对象的原因是因为非可视用户对象没有你需要的窗口句柄。

我们将需要该句柄来创建另一个消息映射。

命名你的新可视用户对象为connected_socket。

这是任意的,但是你应遵守本指南以便继续。

Creating the connected_socket object

connected_socket 对象接手监听socket的工作。

connected_socket 对象将继续socket通信会话,将监听socket解放出来以便接受另一个连接。

每次监听socket接受另一个连接,它将创建新的connected_socket对象。

connected_socket对象是编制管理你的“协议相关”通信会话的代码的地方。

现在,我们将从该对象要求两个部件开始。

在connected_socket对象中,声明一个socket类型的实例变量。

socket sSocket

而后,在connected_socket对象的constructor中创建一个新的socket对象。

你应该将visible属性设为FALSE,除非你希望可视用户对象出现在屏幕上。

sSocket = create socket

visible = FALSE

保存这段脚本,然后创建叫initsocket()的用户对象函数。

同样,该函数的名字是任意。

在该函数中你将初始化socket并创建消息映射。

该用户对象将拥有自己的消息映射,并将响应FD_READ, FD_WRITE和FD_CLOSE事件。

integer aEvent

aEvent = ws.FD_READ + ws.FD_WRITE + ws.FD_CLOSE

sSocket.initsocket(uiTmp)

sSocket.WSAAsyncSelect(handle(this),1024,aEvent)

为用户对象创建Custom_01事件。

这是你处理连接的地方。

再回到编辑主窗口Custom_01事件的地方。

在该事件中,你将:

创建你的可视用户对象的新实例。

用socket对象的accept()方法接收socket连接。

accept()函数返回socket标识符,即socket编程中众所周知的socket号。

socket号传递到新的connected_socket对象。

用OpenUserObject()函数在窗口上打开用户对象。

ulong ulAddr

int iPort

uint uiTmp

connected_socket csTmp

uiTmp = sockSocket.accept(ulAddr,iPort)

if uiTmp > 0 then

OpenUserObject(csTmp,0,0)

csTmp.initsocket(uiTmp)

end if

在socket连接上通讯

如果你按本指南中描述的创建一个PowerSocket服务器程序,socket通信会话将发生在connected_socket用户对象的custom_01事件中。

事件

关于插座通信会话要知道的最重要的事是区分不同事件。

你可以用WinSock函数WSAGetSelectEvent()决定哪个事件发生了。

PowerBuilder 消息目标(message)包含该函数需要的参数。

iEvent = ws.WSAGetSelectEvent(message.longparm)

在新消息映射在connected_socket对象的initsocket()函数中被创建是,FD_WRITE事件将发生。

它表示socket连接好了并“写就绪”。

在你的程序中只有两中情况FD_WRITE会发生。

一种是当socket被首先连接。

另一种是你在试图写时遇到块条件(blocking condition)。

你将暂停脚本直到下一个FD_WRITE。

FD_READ 不同。

在仍有数据要读时,你将持续收到FD_READ事件。

你将不得不准备的一个异常条件,就是在缓冲里还有数据要读时收到FD_CLOSE事件。

我们设置了一个标志,让我们知道收到这一事件。

我们检验IoctlSocket()函数来看看在缓冲里是否还有数据要读。

发送与接收数据

在PowerSocket应用中所有数据作为blob在socket上发出。

这意味着你必须使用PowerBuilder blob处理函数管理你的数据。

你将在下面的例子看到数据在缓冲(bolbBuf)中被派送。

下列例子模拟HTTP服务器方式处理通信会话。

blob blobBuf, blobItem //create blob variables

int iLen, iPos, iEvent

string sTmp

window parentwindow

iEvent = ws.WSAGetSelectEvent(message.longparm) //Determine what event occurred

if iEvent = ws.FD_READ then //If the FD_READ event occurred

blobBuf = blob(space(1024))

iLen = sSocket.recv(blobBuf,len(blobBuf),0)

sTmp = string(blobmid(blobBuf,1,iLen))

iPos = pos(sTmp,"/")

if iPos > 0 then

sTmp = mid(sTmp,iPos + 1)

end if

iPos = pos(sTmp," ")

if iPos > 0 then

sTmp = left(sTmp,iPos - 1)

end if

if sTmp = "" then

sTmp = "index.html"

end if

iPos = pos(sTmp,"~r~n")

if iPos > 0 then

sTmp = left(sTmp,iPos - 1)

end if

select html into :

html from documents where name = :

sTmp;

if sqlca.sqlcode <> 0 then

html = "Error:</p><p> Document not found"

html = html + "

Error:

 Document not found

"

html = html + "Please try again."

end if

iEvent = ws.FD_WRITE

bWrite = TRUE // FD_WRITE event occurs upon socket connect. Only

// interested in FD_WRITE after send()'ing starts

end if

if iEvent = ws.FD_WRITE and bWrite = T

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1