文档库 最新最全的文档下载
当前位置:文档库 › LWIP接口函数的文档

LWIP接口函数的文档

LWIP接口函数的文档
LWIP接口函数的文档

Lwip 协议栈的设计与实现

(中文版)

Swedish Institute of Computer Science

February 20, 2001

作者:Adam Dunkels adam@sics.se 翻译:果农(QQ:10205001)

核桃(QQ:329147)

佳旭(QQ:3232253)

整理:佳旭(QQ:3232253)

本文为QQ群ARM TCPIP LCD(群号:10988210)版权所有未经作者许可不得用于商业用途

摘要

LWIP是TCP/IP协议栈的一种实现。LWIP的主要目的是减少存储器利用量和代码尺寸,使LWIP适合应用于小的、资源有限的处理器如嵌入式系统。为了减少处理器和存储器要求,lwIP 可以通过不需任何数据拷贝的API进行裁减。

本文叙述了lwIP的设计与实现。叙述了协议实现及子系统中所使用的算法和数据结构如存储和缓冲管理系统。还包括LWIP API的参考手册和使用LWIP 的一些代码例子。

目录

1 Introduction (1)

2 Protocol layering (1)

3 Overview (2)

4 Process model (2)

5 The operating system emulation layer (3)

6 Buffer and memory management...................................................................... (3)

6.1 Packet buffers -pbufs (3)

6.2 Memory management (5)

7 Network interfaces........................................................................................ .. (5)

8 IP processing (7)

8.1 Receiving packets (7)

8.2 Sending packets (7)

8.3 Forwarding packets (8)

8.4 ICMP processing (8)

9 UDP processing............................................................................................ (8)

10 TCP processing.......................................................................................... (9)

10.1 Overview (9)

10.2 Data structures (10)

10.4 Queuing and transmitting data (12)

10.4.1 Silly window avoidance (13)

10.5 Receiving segments (13)

10.5.1 Demultiplexing (13)

10.5.2 Receiving data (14)

10.6 Accepting new connections (14)

10.7 Fast retransmit (14)

10.8 Timers (14)

10.9 Round-trip time estimation (15)

10.10Congestion control (15)

11 Interfacing the stack (15)

12 Application Program Interface...................................................................... .. (16)

12.1 Basic concepts (16)

12.2 Implementation of the API (17)

13 Statistical code analysis (17)

13.1 Lines of code (18)

13.2 Object code size (19)

14 Performance analysis................................................................................. (20)

15 API reference........................................................................................... (21)

15.1 Data types (21)

15.1.1 Netbufs (21)

15.2 Bu?er functions (21)

15.2.1 netbuf new() (21)

15.2.2 netbuf delete() (21)

15.2.3 netbuf alloc() (22)

15.2.4 netbuf free() (22)

15.2.5 netbuf ref() (22)

15.2.6 netbuf len() (23)

15.2.7 netbuf data() (23)

15.2.8 netbuf next() (23)

15.2.9 netbuf ˉrst() (24)

15.2.10 netbuf copy() (24)

15.2.11 netbuf chain() (24)

15.2.12 netbuf fromaddr() (24)

15.2.13 netbuf fromport() (25)

16 Network connection functions (25)

16.0.14 netconn new() (25)

16.0.15 netconn delete() (25)

16.0.16 netconn type() (25)

16.0.17 netconn peer() (25)

16.0.18 netconn addr() (26)

16.0.19 netconn bind() (26)

16.0.20 netconn connect( (26)

16.0.21 netconn listen() (26)

16.0.22 netconn accept() (26)

16.0.23 netconn recv() (27)

16.0.24 netconn write() (28)

16.0.25 netconn send() (29)

16.0.26 netconn close() (30)

17 BSD socket library (30)

17.1 The representation of a socket (30)

17.2 Allocating a socket (30)

17.2.1 The socket() call (30)

17.3 Connection setup (31)

17.3.1 The bind() call (31)

17.3.3 The listen() call (32)

17.3.4 The accept() call (32)

17.4 Sending and receiving data (33)

17.4.1 The send() call (33)

17.4.2 The sendto() and sendmsg() calls (34)

17.4.3 The write() call (34)

17.4.4 The recv() and read() calls (35)

17.4.5 The recvfrom() and recvmsg() calls (36)

18 Code examples (36)

18.1 Using the API (36)

18.2 Directly interfacing the stack (39)

Bibliography (41)

1 序论

在过去的几年里,人们对计算机互连和计算机无线互连支持设备的兴趣不断的增长,计算机逐渐与日常使用的设备无缝结合,并且价格不断下降。同时,无线网络技术如Bluetooth [HNI+98] 和 IEEE 802.11b WLAN [BIG+97]不断显现。这也在一些领域譬如医疗保健、安全保卫、交通运输、加工业等引起了许多新引人入胜的情节。小的设备如传感器能被联入现有的网络如全球因特网,并可以在任何地方对其进行监控。

在过去的几年里,互联网技术证明自己具有足够的灵活性来合并不断改变的网络的环境。与当初为低速网络譬如ARPANET网而产生的互联网相比,今天的大范围连接的互联网技术在带宽和误码率方面都与原来有着巨大的差异。由于互联网的大量应用,把将来的无线互连网络应用于现有的互连网络将会给我们带来巨大的收益。并且,大面积互连的互联网也是一强劲趋势。

自从人们经常对像传感器这样的小设备有小的物理外形和便宜的价格的要求,实现一较少的处理和存储要求的互连协议就成为必须解决的问题。本文描述了一种称为LWIP的小到足以满足最小系统要求的TCP/IP协议栈的设计与实现。

本文结构如下编排:第2,3和4部分对lwIP栈作一个概述,第5部分叙述操作系统模拟层,第6部分叙述缓存和存储管理。第7部分介绍lwIP抽象的网络接口,第8,9,和10部分叙述IP,UDP,和TCP协议的实现。第11和12部分叙述怎样与lwIP进行接口并介绍lwIP API。第13和14部分分析了实现过程。最后,15部分提供了lwIP API用户参考手册,17和18部分展示了多种代码例子。

2 协议分层(Protocol layering)

TCP/IP协议被设计为分层结构,各协议层分别解决通信问题的一部份。这一分层对于协议的设计、实现可起一个指导作用,各个协议可分开实现。然而协议严格的按分层结构来实现,各层之间的通讯可能会导致总体性能的降低 [[Cla82a] 。 为克服这些问题, 协议的某些内部方面可传达给其它协议共享,但必须注意,保证只有那些重要信息才在各层共享。

尽管底层协议或多或少可以进行交叉存取,大部分TCP/IP协议,还是在应用层协议与底层协议之间进行严格的区分。在大部分操作系统中,底层协议被作为与应用层程序具有通讯接口的操作系统内核的一部分。应用程序被看作是TCP/IP协议的抽象,网络通讯与进程间通讯或者文件I/O只有很小的差别。这意味着,因为应用程序不知道被底层协议所使用的缓冲机制,它不能利用缓冲机制对经常使用的数据进行缓冲。同样,当应用程序发送数据时,在数据被网络代码处理前,必须把这些数据从应用程序存储区被拷贝到内部缓冲区。

最小系统中使用的操作系统像lwIP的目标系统在内核和应用进程之间常常并不存在严格的保护屏障。这就允许应用程序和底层协议之间使用一种更宽松的方案,通过共享内存。特别地,应用层可以意识到底层协议所使用的缓存处理机制。因此,应用可以更有效地重用缓冲区。而且,

既然应用进程和网络代码可以使用相同的内存,应用可以直接读写内部缓存,因此节省了执行拷贝的开销。

3 总述(Overview)

正如其他TCP/IP协议的实现,分层协议的设计为LWIP的设计与实现提供一向导。每一个协议都作为一个模块来实现,提供一些与其他协议的接口函数。尽管各层分开实现,但正如上面所讨论的,为了同时提高处理速度和内存利用两方面的性能,一些层在设计时违背这一原则。例如:当检验一接收到的TCP段(segment)的校验和(checksum)和分解TCP段时,源和目的IP 地址必须被告知TCP模块。LWIP实现时不是通过函数调用把IP地址传递给TCP,而是TCP模块通过获取IP报头的结构进而自己提取这一信息。

LWIP有几个模块组成,除了实现TCP/IP协议的各个模块(IP、ICMP、UDP、和 TCP),同时设计了许多支持模块。这些支持模块组成了操作系统模拟层(第5章)、缓冲和存储管理子系统(第6章)、网络接口函数(第7章)和一些处理因特网校验和的函数。LWIP还包括关于API的摘要(第12章)。

4 进程模型(Process model)

协议实现的过程模型以把系统划分成为不同的过程的方法进行描述。用于实现通讯协议的过程模型使每个协议作为孤立的过程运行。这种模型使用严格的协议分层,协议之间的通讯结点必须被严格定义。虽然这种方法有其诸多优势如协议能在运行时被增加,代码一般容易理解和调试,但也有不利因素。 严格的分层,正如先前所述,并不总是实现协议的最好方法。 同时,更重要的,每跨越一层,必须做一次上下文切换。这将意味着,接受一个TCP段要进行三次上下文切换:从网络接口的驱动,到IP处理,再到TCP处理,最终到应用处理。根据网络接口的设备驱动程序,对于IP过程,对于TCP过程和最后。 在大多数操作系统中一个上下文切换所花的代价都是相当昂贵的。

另一个较普通的方法是把通信协议封装在操作系统的内核。 在这种内核实现通讯协议的情况下,应用程序通过系统调用完成通讯。 通讯协议之间不严格区分,但可以使用交叉协议分层技术。

lwIP所使用的过程模型是:把所以协议封装到一个单一的过程中,从而与操作系统内核分开。应用程序可能也驻留在lwIP处理过程中,或者在单独的过程中。 TCP/IP栈和应用程序之间的通信可以通过函数调用实现,也可以通过更为抽象的API。

以上两种LWIP的实现方法各有其优缺点。把LWIP作为一个过程的主要优点是便于在不同的操作系统上移植。由于LWIP的设计目标是面向小的操作系统,这些操作系统一般不支持进程外交换(swapping out processes)或者虚拟存储,这样由于LWIP处理过程交换或者翻页到磁盘而引起的不得不等待磁盘响应造成的延迟将不再是一个问题。尽管在获得服务响应前必须等待调度仍然是一个问题,但是,在LWIP设计时,这并没有妨碍它在一操作系统内核中实现。

5 操作系统模拟层

为了使lwIP便于移植,与操作系统有关的功能函数调用和数据结构没有在代码中直接使用。而是当需要这样的函数时,操作系统模拟层将加以使用。操作系统模拟层向诸如定时器、处理同步、消息传送机制等的操作系统服务提供一套统一的接口。原则上,移植lwIP到其他

操作系统时,仅仅需要实现适合该操作系统的操作系统模拟层。

操作系统模拟层提供了由TCP使用的定时器功能。操作系统模拟层提供的定时器是一次性的定时器,当超时发生时,调用一个已注册函数至少要200ms的间隔。

进程同步机制仅提供了信号量。即使在操作系统底层中信号量不可用,也可以通过其他信号原语像条件变量或互锁来模拟。

信息传递的实现使用一种简单机制,用一种称为“邮箱”的抽象方法。邮箱做两种操作:邮寄和提取。邮寄操作不会阻塞进程;邮寄到邮箱的消息由操作系统模拟层排入队列直到另一个进程来提取它们。即使操作系统底层对邮箱机制不支持,也容易用信号量实现。

6 缓冲和存储管理

通讯系统中的存储和缓冲管理必须能够适应大小变化的缓冲区,从几百字节的包含完全大小TCP段的缓冲区到仅仅包含几个字节的短的ICMP回报。而且,为了避免拷贝它应当尽可能让缓冲区的数据内容驻留在内存中,网络子系统不管理像应用存储或ROM这样的内存。

6.1包缓冲器-pbufs

Pbuf在lwIP的内部表示一包,也是为了最小限度的使用栈这一特殊需要而设计。 Pbufs类似于用于BSD实现的mbufs。 pbuf结构既支持分配动态内存来保存包内容,也支持把包数据存储在静态存储区。Pbufs能在一张列表中一起被连在一起,称为一个pbuf链,这样一个包可以跨越若干个pbufs。

Pbufs具有三种类型,PBUF RAM,PBUF ROM,和PBUF POOL。图1中pbuf描绘了PBUF RAM类型,和储存的被pbuf子系统管理的数据包。图2中的pbuf是被链在一起的pbuf的一个例子,在其中链的第一个pbuf具有PBUF RAM类型(where the first pbufin the chain is of the PBUF RAM type),而第二个具有PBUF ROM类型,这意味着它具有不被pbuf系统管理的存储数据。第三种类型的pbuf ,PBUF POOL如图3所示,包括从共有的固定大小的pbufs分配的固定大小的pbufs (consists of fixed size pbufs allocated from a pool of fixedsize pbufs.)。一个pbuf链可能包括多重类型的pbufs。

三种类型有不同的使用。 PBUF_POOL主要被网络设备驱动程序使用,因为对操作系统来说分配单一的pbuf速度较快并且适合用于中断管理(suitable foruse in an interrupt handler)。当应用程序发送位于被应用程序管理的存储区的数据时,PBUF_ROM被使用。在pbuf被移交到TCP/IP 栈后,数据不能修改,因此这一pbuf类型,这类型主要用于数据位于ROM时(因此名称为PBUF_ROM )。PBUF_ROM pbuf中的数据可能会用到的头存储在PBUF_RAM pbuf中,它链接在PBUF_ROM pbuf的前面,如图2所示。

当应用程序发送动态地产生的数据时,PBUF_RAM类型的Pbufs也被使用。 在这种情况下,pbuf系统不光为应用数据分配存储空间,也为将要发送的数据的报头准备空间。如图1所示。 pbuf系统不能预先知道为将要发送的数据准备什么样的报头,并且假定最坏的情况。报头大小在编译时可动态配置。

实质上,进入pbufs的是PBUF_POOL类型,离开pbufs的是PBUF_ROM或PBUF_RAM类型。

pbuf的内部的结构如图1~3。 pbuf结构包括两个指针,两长度域,一个flags域,和一参考计数。pbuf链中next域是一个指向下一个pbuf的指针。Payload指针指向pbuf中的数据的起始位置。len域包含pbuf的数据内容的长度。Tot_len域包含当前的pbuf的长度和在pbuf链中接下来的pbufs的所有len领域的总数。换句话说,tot_len域是len域和pbuf链中的随后的pbuf中的tot_len域的值的总和。flags域表明pbuf的类型,而ref领域包含一参考计数。 Next和payload 域是内部指针和依赖于处理器体系结构的数据大小。两个长度域为16位无符号整形,flags和ref 域均为4bit宽。pbuf结构整个的大小取决于所使用的处理器体系结构中一个指针的大小及可能的最小alignment的大小。 在带有32位指针和4个字节alignment的体系结构,整个的大小为16字节,16位指针和1个字节alignment的体系结构上,大小是9个字节。

pbuf模块为操纵pbufs提供了函数。函数pbuf_alloc() 完成分配一个pbuf的任务,它能够分配上面所说的三种pbuf中的任何一种。pbuf_ref()增加参考计数。 pbuf_free()完成释放分配的工作,它首先减少pbuf的参考计数。 如果参考计数到达零表示pbuf已经被释放。 函数pbuf_realloc()收缩pbuf使它刚好能够包含数据大小。 pbuf_header()调整payload 指针和长

度域,以便对pbuf中的数据的报头进行预先估计。 buf_chain() 和pbuf_dechain()用于用链接pbufs。

6.2内存管理

支持pbuf调度的存储管理非常简单。它处理内存中连续区域的分配和释放,可以紧缩一个预先分配的内存块。内存管理器使用系统中总内存的专用部分,这确保网络系统不会使用所有可利用内存,而且如果网络系统用了所有它自己的内存其他程序的操作也不会影响它。

在内部,内存管理通过将一种小的结构放置在每一被分配的内存块的顶端上来追踪分配的内存。这个结构(图4)中设置两个指针指向内存中下一个和前一个分配块,还有一个used标志用来指示这个分配块是否已经被分配。

通过搜索一个未使用的内存块来分配内存,这个内存块对于请求分配来说足够大。使用最先适用原则,因此第一块被使用的内存足够大。当一个分配块释放时,used标志被设为0。为了防止碎片,检测下一个和上一个分配块的used标志,如果它们还没被使用,几个块合并成一个大未使用块。

7网络接口

硬件设备驱动程序中,lwIP用一个类似于BSD的网络接口结构来描述物理硬件。 网络接口结构如图5所示。通过next指针,网络接口被连成一个全局链表(global linked list)。

每个网络接口有一个名字,存储在图5中的name字段。这个两个字符的名字识别用于网络接口中的设备驱动类型,而且当接口在运行时由人为操作来配置。这个名字由设备驱动设置,应当映射由网络接口表示的硬件类型。例如,蓝牙驱动网络接口可能使用名字btd,而IEEE802.11b WLAN硬件可能使用名字wl。由于这些名字不必是唯一的,num字段用来区分同类设备中的不同的网络接口。

当发送和接收包时,三个IP地址ip_addr,netmask和gw由IP层使用,它们的用途在下一节

叙述。给网络接口配置多于一个IP地址是不允许的,一个网络接口应当为每一个IP地址创建。

当包接收到时,设备驱动应当调用input指针指向的函数。

网络接口通过output指针连接到设备驱动。这个指针指向设备驱动中的一个函数,它在物理网络上传送一个包,当一个包被发送时它由IP层调用。这个字段由设备驱动初始化函数填充。output函数的第三个参数ipaddr是主机的IP地址,它可以接收实际链路层的帧。它不应和IP包的目的地址相同。特别地,当发送一个IP包到不在本地网络的主机时,链路层帧被发送到网络

上一个路由。这种情况,给output函数的IP地址将是路由的IP地址。

最后,state指针指向设备驱动中网络接口的特定状态,由设备驱动设置。

8 IP处理

lwIP仅仅实现IP最基本的功能,它可以发送,接收和转发包,但不能发送或接收分割的IP 包,也不能处理带IP选项的包。对于大多数应用来说这不会引起任何问题。

8.1接收包

对于接收的IP若干包,处理从ip_input( )函数被设备驱动程序调用开始。在这里,初始化工作将检查IP版本,同时确定报头长度,还会计算和检查报头checksum域。期望的情况是,自从Proxy服务器重组所有碎片(fragmented)包以来,堆栈就再没有收到碎片(fragments),这样任何IP碎片的包都会被默默的丢弃。带有ip选项的包同样会被指定为由代理处理,并因此被丢掉。

接下来,函数通过网络接口的IP地址检验目的地址以确定包是否去往主机。网络接口已在链表中排序,可以线性查找。网络接口的序号指定为是小的号,因为比线性查找更巧妙的查找方法还没实现。

如果接收的包是主机指定的包,将使用protocol域来决定该包应该传给哪个更高层协议。

8.2发送包

一个要发送的包由函数ip_output( )处理,它使用函数ip_route( )寻找适当的网络接口来上传包。 当时发送包的网络接口被确定后,包被传递到ip_output_if()函数,该函数把发送网络接口作为一个函数自变量。 在这里,所有IP报头域被填补并且IP报头checksum被计算。 IP 包的源和目的地址作为变量传递给ip_output_if()函数。源地址可能被略去(left out),然而,在这种情况下要发送的网络接口的IP地址将被用作包的来源IP地址。

ip_route()函数通过线性查找网络接口列表找到适合的网络接口。在查找IP包的目的IP地址期间,用网络接口的网络掩码进行掩码。如果目的地址等于经掩码的接口IP地址,则选择这个接口。如果找不到匹配的,则使用缺省网络接口。缺省网络接口由人工操作在启动时或运行时配置。如果缺省接口的网络地址和目的IP地址不匹配,则选择网络接口结构中的gw字段作为链路层帧的目的IP地址。(注意这各情况下IP包的目的地址和链路层帧的IP地址是不同的。)路由的原始形式忽略了这个事实:一个网络可能有许多路由器依附它。而工作时,对于一般情况下,一个本地网络只有一个路由器。

因为运输层协议UDP和TCP在计算运输层校验和时需要有目的IP地址,所以在包传给IP层前外发网络接口在某些情况下必须已确定。这可让运输层函数直接调用ip_route()函数完成,因为在包到达IP层时外发网络接口已经知道,没必要再查找网络接口列表。而是那些协议直接调用ip_output_if()函数。由于这个函数把网络接口作为参数,可避免外发接口的查找。

注:运行期间lwIP的手工配置要有一个能配置栈的应用程序,lwIP中不包含这样的程序。

8.3转交包

如果没有网络接口的IP地址和传进包的目的地址相同,这个包应当转发。这由函数

ip_forward()完成。在这里,TTL字段减小,如果变为零,则ICMP错误信息被发送到IP包原始发送器并丢弃这个包。由于IP头被改变,有必要调整IP头校验和。然而不必重算完整的校验和,因为可用简单的算术来调整原始的IP校验和[MK90,Rij94]。最后,包被转发到适当的网络接口。用来寻找合适网络接口的算法和发送IP包时使用的一样。

8.4 ICMP处理

ICMP处理是相当简单的。 由ip_input()收到的ICMP包被移交到icmp_input(),它解析ICMP 报头并且进行适当的处理。 一些ICMP信息被传递到更高协议层并被传输层的一些特殊函数处理(Some ICMP messages are passed to upper layer protocols and those are taken care of by special functions in the transport layer)。ICMP目的地不能到达的信息能被运输层协议发送,尤其是UDP,和函数icmp_dest_unreach( )。

使用ICMP ECHO信息来探测网络被广泛应用,因此对ICMPECHO进行了性能优化。 实际处理在函数icmp_input( )中发生,包括对接收的包的目的和源地址进行交换,改变ICMP类型为echo reply并且调整ICMP checksum。 然后包回送到IP层等待传送。

9 UDP 处理

UDP 是一个简单的协议,用来完成不同处理过程间的包分离。每一个UDP话路(session)的状态都被保留在一个PCB 结构中,如图7所示 。UDP PCBs 保存在一个链表中,当UDP datagram 到达,则搜索该链表并进行匹配。

UDP PCB 结构中包含一个指向全局UDP PCB链表中的下一个 PCB的指针。UDP话路(session)由IP地址和端口号来定义,并且被存放在local_ip, dest_ip,local_port,dest_port域中。 Flags域指出这一话路(session)将使用什么样的UDP 校验和策略。这可能既没关掉UDP checksumming 完全,或者使用UDP 轻便在哪个检验数字盖住只数据报的部分。This can be either to switch UDP checksumming off completely, or to use UDP Lite [LDP99] in which the checksum covers only parts of the datagram. If UDP Lite is used, the chksum len field specifies how much of the datagram that should be checksummed.

当接收到由PCB标明的session中的datagram时,最后二个参数 recv 和recv_arg将被使用。当接收到datagram时,recv所指向的函数被调用。

由于UDP较为简单,输入和输出处理也较简单,如图8所示。

当收到一个UDP datagram 时,IP层调用udp_input()函数。这里,如果session应该使用checksumming,UDP checksum将被检查同时datagram被分离。当发现相应的UDP PCB,recv函数被调用。

10 TCP 处理

TCP 为传输层协议它为应用层提供可靠的二进制数据流服务。 TCP协议比这里描述的其它协议都要复杂, 并且TCP 代码占lwIP总代码的50%。

10.1 总述

基本TCP 处理(图9) 被划分成六个函数;函数tcp_input()、tcp_process()、tcp_receive()与TCP 输入处理有关, tcp_write()、 tcp_enqueue()、tcp_output() 对输出进行处理。

当应用程序想要发送TCP 数据, 函数tcp_write()将被调用。 函数tcp_write() 将控制权交给tcp_enqueue(),该函数将数据分成合适大小的TCP段(如果必要),并放进发送队列。 接下来函数tcp_output()将检查数据是否可以发送。也就是说,如果接收器的窗口有足够的空间并且

拥塞窗口足够大,则使用ip_route()和ip_output_if() 两个函数发送数据 。

当ip_input()对IP报头进行检验且把TCP段移交给tcp_input()函数后,输入处理开始。 在该函数中将进行初始检验(也就是 ,checksumming 和TCP 剖析析)并决定该段属于哪个TCP连接。该段于是由tcp_process()处理,它实现TCP状态机和其他任何必须的状态转换。 。如果一个连接处于从网络接收数据的状态,函数tcp_receive() 将被调用。 如果那样, tcp_receive() 将把段上传给应用程序。 如果段构成未应答数据(先前放入缓冲区的)的ACK, 数据将从缓冲被移走并且收回该存储区。 同样, 如果接收到请求数据的ACK,接收者可能希望接收更多的数据,这时tcp_output() 将被调用。

10.2 数据结构

由于小型嵌入式系统内存的限制,LWIP所使用的数据结构被故意缩小。 这是在数据结构复杂度与使用数据结构的代码的复杂度之间的一个折衷。这样就因为要保证数据结构的小巧而使代码复杂性增加。

TCP PCB相当大,如图10 。 因为TCP 连接在处于监听(listen)和时间等待(TIME-WAIT)状态时比处于其他状态的连接需要保留较少状态信息,对于这些连接使用了一种更小的PCB 数据结构。 这种数据结构镶嵌在完整的PCB 结构中, 在PCB 结构中的排列持续如图10, 因此有些笨拙。

TCP PCBs 被保留在一份链表中, 并且next指针把PCB列表连接在一起。 状态变量包含当前连接的TCP状态。 其次, 辨认连接的IP 地址和端口号被保存。 mss 变量保存连接所允许的最大段大小。

当接受数据时,rcv_nxt 和rcv_wnd域被使用。 rcv_nxt域包含期望从遥端的下个顺序编号(contains the next sequence number expected from the remote end),因而当发送ACKs 到远程主机时被使用。接收器的窗口被保留在rcv_wnd中,并且在将要发出的TCP 段中被告知。 tmr 被作为定时器使用,在经过一特定时间后连接应该被取消, 譬如连接在TIME-WAIT 状态。 连接所允许的最大段大小被存放在mss域中。 Flags域 包含连接的附加状态信息, 譬如连接是否为快速恢复或被延迟的ACK是否被发送。

域rttest, rtseq, sa, 和sv 被使用为round-trip时间估计。 用于估计的段顺序号存储在rtseq ,该段被发送的时间存放在rttest。 平均round-trip时间 和round-trip时间变化分别存放在sa和sv 。 这些变量被用来计算存放在rto域中的转播暂停(retransmission time-out)。 二个域lastack 和dupacks 被用来实现快速转播和快速重发。 lastack包含由最后接受到的ACK 应答的顺序编号,dupacks 对接收到多少关于存储在lastack的顺序编号的ACK 进行计数。 当前连接的阻塞窗口被存放在cwnd域,并且缓慢的起动门限被保留在ssthresh 。

六个域snd_ack、 snd_nxt、snd_wnd、snd_wl1、snd_wl2 和snd_lbb 在发送数据时使用。 由接收器应答的最高的顺序编号被存放在snd_ack, 并且下个被发送的顺序编号保存在snd_nxt 。接收器的广告窗口(advertised window)保存在snd_wnd,两域 snd_wl1 和snd_wl2在更新snd_wn 时使用。 Snd_lbb域包含发送队列最后字节的顺序编号。

当传递接受的数据到应用层时将使用函数指针recv 和recv_arg。 三个队列unsent, unacked 和ooseq当发送和接受数据时被使用。 已经从应用接收但未被发送的数据由队列unsent进行排队,已发送但还没有被远程主机应答(acknowledged)的数据由unacked 存储。 接收的序列外

面的数据由ooseq进行缓冲。

表11中的Tcp_seg 结构是TCP 段的内部表示方法。 这个结构由一个next指针开始,该指针用于连接排队段。 len域包含段的长度。 这意味着一个数据段的len域将包含段中数据的长度, 具有SYN或FIN标志的空段的len被设置为1 。 pbuf结构类型指针p 是包含实际段、tcphdr、指向TCP头的数据指针和数据段的缓冲。 分别的,对于将要外发的段, rtime域被用于该段的转播暂停。 因为接收的段不会需要被转播, 对于接收段来说这个域并不需要并且也不为该域分配内存。

10.3 顺序编好计算(Sequence number calculations)

用于枚举TCP二进制数据流的TCP顺序编号为无符号32位数据, 因此其范围是 。 因为在TCP 连接中要发送字节的数量可能会比32 位组合的数量更多, 顺序编号以232为模数进行计算 。 这意味着, 普通的比较操作符无法被TCP 顺序编号使用。 修改过的比较操作符, 叫做

< seq 和>

seq

, 由下面关系定义:

这里s 和t 是TCP 顺序编号。 比较操作符≦≧也等效地被定义。 比较操作符作为C 宏指令被定义在标头文件。

10.4 队列和发送数据

将要发送的数据被划分成适当的大小的大块并tcp_enqueue()指定顺序编号。这里, 数据被打包进pbufs 结构并附加进tcp_seg 结构。 在pbuf内,TCP头被建立,并且除应答数字, ackno 和广播窗口, wnd以外的所有域被填充。 这些域在段排队时可以被改变,并由tcp_output()进行设置,该函数完成段的实际传输。 在段被建立之后, 他们被送往PCB里的unsent列表进行排队 。 函数tcp_enqueue()设法用最大段大小的数据填装各段直到在unsent 队列的末端发现段under-full, 该段使用pbuf chaining functionality功能被添附以新数据。

在tcp_enqueue() 格式化和排队了段之后, tcp_output()函数被调用。它检查在当前的窗口中是否还有空间来存储更多的数据。当前窗口的数值是通过窗口数据拥挤的最大量和接收窗口的广播。(It checks if there is any room in the current window for any more data. The current window is computed by taking the maximum of the congestion window and the advertised receiver's window)。 其次, 它填装由tcp_enqueue() 未填装的TCP头的域,并且使用ip_route()和 ip_output_if()传送段。 在段被放入传输后unacked表后,停留直到该段的ACK被接收到。 当段放入unacked 表的同时, 如在10.8部分所描述同时也为重发计时。 当段需重发时原来的TCP、IP头被保留,只需对TCP 头做少量变化。 TCP头的ackno 和wnd域被设置为当前值,因为在段的原始传输和重发期间我们可能接收了数据。 这只改变报头里的二个16 位字和整体TCP checksum不必要重新计算,因为简单的算术[ Rij94 ] 可以用来更新checksum。当段最初被传送时 ,IP 层已经增加了IP 头,并且没有理由改变它。 因而重发不要求IP头的 checksum.的任何重发计算。

Silly Window Syndrome [Cla82b] (SWS)综合症状[ Cla82b ] (SWS) 是一个可能导致非常坏的性能的TCP 现象。当TCP 接收器广播一个小窗口并且TCP 发送者立刻发送数据填装窗口时SWS 发生。 当这小段被应答窗口再次打开并且发送者将再发送小段填装窗口。 这导致TCP 数据流包括许多非常小段的情况发生。 为了避免SWS 发送者和接收者都必须设法避免这个情况。 接收者不能给小窗口更新做广播并且当只提供一个小窗口时发送者不能送小段。

在lwIP, SWS 在发送端自然地被避免,因为TCP 段被建立和排队时没有做广播接收器窗口的应答。 在大数据量传输时队列将包括最大尺寸大小的段。 这意味着如果TCP 接收器广播一个小窗口, 发送者不会送队列中的第一个段,因为它比广播的窗口大。相反, 它将等待直到窗口是足够大以至于能容纳最大大小的段。 当作为TCP 接收器时, lwIP 不会给比连接的最大段大小小的接收器的窗口做广播。

10.5 接收段

10.5.1 复用

当TCP 段到达tcp_input() 函数时, 他们将在TCP PCBs之间被解析(demultiplexed) 。 解析的关键是来源和目的地IP 地址和TCP 端口数。 当解析段的时候有种二类型的PCBs必须突出的(distinguished):那些对应于开放连接的和那些对应于连接是半的打开。 半开放连接是指那些处于监听状态和只有本地TCP端口号被指定且本地IP 地址为任意值的连接, 但是开放连接有指定的两个IP 地址和两个端口号。

许多TCP 的实现, 譬如早期的BSD 实现, 使用具有单一入口缓存的PCBs链表技术。 在这之后基本理论是, 多数的TCP 连接构成批量传送,它典型地显示一个大批量的位置[Mog92], 造成一个高缓冲命中比率。 另一个方案包括两个具有单一入口的缓冲器, 一个为对应于被送的最后的包的PCB,一个为最后接受的包的PCB [ PP93 ] 。 通过移动最近被使用的PCB 到列表的前端,一份供选择的方案可以实施。 两种方法 [ MD92 ]都胜过单一入口的缓冲方案。

在lwIP, 每当PCB 匹配被发现,解析段时, PCB都将被移动向PCBs 列表的前端。 但是,在听状态的连接所用的PCBs并不被移动, 因为这种连接并不期望接收段。

10.5.2 接收数据

对接收到的段的实际处理是在函数tcp_receive()里进行的。 段的应答数字与在unacked队列中的段比较。 如果应答数字比段在unacked 队列的顺序编号高, 该段从队列中被移走并且为段分配的内存也被收回。

如果接收的段的顺序编号比PCB中rcv_nxt变量高,该段将脱离序列。序列外的段在PCB中的ooseq 队列进行排队。 如果接收的段的顺序编号与rcv_nxt 是相等的, 通过调用在PCB中的函数recv,段被转交给上层,并且关于接收段的长度的rcv_nxt域被加进来。 因为在序列内的段的接收也许意味着先前被接受的在序列外的段是被期望的下一个段, ooseq 队列被检查。 如果它包含顺序编号与rcv_nxt顺序编号相等的段, 通过调用函数recv该段被转交给应用程序并且更新rcv_nxt。 这个过程持续到ooseq 队列为空或ooseq的下一个段脱离序列。

10.6 接受新的连接(Accepting new connections)

处于听状态,也就是说已经被动地开放的TCP 连接,, 已经准备从远程主机接受新的连接。为了那些连接,必须建立新的TCP PCB ,并传递给打开初始听连接的应用程序。在lwIP里, 这个步骤是通过使用回调函数来完成,这个函数当一个新的连接被建立时被调用。

当处于听状态的连接接收一个具有SYN标志的TCP段时(When a connection in the LISTEN state receives a TCP segment with the SYN flag set),一个新的连接就建立了,并且一个带有SYN和ACK的标志的段被送出以回应那个SYN段。这个时候这个连接就进入了SYN-RCVD状态,并等待发送的SYN段的应答,当应答信息收到后,这个连接就进入了ESTABLISHED阶段,接受函数(在PCB中的accept域如图10)会被调用 。

10.7 快速转发(Fast retransmit)

IWIP里拥有快速转发和快速恢复的功能。该功能通过明确最后被应答的顺序编号实现的。如果收到同一顺序编号的另外个应答信号,TCP PCB 里的 dupacks 计数建立。当DUPACKS到3的时候,

在未应答序列中的第一个段将要被重新送出,快速恢复被初始化。快速恢复的步骤完成以后的动作 [ASP99]:无论什么时候收到一个新数据的应答信号,dupacks计数都复位为0。

10.8 定时器(Timers)

和在BSD TCP 中实现一样,lwIP 使用二个周期性定时器,周期分别为500ms和200ms。 这二个定时器又被用来实现更加复杂的逻辑定时器,如转发定时器、TIME-WAIT 定时器和delayed ACK 定时器。

fine grained timer定时器,如果有应该被发送的任一被延迟的ACKs,tcp_timer_fine() 将在定时结束时检查TCP PCB,正如在tcp pcb 结构中的flag域所表明的 (图10) 。 如果delayed ACK 标志被设置, 空的TCP 应答段被发送并且标志被清除。

coarse grained timer定时器,在tcp_timer_coarse()里实现,并且扫描PCB 列表。 对于任何一个PCB, 未应答段列表(在tcp_seg 结构中的unacked指针,如表11), 被否认(is traversed), 并且rtime 变量被增加。 如果rtime 比当前的转发暂停时间(由PCB结构中的rto 变量给出)大, 段被转发并且转发暂停被加倍。只有在拥塞窗口和广播接收器的窗口的值允许的情况下段才被转发。 在转发以后, 拥塞窗口被设置成一最大段大小,slow start threshold被设置为有效的窗口大小的一半,并且slow start在连接中被初始化。

对于在TIME-WAIT状态的连接, coarse grained timer定时器也会在PCB 结构中增加tmr域。当这个定时器到达2×MSL门限,连接被取消。 coarse grained timer定时器同时也增加一个全局TCP 时钟, tcp_ticks。 这个时钟用来估计round-trip时间转播暂停(time-out)。

10.9 Round-trip 时间估计(Round-trip time estimation)

round-trip时间估计是TCP 的一个重要部份,因为估计的round-trip时间被用来确定适当的转发暂停。 在lwIP, round-trip时间测量的实现与BSD 相似。每一次round-trip往返 round-trip 时间就被测量一次,并且使用smoothing函数(在[ Jac88 ]中描述) 对适当的转发暂停进行计算。

TCP PCB的变量rtseq 保存着往返时间被测量的段的顺序编号。 PCB中的Rttest变量保存着当段第一次被传送时tcp_ticks的值。 当一个顺序编号等于或大于rtseq的ACK被接收到时,round-trip时间通过从tcp_ticks减去rttest被测量。 如果转发发生在round-trip时间测量期间,测量不被采取。

10.10拥塞控制(Congestion control)

拥塞控制的实现是出乎意料的简单,仅仅包括几行代码。 当一个新数据的ACK被拥塞窗口接受, cwnd, 被mss2/cwnd 增加或被一最大段大小增加, 取决于连接是缓慢起动还是拥塞避免(depending on whether the connection is in slow start or congestion avoidance)。 当发送数据时,接收器的广播窗口和拥塞窗口的最小值用来确定每个窗口能够发送数据的多少。

11栈接口(Interfacing the stack)

使用由TCP/IP协议栈提供的服务有二种方式;一种是直接调用在TCP 和UDP 模块中的函数,另一种就是使用lwIP API。

TCP 和UDP 模块提供一个网络服务的基本接口。 该接口基于回调,因此使用它的应用程序可能因此不必以连续方式进行操作。 这使应用程序的编程更加困难并且应用代码更难理解。 为了接受数据,应用程序登记一个协议栈的回调函数。 回调函数同一个特定的连接联系在一起,当该连接的包到达时, 回调函数被协议栈调用。

此外, 与TCP 和UDP 模块直接接口地应用程序,必须(至少部份地)保留在像TCP/IP协议栈这样的处理过程中。 这归结于回调函数无法横跨处理界限调用的事实。 这既有好处也有不足。好处是应用程序和TCP/IP 协议是在同一个处理过程中, 发送和接收包时不用上下文切换。 主要不足是,在任何长的连续计算过程中应用程序无法介入自己,因为TCP/IP 处理无法与计算平行发生, 因而丧失通讯性能。 通过把应用程序分成两部分可以克服这一缺点, 一部分应付通信一部分应付计算。 负责通讯的部分驻留在TCP/IP 过程中,负责计算的部份将是一个单独的过

程。 将要在下一节介绍的lwIP API 提供了一个结构化的方式,用这样方式来划分应用程序。

TCP/IP的处理不应该与其他运算并行处理,这样将会降低通讯的性能,所以我们把应用程序分解为两个部分,一部分专注于处理通讯,另一部分做其他的运算。通讯的部分将包含在TCP/IP 进层中,而其他的繁杂运算则作为一个独立的进程。下一节将介绍LWIP 的 API 提供的分开的结构来应用的办法。

12应用程序接口 API

作为高级别的BSD socket API,它是不适宜用于一个最小限度的TCP/IP执行的.特别BSD SOCKETS要求在TCP/IP协议栈中将要发送的数据从应用程序拷贝到内部缓存.需要拷贝数据的原因是通常TCP/IP协议栈和应用程序一般都处在不同的保护领域.大多数时候应用程序是位于户进程而TCP/IP却在操作系统内核中。通过避免这额外的拷贝就可以大幅度的提高API的性能[ABM95]。同样地,这样的拷贝需要分配额外的内存,每个信息包都浪费了双倍的内存。

LWIP API是专为LWIP设计并利用LWIP的内部结构达成效果,LWIP API 和 BSD API非常类似,但操作相对低级。LWIP API不需要TCP/IP和应用程序之间的相互拷贝数据,应用程序可以巧妙的直接处理内部缓存。

由于BSD SOCKET API 很容易理解且已经有很多人为它写过应用程序,LWIP API很有必要有与BSD SOCKET 的兼容层面。17节中介绍了如何用LWIP API 去重写BSD SOCKET 函数,15节中有LWIP API 的一个参考手册。

12.1 基本概念

从应用程序去看,BSD SOCKET API的数据处理都是在一个连续的内存区域完成的。这是因为应用程序通常也是在这样的一个连续大内存块中完成数据处理的。 LWIP采用这样的机制是没有优势的,因为IWIP通常处理的数据缓存都被分割成了小的内存块。在通过应用程序前这些数据就会不得不要复制到一个连续的内存区,这将浪费双方的处理时间和内存,因此LWIP API允许应用程序巧妙地直接处理分离的缓存去避免额外的拷贝。

LWIP API 尽管非常类似 BSD SOCKET API,可是却有着值得注意的不同的地方,应用程序使用BSD SOCKET API 时候不需要知道普通文件和网络连接之间的差别,但使用LWIP API的时候就必须要知道确实在使用网络连接。

网络数据被接收到分离的内存块的时候是以缓存的形式出现的,由于很多应用程序都希望在一个连续的内存区域处理数据,这就要有个函数去把这些缓存碎片复制到连续的内存空间中。

发送出去的网络数据根据是TCP连接还是UDP是不同地处理的。在TCP连接时,数据通过一个指向连续内存区的指针发送,TCP/IP协议为传送区分适当大小的数据包和数据队列。在发送UDP数据的时候,应用程序将明确地分配缓存并填充数据,在输出函数被调用的时候由TCP/IP 协议栈马上发送出去。

12.2 API的执行

API是分做两个部分执行的,在图12中我们可以看到,一部分位于在TCP/IP的进程模块中,一部分当作连接库在应用程序中执行,这两部分的API通过由操作系统仿真层提供的进程间通讯(IPC)传达信息.当前使用的IPC机制有以下3种:

共享内存

消息

信号

当操作系统支持这些IPC类型的时候,并不意味着他它们得到了操作系统的最底层的

支持,因为操作系统并不是一开始就支持它们,只是操作系统的的仿真层仿真了它们。

图示12 . 分开为两部分的API执行

一般的设计原理都是尽可能地提高TCP/IP进程里的API的工作能力更胜于应用程序里API.这很重要,因为大部分的进程都用TCP/IP进程进行它们的TCP/IP通讯。遵循API部分的代码足迹,和应用程序连接的这部分并不是很重要.这些代码可以在进程间共享,即使操作系统并不支持共享连接库。这些代码还可以保存在ROM中,嵌入系统一般尽管处理能力不高却拥有很大的ROM空间。

缓存管理器位于API执行库里,buffer在应用程序进程中被建立,复制和分配.应用程序和TCP/IP进程间使用共享内存来传递buffer,应用程序中用于通讯的buffer数据类型是一种提取于pbuf的类型。

buffer传输引用到的内存,和分配的内存不同,它是可以利用共享内存的.所以可以进程间共享引用的内存.运行LWIP的嵌入式操作系统一般有意不做任何形式的内存保护,所以不会有问题。

操作网络连接的函数位于TCP/IP进程的API中.应用程序的API函数会通过一个简单的通讯协议传递一个信息个TCP/IP进程的API,这信息包含操作的类型,和操作的相关变量.这个操作由TCP/IP的API传输后用信息给应用程序一个返回值。

13 代码统计分析

本节分析了LWIP的源代码行的数量和编译后结果大小的关系.代码被两种不同的处理器结构编译:

Intel Pentium III处理器,在FreeBSD 4.1下面用GCC 2.95.2 编译,开启了编译优化选项。 6520处理器[Nab, Zak83].用cc65 2.5.5 [vB] 编译,开启了编译优化选项。

Intel x86 用了7个32位寄存器和32位指针。 6502主要用于嵌入系统,具有一个8位累加器两个8位索引寄存器和16位指针。

13.1 代码行

表1

图示13 代码行比例

表1介绍了LWIP代码行的数量图示13显示了各部分的代码比例。"sunpport functions"类别包括了缓存和内存管理器还有校验和处理函数,在事实配置支持的情况下,校验和函数应该用普通C执行而不用处理器特殊的运算法则。"API"类别包括了应用程序的API和TCP/IP协议栈的API.操作系统的仿真层在这里没有分析显示,因为它在操作系统的底层而且大小有很大不定性,在这里就没必要比较它了。

作为比较,这里忽略了所有的注释,空白行和头文件.我们可以看到TCP这一块比其它的执行协议都大得多,,而API和support functions 加起来就和TCP差不多大。

13.2 目标结果代码大小

表2. LWIP在Intel x86下编译后代码的大小

MT明泰_读卡器_API接口函数库使用说明书

API接口函数库使用说明 部文件:V1.0.20 发布时间:2015-04-29

版本更新记录

目录 API接口函数库使用说明 (1) 1. 文档概述 (6) 1.1. 文档围 (6) 1.2. 面向对象 (6) 1.3. 参考资料 (6) 2. 函数库介绍 (6) 2.1. 功能 (6) 2.2. 性能 (7) 3. 运行环境 (7) 3.1. 硬设备 (7) 3.2. 软件的运行平台 (7) 3.3. 函数调用方法 (8) 3.3.1. Delphi调用32位动态库的方法 (8) 3.3.2. VB调用32位动态库的方法 (9) 3.3.3. VC调用32位动态库的方法 (11) 4. API介绍 (11) 4.1. 函数调用流程 (11) 4.1.1. 非接触式存储卡API调用流程 (11) 4.1.2. 非接触式CPU卡片API调用流程 (12) 4.1.3. 接触式CPU卡片API调用流程 (12) 4.1.4. 接触式存储卡片API调用流程 (12) 4.1.5. API调用流程 (12) 4.1.6. 函数操作结果信息表 (16) 4.2. 设备操作函数组 (19) 4.2.1 打开读写器device_open (19) 4.2.2 关闭读写器device_close (19) 4.2.3 判断设备通讯类型device_gettype (19) 4.2.4 设置通讯波特率device_setbaud (20) 4.2.5 获取读写器版本信息device_version (20)

4.2.6 读写器蜂鸣device_beep (21) 4.2.7 LED灯控制 device_ledctrl (21) 4.2.8 获取读写器生产序列号 device_readsnr (22) 4.2.9 获取设备状态 get_device_status (22) 4.2.10 读取读卡器的EEPROM (23) 4.2.11更新读卡器的EEPROM (23) 4.2.12 复位串口配置信息 ReSetupComm (24) 4.2.13 读卡器软复位 device_reset (24) 4.2.14 获取设备状态扩展 get_device_statusEx (25) 4.2.15 获取非接触式CPU卡卡片状态 dev_cardstate (25) 4.2.16 获取接触式CPU卡到位状态 ICC_GetStatus (26) 4.2.17 读EMID号Dev_GetEMID (26) 4.3 接触式卡片操作函数 (27) 4.3.1 判断接触式卡片状态sam_slt_getstate (27) 4.3.2 接触式卡片上电复位sam_slt_reset (28) 4.3.3 接触式卡设置复位波特率sam_slt_reset_baud (28) 4.3.4 接触式卡片下电sam_slt_powerdown (29) 4.4. 非接触 CPU 卡函数 (29) 4.4.1 激活非接触式卡open_card (29) 4.4.2 设置非接触式卡片为halt状态 rf_halt (30) 4.4.3 应用层传输命令card_APDU (31) 4.5 非接触式存储卡操作函数 (31) 4.5.1 激活非接触式存储卡rf_card (31) 4.5.2 非接触式存储卡认证扇区 rf_authentication (33) 4.5.3 非接触式存储卡读数据rf_read (33) 4.5.4 非接触式存储卡写数据rf_write (34) 4.5.5 非接触式存储卡读值块rf_readval (34) 4.5.6 非接触式存储卡写值块rf_initval (35) 4.5.7 非接触式存储卡加值rf_increment (35) 4.5.8 非接触式存储卡减值rf_decrement (36) 4.5.9 非接触式存储卡值传送 rf_transfer (36) 4.6 二代操作函数 (37) 4.6.1 卡操作指令-读卡IDCard_Read (37) 4.6.2 卡操作指令-读卡IDCard_ReadCard (39) 4.6.3卡操作指令根据索引获取数据IDCard_GetCardInfo (40) 4.6.4 获取二代证模块ID IDCard_GetModeID (40) 4.6.5 读卡模块扩展一IDCard_ReadCard_Extra (41) 4.6.6 设置二代证照片存储路径 IDCard_SetPhotoPath (41) 4.6.7 设置二代证照片名字 IDCard_SetPhotoName (42) 4.6.8 读二代证信息扩展二 IDCard_ReadCard_Ex (42) 4.6.9 删除所有二代证照片文件delete_all_photofile (44) 4.6.10 获取卡ID号IDCard_Read_IDNUM (44) 4.6.11 获取卡IDCard_Name (45) 4.6.12 获取卡性别IDCard_Sex (45)

ODBC的接口函数

ODBC的接口函数 1.连接到数据源 下面的函数用于连接到数据源: (1)SQLAllocHandle:分配环境、连接、语句或者描述符句柄。(2)SQLConnect:建立与驱动程序或者数据源的连接。访问数据源的连接句柄包含了包括状态、事务申明和错误信息的所有连接信息。(3)SQLDriverConnect:与SQLConnect相似,用来连接到驱动程序或者数据源。但它比SQLConnect支持数据源更多的连接信息,它提供了一个对话框来提示用户设置所有的连接信息以及系统信息表没有定义的数据源。 (4)SQLBrowseConnect:支持一种交互方法来检索或者列出连接数据源所需要的属性和属性值。每次调用函数可以获取一个连接属性字符串,当检索完所有的属性值,就建立起与数据源的连接,并且返回完整的连接字符串,否则提示缺少的连接属性信息,用户根据此信息重新输入连接属性值再次调用此函数进行连接。 2.获取驱动程序和数据源信息 下面的函数用来获取驱动程序和数据源信息: (1)SQLDataSources:能够被调用多次来获取应用程序使用的所有数据源的名字。 (2)SQLDrivers:返回所有安装过的驱动程序清单,包括对它们的描述以及属性关键字。 (3)SQLGetInfo:返回连接的驱动程序和数据源的元信息。

(4)SQLGetFunctions:返回指定的驱动程序是否支持某个特定函数的信息。 (5)SQLGetTypeInfo:返回指定的数据源支持的数据类型的信息。 3.设置或者获取驱动程序属性 下面的函数用来设置或者获取驱动程序属性: (1)SQLSetConnectAttr:设置连接属性值。 (2)SQLGetConnectAttr:返回连接属性值。 (3)SQLSetEnvAttr:设置环境属性值。 (4)SQLGetEnvAttr:返回环境属性值。 (5)SQLSetStmtAttr:设置语句属性值。 (6)SQLGetStmtAttr:返回语句属性值。 4.设置或者获取描述符字段 下面的函数用来设置或者获取描述符字段: (1)SQLGetDescField:返回单个描述符字段的值。 (2)SQLGetDescRec:返回当前描述符记录的多个字段的值。(3)SQLSetDescField:设置单个描述符字段的值。 (4)SQLSetDescRec:设置描述符记录的多个字段。 5.准备SQL语句 下面的函数用来准备SQL语句: (1)SQLPrepare:准备要执行的SQL语句。 (2)SQLBindParameter:在SQL语句中分配参数的缓冲区。 (3)SQLGetCursorName:返回与语句句柄相关的游标名称。

接口使用说明文档

中国移动短信网关 SP端接口使用手册 China Mobile Shot Message Gateway Interface for SP Manual 作者:沈岗 日期:2004年1月 版本:V1.2

一、CMSMIF.CMPPApp 简要说明: 该类采用CMPP协议(V2.0)实现了SP端与移动短信网关的连接处理。 本类中,采用长连接方式与ISMG通讯。通信双方以客户-服务器方式建立TCP连接,用于双方信息的相互提交。当信道上没有数据传输时,通信双方应每隔时间C发送链路检测包以维持此连接,当链路检测包发出超过时间T后未收到响应,立即再发送链路检测包,再连续发送N-1次后仍未得到响应则断开此连接。参数C、T、N可通过属性配置。 消息发送时采用并发方式,即发送一条消息不等待网关回复确认,继续向网关发送短信,这样发送消息速度非常快,完全取决于网关的处理速度及网络速度。为避免消息丢失,同时采用了滑动窗口流量控制,窗口大小可通过属性设置。 消息接收、网络断开等采用事件触发方式,不需应用程序轮询,在此接口基础之上编程方便。 类中运用了多线程技术,如一条线程处理发送网络包,而另一条线程处理从网关上接收网络包,其他还有一些线程处理检测包、网络连接情况监测等,使程序思路明确、执行效率很高、运行非常稳定。 (一)属性 1.ActiveInterval 说明:检测包发送时间间隔,单位:毫秒。默认值为120000,即120秒。为上 述类说明中的C参数。 2.MaxNetworkPackSize 说明:与ISMG通讯时最大网络包大小,单位:字节。默认值为512Byte。 3.MaxRetryTimes 说明:网络超时最大重发次数,单位:次。默认值为3次。为类说明中的N。 4.OverTime 说明:网络包发送超时时间,单位:毫秒,超过此值还未收到回复则重发。默认值 为60000,即60秒。为类说明中的T。 5.QueueLength 说明:网络队列大小,单位:个,默认值为20。为类说明中的滑动窗口大小, 以控制发送流量。 (二)方法 1.ConnectToIsmg 方法说明: 连接到远程短信网关ISMG上,只有连接到远程短信网关上,才可进行短信收发操作。 在本操作中,自动初始化本地Socket,以连接到指定IP服务器的指定端口上。 声明原型:int ConnectToIsmg(string ServerIP,int Port,string SP_ID,string Secret,string SN) 参数说明: ServerIP:远程短信网关服务器的IP地址,如211.138.200.51 Port:远程短信网关服务器的端口号,如7890 SP_ID:企业服务代码

输入法接口函数说明

输入法编程(转贴)(快看) IME输入法编程 第一章Windows9x系统下汉字输入法的基本原理 Windows系统下汉字输入法实际上是将输入的标准ascii字符串按照一定的编码规则转换为汉字或汉字串,进入到目的地。由于应用程序各不相同,用户不可能自己去设计转换程序,因此,汉字输入自然而然落到WINDOWS系统管理中。 一、输入法与系统的关系 键盘事件应用程序 || Windows的USER.EXE | 输入法管理器 | 输入法 系统的键盘事件有windows的user.exe软件接收后,user.exe在将键盘事件传导输入法管理器(Input Method Manager,简称IMM)中,管理器再将键盘事件传到输入法中,输入法根据用户编码字典,翻译键盘事件为对应的汉字(或汉字串),然后再反传到user.exe 中,user.exe再将翻译后的键盘事件传给当前正运行的应用程序,从而完成汉字的输入。 二、汉字输入法的组成 微软Windows9x系统中汉字输入法的名称是"Input Method Editor " ,简称IME,输入法的程序名称为:*.ime,数据文件名称为*.MB,即通常说的输入法编码表(字典). 实际上IME文件是一个动态连接库程序(DLL),它与dll文件没有区别,只是名称不同而已。 一般汉字输入法都由三个窗口组成: 状态窗口(Status Windows)-显示当前的输入法状态(中文还是英文等站环信息); 编码输入窗口(Composition Windows)-显示当前击键情况; 汉字选择窗口(Candidates Windows)-列出当前编码的全部汉字(串),供用户选择或查询。 上述三个窗口由基本的用户接口(User Interface )函数管理着。 现在我们用Dumpbin.exe打开微软提供的拼音输入法(WINDOWS\SYSTEM\WINPY.IME)看看它有什么组成(这里一WINDOWS98为例,并假定windows系统安装在c:盘下):

通达信函数大全使用说明

软件简介: 通达信全部函数及其用法(2011年最新版) (一)行情函数 1)HIGH(H)最高价返回该周期最高价.2)LOW(L)最低价返回该周期最低价.3)CLOSE(C)收盘价返回该周期收盘价.4)VOL(V)成交量(手)返回该周期成交量.5)OPEN (O)开盘价返回该周期开盘价.6)ADVANCE 上涨家数返回该周期上涨家数. (本函数仅对大盘有效)7)DECLINE 下跌家数返回该周期下跌家数. (本函数仅对大盘有效)8)AMOUNT 成交额(元)返回该周期成交额.9)VOLINSTK 持仓量返回期货该周期持仓量.10)QHJSJ 期货结算价返回期货该周期结算价. 11)BUYVOL 外盘(手)返回外盘,即时行情数据 12)SELVOL 外盘(手)返回外盘 13)ISBUYORDER 主动性买单返回当前成交是否为主动性买单.用法: ISBUYORDER,当本笔成交为主动性买盘时,返回1,否则为0 14)DHIGH 不定周期最高价返回该不定周期最高价.15)DOPEN 不定周期开盘价返回该不定周期开盘价.16) DLOW 不定周期最低价返回该不定周期最低价.17)DCLOSE 不定周期收盘价返回该不定周期收盘价.18) DVOL 不定周期成交量价返回该不定周期成交量价.19)NAMELIKE 模糊股票名称返回股票名称是否以参数开头.

用法: if(NAMELIKE('ST'),x,y); 20)CODELIKE 模糊股票代码返回股票代码是否以参数开头. 用法: if(CODELIKE('600'),x,y); 21)INBLOCK 属于某板块返回股票是否属于某板块. 用法: if(INBLOCK('沪深300'),x,y); (二)时间函数 1)PERIOD 周期取得周期类型. 结果从0到11,依次分别是1/5/15/30/60分钟,日/周/月,多分钟,多日,季,年. 2)DATE 日期取得该周期从1900以来的的年月日. 用法: DATE 例如函数返回1000101,表示2000年1月1 日,DATE+19000000后才是真正的日期值 3)TIME 时间取得该周期的时分秒.用法: TIME 函数返回有效值范围为(000000-235959) 4)YEAR 年份取得该周期的年份.5)MONTH 月份取得该周期的月份.用法: 函数返回有效值范围为(1-12) 6)WEEKDAY 星期取得该周期的星期数.用法: WEEKDAY 函数返回有效值范围为(1-7) 7)DAY 日取得该周期的日期.用法: DAY 函数返回有效值范围为(1-31) 8)HOUR 小时取得该周期的小时数.用法: HOUR 函数返回有效值范围为(0-23),对于日线及更长的分析周期值为0

DLL函数接口说明

typedef void __stdcall (*fun_AddResult)(char pDataStr[10][255],double pDataDouble[100]); extern "C" void __declspec(dllimport) __stdcall SetBackColor(TColor pBkColor); extern "C" void __declspec(dllimport) __stdcall FanSelect( void *pSeriesNames,//系列名称YLDStr * (typedef struct{char Data[255];} YLDStr;) const int pSeriesNameCount,//系列名称个数,-1时表示全部选择 void *pSubSeriesNames,//系列名称YLDStr * (typedef struct{char Data[255];} YLDStr;) const int pSubSeriesNameCount,//子系列名称个数,-1时表示全部选择 const double &pFlow, //风量 const int &pFlowUnitType, //风量单位类型0-m^3/h 1-m^3/s 2-l/s 3-cfm const double &pPres, //风压 const int &pPresUnitType, //风压单位类型0-Pa 1-mmH2O 2-kgf/cm^2 3-inH2O const int &pPresType, //风压类型0-全压1-静压 const int &pOutFanType,//出风方式0-管道出风1-自由出风 const double &pAirDensity,//空气密度 const double &pMotorSafeCoff,//电机容量安全系数(%) const bool &pUserSetMotorSafeCoff,//用户设定了电机容量安全系数 double &rFlow_STDUnit,//标准单位下的风量 fun_AddResult pAddResult//函数指针,用于回传数据 ); extern "C" void __declspec(dllimport) __stdcall Belt_Selection( const char *pSeriesName, const char *pSubTypeName, const char *pModelName, const int &pSped_DataType,//电机转速类型0-标准数据1-用户数据默认为0(界面选择) const int &pHz_DataType,//频率选择0-50HZ 1-60HZ(界面选择) const int &pRotation,//出风旋转角度R0,R90,R180,R270(参考常量定义) const double &pFanSped,//风机转速(第一步计算得到) const double &pMotorPow,//电机功率(第一步计算得到) const double &pFlow_STDUnit,//标准单位下的风量 const double &pTPres,//全压(第一步计算得到) const double &pSPres,//静压(第一步计算得到) const double &pFTEff,//全压内效率(第一步计算得到) const double &pSdbA,//噪声(第一步计算得到) const int &pV olt,//用户选择的电压(参考电压常量声明V380 V400) , bool pPole[4],//用户选择的极数2,4,6,8 bool pBeltType[4],//用户选择的皮带类型SPZ SPA SPB SPC const bool &pBeSetFanSped,//用户设定了风机转速 const double &pFanSpedRt_User,//用户设定的风机转速差 const bool &pBeSetBeltMoveSped,//用户设定最大皮带运动速度 const double &pBeltMoveSped_User,//用户设定的最大皮带运动速度

LWIP接口函数的文档

Lwip 协议栈的设计与实现 (中文版) Swedish Institute of Computer Science February 20, 2001 作者:Adam Dunkels adam@sics.se 翻译:果农(QQ:10205001) 核桃(QQ:329147) 佳旭(QQ:3232253) 整理:佳旭(QQ:3232253) 本文为QQ群ARM TCPIP LCD(群号:10988210)版权所有未经作者许可不得用于商业用途 摘要

LWIP是TCP/IP协议栈的一种实现。LWIP的主要目的是减少存储器利用量和代码尺寸,使LWIP适合应用于小的、资源有限的处理器如嵌入式系统。为了减少处理器和存储器要求,lwIP 可以通过不需任何数据拷贝的API进行裁减。 本文叙述了lwIP的设计与实现。叙述了协议实现及子系统中所使用的算法和数据结构如存储和缓冲管理系统。还包括LWIP API的参考手册和使用LWIP 的一些代码例子。 目录 1 Introduction (1) 2 Protocol layering (1) 3 Overview (2) 4 Process model (2) 5 The operating system emulation layer (3) 6 Buffer and memory management...................................................................... (3) 6.1 Packet buffers -pbufs (3) 6.2 Memory management (5) 7 Network interfaces........................................................................................ .. (5) 8 IP processing (7) 8.1 Receiving packets (7) 8.2 Sending packets (7) 8.3 Forwarding packets (8) 8.4 ICMP processing (8) 9 UDP processing............................................................................................ (8) 10 TCP processing.......................................................................................... (9) 10.1 Overview (9) 10.2 Data structures (10)

Excel表格中的一些基本函数使用方法

Excel表格中的一些基本函数使用方法 一、输入三个“=”,回车,得到一条双直线; 二、输入三个“~”,回车,得到一条波浪线; 三、输入三个“*”或“-”或“#”,回车,惊喜多多; 在单元格内输入=now()显示日期 在单元格内输入=CHOOSE(WEEKDAY(I3,2),"星期一","星期二","星期三","星期四","星期五","星期六","星期日") 显示星期几 Excel常用函数大全 1、ABS函数 函数名称:ABS 主要功能:求出相应数字的绝对值。 使用格式:ABS(number) 参数说明:number代表需要求绝对值的数值或引用的单元格。 应用举例:如果在B2单元格中输入公式:=ABS(A2),则在A2单元格中无论输入正数(如100)还是负数(如-100),B2中均显示出正数(如100)。 特别提醒:如果number参数不是数值,而是一些字符(如A等),则B2中返回错误值“#VALUE!”。 2、AND函数 函数名称:AND 主要功能:返回逻辑值:如果所有参数值均为逻辑“真(TRUE)”,则返回逻辑“真(TRUE)”,反之返回逻辑“假(FALSE)”。

使用格式:AND(logical1,logical2, ...) 参数说明:Logical1,Logical2,Logical3……:表示待测试的条件值或表达式,最多这30个。 应用举例:在C5单元格输入公式:=AND(A5>=60,B5>=60),确认。如果C5中返回TRUE,说明A5和B5中的数值均大于等于60,如果返回FALSE,说明A5和B5中的数值至少有一个小于60。 特别提醒:如果指定的逻辑条件参数中包含非逻辑值时,则函数返回错误值“#VALUE!”或“#NAME”。 3、AVERAGE函数 函数名称:AVERAGE 主要功能:求出所有参数的算术平均值。 使用格式:AVERAGE(number1,number2,……) 参数说明:number1,number2,……:需要求平均值的数值或引用单元格(区域),参数不超过30个。 应用举例:在B8单元格中输入公式: =AVERAGE(B7:D7,F7:H7,7,8),确认后,即可求出B7至D7区域、F7至H7区域中的数值和7、8的平均值。 特别提醒:如果引用区域中包含“0”值单元格,则计算在内;如果引用区域中包含空白或字符单元格,则不计算在内。 4、COLUMN 函数 函数名称:COLUMN 主要功能:显示所引用单元格的列标号值。

CAN应用接口函数

CAN应用接口函数库使用手册V1.0

目录 1.接口卡设备类型定义 (3) 2.错误码定义 (4) 3.函数库中的数据结构定义 (5) 3.1.VCI_BOARD_INFO (5) 3.2.VCI_CAN_OBJ (6) 3.3.VCI_CAN_STATUS (7) 3.4.VCI_ERR_INFO (8) 3.5.VCI_INIT_CONFIG (9) 3.6.VCI_RxAcptMask (10) 3.7.VCI_RxAcptFilter (11) 4.接口库函数说明 (12) 4.1.FD_OpenDevice (12) 4.2.FD_CloseDevice (13) 4.3.FD_InitCan (14) 4.4.FD_ReadBoardInfo (15) 4.5.FD_GetReceiveNum (16) 4.6.FD_ClearBuffer (17) 4.7.FD_StartCAN (18) 4.8.FD_ResetCAN (19) 4.9.FD_Transmit (20) 4.10.FD_Receive (21) 4.11.FD_RxAcptMaskInit (22) 4.12.FD_DisableRxAcptFilter (23) 4.13.FD_RxAcptFilterInit (24) 4.13.FD_SetOperationMode (25) 5.接口库函数使用方法 (26) 5.1.VC调用动态库的方法 (26) 5.2.VB调用动态库的方法 (26)

1.接口卡设备类型定义 各个接口卡的类型定义如下: 设备名称设备类型号备注 USBCAN11第一代USBCAN USBCAN22第二代USBCAN CAN2323待开发PCICAN4待开发

常用函数使用说明

可以给一列数后面标注大小 可以在一列数前面标记人民币符号 可以在一句话中提起字符 提取年 提取月

在身份证中提取年月日 可以比对,对比两个单元格里的内容是否一样 给数字固定四舍五入

显示系统当前的日期

向下舍入 1、向上四舍五入数字函数ROUND ⑴功能 按指定的位数对数值进行四舍五入。 ⑵格式 ROUND(数值或数值单元格,指定的位数) ⑶示例 A列 B列 12.351 325.525

…… B1中输入公式 ①保留2位小数——从千分位向百分位四舍五入。 =ROUND(A1,2)=12.35 向下复制公式到B2 =ROUND(A2,2)=325.53 ②四舍五入取整数——从十分位向个位四舍五入保留整数。 B1中输入公式 =ROUND(A1,0)=12 向下复制公式到B2 =ROUND(A2,0)=326 ③四舍五入到十位——从个位向十位四舍五入保留到十位数字。 B1中输入公式 =ROUND(A1,-1)=10 向下复制公式到B2 =ROUND(A2,-1)=330 说明: 函数ROUND的第1个参数可以是具体的数值也可以是数值单元格引用。 函数ROUND的第2个参数——指定保留的位数,保留小数位用正整数表示,即1,2,3,4……(对应十分位、百分位、千分位、万分位……);保留整数位用非正整数表示,即0,-1,-2,-3,……(对应个位、十位、百位……)。 2、向下舍数字函数ROUNDDOWN ⑴功能 按指定的位数对数值进行舍入。 ⑵格式 ROUNDDOWN(数值或数值单元格,指定的位数) ⑶示例 A列 B列 12.351 325.525 …… B1中输入公式 ①保留2位小数——舍去千分位及以后的小数位保留到百分位。 =ROUNDDOWN (A1,2)=12.35 向下复制公式到B2 =ROUNDDOWN (A2,2)=325.52 ②舍去小数位保留整数——舍去十分位及以后的小数位保留整数部分。 B1中输入公式 =ROUNDDOWN (A1,0)=12 向下复制公式到B2 =ROUNDDOWN (A2,0)=325 ③整数保留到十位——整数部分舍去个位上大于0的数字(用0代替),保留十位及以前的高位数字。

API函数手册

POSTEK PPLⅠAPI函数手册 G Series 条码标签打印机 Version 2.00 深圳市博思得通信发展有限公司 二○○四年

API函数库文件说明 名称:CDFPSK.dll 中文版本编号:1.X.X.X 英文版本编号:2.X.X.X 版权所有:?2004深圳市博思得通信发展有限公司。保留所有权利。 用途 本API函数库为深圳市博思得通信发展有限公司条码标签打印机的用户提供一组命令,为他们编写基于Windows9X,NT,2000,XP等操作系统的应用程序提供便利。 本API函数库仅支持本公司产品。 缩略语对照 PPLⅠ:深圳市博思得通信发展有限公司的第一套打印机编程语言(Printer Porgram Language Ⅰ)。 API:应用程序编程接口(Application Program Interface)。 Dots:像素(pixel)是一种计算机科学技术尺寸单位,原指电视图像成像的最小单位,在打印机领域表示打印机的最小打印成像单位:1dot等于一英寸除以打印机的最大分辨率。 - 对于203DPI的打印机来说, 1dot = 25.4mm/203 = 0.125mm(1dot = 1000 / 203 = 5mil); - 对于300DPI的打印机来说, 1dot = 25.4mm/300 = 0.085mm(1dot = 1000 / 300 = 3mil)。 TrueType Font:是基于Windows操作系统使用,可装卸的字体。 - 已经安装的TrueType Font,都可以被本函数使用。 使用前须知 字符串 * 字符串以双引号(“)作为起始和结束标记; *

OCX接口说明V4

1.概述 精伦电子股份有限公司开发的二代身份证读卡系列机具适用于相关行业的联机型应用。产品提供了完善的二次软件开发接口(API)。本手册针对提供的ActiveX控件,对开发接口的文件组成、方法定义格式、调用方法及返回值等进行了详细的说明。 2.接口文件说明 接口文件包括: IdrControl.ocx Dewlt.dll Savephoto.dll Wltrs.dll 适用开发语言: 网络脚本开发 第一次使用时,需要以管理员身份运行SetupOCX.exe对控件进行安装注册。 更新说明: V4.0.1.0增加对编码设备支持,可设置日志文件。 V4.0.0.6增加RepeatRead 方法,可设置后进行连续读身份证。 V4.0.0.0增加对210-P的支持。 V3.4.1.4解决和13002相关在20130726的读卡体管理号问题。 V3.4.1.3解决一个潜在导致内存泄漏的问题。 V3.4.1.2增加GetCardPhotobuf方法,用于获取身份证正反面图片JPG格式Base64编码信息。 V3.4.1.0增加ExportPhoto方法,可在读卡结束后生成指定照片和卡图片文件名。

3.接口方法说明 3.1. 身份证方法 3.1.1.读身份证方法 原型:short ReadCard(long iPort,BSTR PhotoPath) 说明:本方法将打开端口、找卡、读卡等功能进行了集成,可用于打开串口或USB口并读取二代证卡内信息。 参数: 1、iPort:设置串口、USB或iDR210免驱动USB-HID。 普通串口 1 – 16(十进制) 例如: 1:串口1(COM1) 2:串口2(COM2) USB USB-HID (iDR210) 1001 例如: 1001:USB 2、PhotoPath:生成图片文件的绝对路径,包括生成的照片文件photo.bmp,photo.jpg和指定文件名的照片文件,和身份证正反面图片card.jpg。该参数为""时,默认将照片文件保存到Windows系统临时文件目录(GetTempPath())。也可自行设置保存的路径,比如:"d:\\photos\\photo.bmp",注意文件参数必须设置正确,才能正确地将相片文件放在指定位置(相片文件夹若不存在,将会自动生成新文件夹)。 返回值: 值说明 1 正确 -1 端口初始化失败 -2 卡认证失败(请重新将 卡放到读卡器) -3 读取数据失败 -4 生成照片文件失败(请 检查设定路径和磁盘空

API应用程序编程接口详解

API应用程序编程接口 API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。API除了有应用“应用程序接口”的意思外,还特指API的说明文档,也称为帮助文档。另外,也是美国石油协会、空气污染指数、医药、空中位置指示器的英文简称。 Windows API是一套用来控制Windows的各个部件(从桌面的外观到为一个新进程分配的内存)的外观和行为的一套预先定义的Windows函数.用户的每个动作都会引发一个或几个函数的运行以告 诉Windows发生了什么.

这在某种程度上很象Windows的天然代码.其他的语言只是提供一种能自动而且更容易的访问API的方法.VB在这方面作了很多工作.它完全隐藏了API并且提供了在Windows环境下编程的一种完全不同的方法. 这也就是说,你用VB写出的每行代码都会被VB转换为API函数传递给Windows.例如,Form1.Print...VB 将会以一定的参数(你的代码中提供的,或是默认参数)调用TextOut 这个API函数。同样,当你点击窗体上的一个按钮时,Windows会发送一个消息给窗体(这对于你来说是隐藏的),VB获取这个调用并经过分析后生成一个 特定事件(Button_Click). API函数包含在Windows系统目录下的动态连接库文件中(如User32.dll,GDI32.dll,Shell32.dll...). 更易理解地说:Windows 这个多作业系统除了协调应用程式的执行、分配内存、管理系统资源…之外,她同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程式达到开启视窗、描绘图形、使用周边设备…等目的,由於这些函数服务的对象是应用程式(Application),所以便称之为Application Programming Interface,简称API 函数。WIN32 API也就是MicrosoftWindows 32位平台的应用程序编程接口。 凡是在Windows 工作环境底下执行的应用程式,都可以 调用Windows API。 API的历史与现状

VLOOKUP函数的使用方法(图解说明_很详细)

VLOOKUP函数调用方法如下:(本次以提取RRU挂高数据为例) 一、本次涉及的相关文档。 1.《某地区TD宏站现场勘测数据汇总表》如表1-1,共1000多站,本次共列出104个站点的信息: 查看原文档请双击图标:某地区TD宏站现场 查勘数据汇总表,表1-1抓图如下: 2.某工程报价单,共30个宏站,如表1-2(本报价单其他信息均删除,只保留了站点名) 查看原文档请双击图标:某工程报价单.xlsx ,表1-2抓图如下: 二、本次我们以从表1-1中提取表1-2中30个站点的RRU挂高为例,具体步骤如下: 1.先在表1-2中增加“RRU挂高”这一列,然后先提取“某城关水泵厂南”的RRU挂高。操作方法为双击下图所示灰色表格,然后鼠标左键单击列表上面的fx插入函 数。 2.点fx后弹出如下图标,在下拉列表中选择“VLOOKUP”,点确定。

3.点确定后,弹出VLOOKUP函数调用表,包含4个部分(lookup_value、Table_array、C ol_index_num、Range_lookup)。 lookup_value:需要在数据表首列进行搜索的值,本次值为表1-1中的位置B2,用 鼠标单击表1-1中的“某城关水泵厂南”,即可自动输入。。 Table_array:需要在其中搜索数据的信息表,即在表1-2中选择一个搜索区域, 注意所选区域第一列必须是与Lookup_value中查找数值相匹配的 列(本次表1-1中的B列),最后一列必须大于等于RRU挂高那一列 (大于等于C列),至于下拉行数肯定要大于等于106行。如下图: 选择相关区域后,VLOOKUP表中的Table_array会自动输入表1-1中所选区域,如 下图:

ORACLE数据库API接口函数设计说明

ORACLE数据库API接口函数设计说明 API接口函数使用示例: 参见程序OCIDEMO.DSW //工程中不用在连接ociw32.lib只用xjoci.lib就行了。 假定: 工程文件为newocidemo,所在目录为c:\newocidemo,newocidemo.exe 位于c:\newocidemo\debug下面 使用步骤: 1、将MyConnection.h;oratypes.h;ocidem.h;ocidfn.h;xioci.lib复制到c:\newocidemo下面 2、将xioci.dll复制到c:\newocidemo\debug下面 3、设置project 下的settings 下面的link 中的object/library modules: 为xjoci.lib 4、在file中添加MyConnection.h,从而在class中会出现connection,cursor两个新类 API接口函数类设计: CONNECTION类 class connection { friend class cursor; public: BOOL IsConnected(); connection();

~connection(); BOOL connect(char *username, char *password,char *sername); BOOL disconnect(); void display_error() const; private: Lda_Def lda; ub1 hda[HDA_SIZE]; enum conn_state { not_connected, connected }; conn_state state; }; BOOL connect(char *username, char *password,char *sername); 函数用途:connect函数建立OCI程序与ORACLE数据库的连接参数说明:char *username,--用户名 char *password,--口令 char *sername—主机字符串(数据库别名)。 返回值:连接成功返回TRUE,不成功返回FALSE BOOL disconnect(); 函数用途:disconnect函数断开与数据库的连接 参数说明:

文华函数使用说明

文华函数使用说明 求绝对值。 用法: ABS(X)返回X的绝对值。 例:ABS(-10)返回10,ABS(CLOISE-10) 返回收盘价和10的价差。 求反余弦值。 用法: ACOS(X)返回X的反余弦值。 求反正弦值。 用法: ASIN(X)返回X的反正弦值。 求反正切值。 用法: ATAN(X)返回X的反正切值。

求平均绝对偏差。 用法: AVEDEV(X,N)返回X在N周期内的平均绝对偏差。 取得均价。 用法: AVPRICE返回均价。 取K线的位置。 用法: BARPOS 取某K线的位置。 设置背景的样式。 用法: BACKGROUNDSTYLE(i)设置背景的样式。 i = 0 或 1。

将当前位置到若干周期前的数据设为1。 用法: BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1。例:BACKSET(CLOSE>OPEN,3);表示当K线收阳时,自当前位置到3周期前的数值设为1 该函数参数支持变量计算如BACKSET(CLOSE>OPEN,VAR1);//VAR1是变量 本函数运算量很大,将占用很多的CPU资源,导致行情刷新速度变慢,请谨慎使用! 求上一次条件成立到当前的周期数。 用法: BARSLAST(X):上一次X不为0到现在的天数 本函数运算量很大,将占用很多的CPU资源,导致行情刷新速度变慢,请谨慎使用! 介于两个数之间。 用法: BETWEEN(A,B,C)表示A处于B和C之间时返回1(Yes),否则返回0(No) 例:BETWEEN(CLOSE,MA5,MA10); 表示收盘价介于5日均线与10日均

C++接口使用说明

NetCDF C++接口使用说明 作者:杜鸿飞 完成时间:2004年4月

目录 一、NetCDF文件介绍 (2) 二、NetCDF C++类函数详解 (3) 1. NcFile类公有成员函数 (3) 文件操作 (3) 维数操作 (4) 变量操作 (4) 属性操作 (6) 2. NcDim类公有成员函数 (7) 3. NcVar类公有成员函数 (7) 4. NcAtt类公有成员函数 (9) 三、NetCDF C++使用举例 (10)

//***************** function about dimension ****************************** int num_dims(); 返回文件所含dim数目 int unlimdimid(); 返回unlimited dimension的ID void def_dim(NcDim &dim); 将参数dim定义到文件中 NcDim inq_dim(int dimid); 返回文件中ID号为dimid的dim维数 NcDim inq_dim(const string dimname); 返回文件中名字为dimname的dim维数 void rename_dim(int dimid, string name); 将文件中ID号为dimid的维数重命名为name //***************** function about variable ****************************** int num_vars(); 返回文件所含var数目 void def_var(NcVar &var); 将参数var定义到文件中 NcVar inq_var(int varid); 返回文件中ID号为varid的var变量 NcVar inq_var(const string varname); 返回文件中名字为varname的var变量 void rename_var(int varid, string name); 将文件中ID号为varid的变量重命名为name template void put_var_single(int varid, int index[], Type value); 给文件中ID号为 varid的var变量写入一个值 varid:欲写入值的变量的ID号 index: 欲写入值在变量中位置的索引,用数组存储,如对于一个3维变量,对其任一元素写值,index为一含3个元素的数组(0,0,0)到(2,2,2); value: 将要写入的值,为摸板参数类型,其类型由函数自动解析。 template void put_var_entire(int varid, Type block[]); 给文件中ID号为 varid的var变量整体写入值 varid:欲写入值的变量的ID号 block: 存储将要写入值的数组地址,该数组大小应不小于变量实际元素个数。block为摸板参数类型,其类型由函数自动解析。 template void put_var_array(int varid, int start[], int count[], Type *block); 给文件中ID号为 varid的var变量部分写入值 varid:欲写入值的变量的ID号 start:欲写入值的其始位置索引,格式同put_var_single函数中的index参数

相关文档