winsock编程 (二)

目录
  4.1 套接口函数
  4.2 数据库函数
  4.3 针对MICROSOFT WINDOWS的扩展函数

4.1、套接口函数
  Windows Sockets规范包含了以下Berkeley风格的套接口例程:
  accept() * 响应联结请求,并且新建一个套接口。原来的套接口则返回监听状态。

  bind() 把一个本地的名字和一个无名的套接口捆绑起来。
  closesocket() * 把套接口从拥有对象参考表中取消。该函数只有在SO_LINGER被设置
时才会阻塞。
  connect() * 初始化到一个指定套接口上的连接。
  getpeername() 得到连接在指定套接口上的对等通讯方的名字。
  getsockname() 得到指定套接口上当前的名字。
  getsockopt() 得到与指定套接口相关的属性选项。
  htonl() 把32位的数字从主机字节顺序转换到网络字节顺序。
  htons() 把16位的数字从主机字节顺序转换到网络字节顺序。
  inet_addr() 把一个Internet标准的“.”记号地址转换成Internet地址数值。
  inet_ntoa() 把Internet地址数值转换成带“.”的ASCII字符串。
  ioctlsocket() 为套接口提供控制。
  listen() 监听某一指定套接口上连接请求的到来。
  ntohl() 把32位数字从网络字节顺序转换为主机字节顺序。
  ntons() 把16位数字从网络字节顺序转换为主机字节顺序。
  recv() * 从一个已连接的套接口接收数据。
  recvfrom() * 从一个已连接的或未连接的套接口接收数据。
  select() * 执行同步I/O多路复用。
  send() * 从一已连接的套接口发送数据。
  sendto() * 从已连接或未连接的套接口发送数据。
  setsockopt() 设置与指定套接口相关的属性选项。
  shutdown() 关闭一部分全双工的连接。
  socket() 创建一个通讯端点并返回一个套接口。
  * 表示例程在应用于阻塞套接口时会阻塞。
  4.1.1 阻塞/非阻塞和数据易失性
  阻塞是在把应用程序从Berkeley套接口环境中移植到Windows环境中的一个主要焦点。
阻塞是指唤起一个函数
,该函数直到相关操作完成时才返回。由于操作可能需要任意长的时间才能完成,于是问
题就出现了。最明显的一
个例子就是recv(),这个函数会一直处于阻塞状态直到收到对方系统发送的数据。在Berk
eley套接口模型中,一个
套接口的操作的缺省行为是阻塞方式的,除非程序员显式地请求该操作为非阻塞方式。我
们强烈推荐程序员在尽可
能的情况下使用非阻塞方式(异步方式)的操作。 因为非阻塞方式的操作能够更好地在非
占先的Windows环境下工
作。程序员应该在绝对必要的时候才采用阻塞方式。而且在你必须使用阻塞方式的操作前
仔细阅读并理解这一部分

  即使在阻塞方式下,有些操作(例如bind(),getsockopt(),getpeername())也会立刻
完成。 对于这些操作,
阻塞方式和非阻塞方式并没有什么两样。其他一些操作(例如recv())可能立刻完成,也
可能需要阻塞一段随机的
时间才能完成。这都取决于不同的传输情况。当用于阻塞套接口时,这些操作被认为是工
作于阻塞方式的,所有会
阻塞的例程在以前或以后的列表中都打上了星号作标记。
  在Windows Sockets实现中,一个无法立刻完成的阻塞操作是按如下方式处理的。DLL
先初始化操作,然后进入
一个循环, 在循环中发送收到的任何信息-为了使在必要时把处理器交给其他线程,然后
检查Windows Sockets功
能是否完成。如果功能完成了, 或者WSACancelBlockingCall()被唤起,阻塞操作以一个
适当的返回值结束。完整
的关于这种机制的描述,请参见5.3.13节,WSASetBlockingHook(),这一部分还包括了对
于各种函数伪代码的讨论

  如果一个正在运行某一阻塞操作的进程收到了一个Windows消息,那么应用程序有可能
试图发出另一个Windows
Sockets调用,由于很难安全地处理这种情形,Windows Sockets规范不支持这种应用程序
的工作方式。在这种情况
下,有两个函数可以帮助程序员。WSAIsBlocking()可以用来确定在该进程上是否有阻塞的
Windows Sockets调用。
WSACancelBlookingCall()可以用来取消在线的阻塞调用,如果有的话。任何其他的Windo
ws Sockets函数如果在这
种情况下被调用,则会失败并返回错误代码WSAEINPROGRESS。要强调的是,这一限制适用
于所有阻塞和非阻塞的操
作。
  虽然这种机制对于简单的应用程序已经足够了,但这不能支持高级应用程序的复杂的
消息发送要求。(例如,
那些MDI模型的用户)对于这样的应用程序,Windows Sockets API设计了WSASetBlocking
Hook()函数,这个函数可
以允许程序员定义特殊的阻塞钩子来代替上面讨论的缺省消息发送例程。
  只有在以下都为真时,Windows Sockets DLL才调用阻塞钩子函数: 例程是被定义为
可以阻塞的,指定的套接
口也是阻塞套接口, 而且请求不能被立刻完成。(套接口是被缺省地设为阻塞方式的,但
IOCTL FIONBIO和WSAAsy
ncSelect()都可以把套接口设置成为非阻塞模式)。如果应用程序只使用非阻塞方式的套
接口,而且使用WSAAsync
Select()和/或WSAAsyncGetXByY()例程,而不是使用select()和/或getXbyY()例程,那么
阻塞钩子函数就永远也不
会被调用,应用程序也不用再操心由于阻塞钩子函数而带来的重入问题。
  如果一个应用程序在唤起异步或非阻塞方式调用时使用了一个内存对象的指针(例如
一个缓冲区,或者一个全
程变量)作为参数, 那么应用程序要保证那个对象在Windows Sockets实现的整个操作中
都可得到并使用。应用程
序不能再唤起可能影响到内存唤射或寻址能力的其他的Windows函数。在多线程系统中,
应用程序也有责任使用某
种同步机制来协调对内存对象的存取。Windows Sockets实现不能, 也不会提出这种事情
。没有遵守这条规则,所
可能产生的后果已不在规范讨论的范围之内。

4.2 数据库函数
  Windows Sockets规范定义了如下数据库例程。正如我们先前提出的,Windows Socke
ts提供者有可能不采用依
赖于本地数据库的方式来实现这些函数。某些数据库例程返回的指针(例如gethostbynam
e())指向的区域是由Win
dows Sockets函数库分配的 。这些指针指向的数据是易失的。它们只在该线程的下一个W
indows Sockets API调用
前有效。此外,应用程序不应试图修改这个结构,或者释放其中的任何一部分。在一个线
程中,这个结构只有一份
拷贝。因此,应用程序应该在发出下一个Windows Sockets API调用以前把所需的信息拷贝
下来。
  gethostbyaddr() * 从网络地址得到对应的名字(有可能多个)和地址。
  gethostbyname() * 从主机名得到对应的名字(有可能多个)和地址。
  gethostname() 得到本地主机名。
  getprotbyname() * 从协议名得到对应的协议名和数值。
  getservbyname() * 从一个服务的名字得到对应的服务名以及端口号。
  getservbyport() * 从一个端口号得到对应的服务名以及端口号。
  * 表示例程在某些情况下可能会阻塞。

4.3 针对Microsoft Windows的扩展函数
  Windows Sockets规范提供了许多在标准的Berkelet套接口例程之外的扩展函数。本质
上,这些扩展的API是为
了应用程序能更好地处理基于消息的异步发送的网络事件 。虽然基于Windows Sockets的
编程并不强制要使用这个
扩展的API集(WSAStartup()和WSACleanup()除外)但我们推荐应用程序开发者遵循Micro
soft Windows的编程范例

  WSAAsyncGetHostByAddr() 一个标准的Berkeley的getXbyY()函数集合的异步版本。例
如WSAAsyncGetHostByNa
me()函数提供了一个标准Berkeley的gethostbyname()函数的异步基于消息的实现。
  WSAAsyncGetHostByName()
  WSAAsyncGetProtoByName()
  WSAAsyncGetProtByNumber()
  WSAAsyncGetServByName()
  WSAAsyncGetServByPort()
  WSAAsyncSelect() select() 函数的异步版本。
  WSACancelAsyncRequest() 取消一个未完成的WSAAsyncGetXByY()函数的实例。
  WSACancelBlockingCall() 取消未完成的阻塞的API调用。
  WSACleanup() 从底层的Windows Sockets DLL中撤销注册。
  WSAGetLastError() 得到最近的一个Windows Sockets API调用错误的详细情况。
  WSAIsBlocking() 确定底层的Windows Sockets DLL是否在该线程已经被一个调用阻塞

  WSASetBlockingHook() 为底层的Windows Sockets实现设置阻塞钩子。
  WSASetLastError() 设置下一次WSAGetLastError()返回的错误信息。
  WSAStartup() 初始化底层的Windows Sockets DLL。
  WSAUnhookBlockingHook() 恢复原始的阻塞钩子。
  4.3.1 异步选择机制
  WSAAsyncSelect()调用允许应用程序程序注册一个或多个感兴趣的网络事件。这一AP
I调用用来取代探寻网络I
/O调用。在select()或非阻塞I/O例程(例如send()和recv())已经被调用或将要被调用的
情况下都可以使用WSAAs
yncSelect()调用。在这种情况下, 在声明感兴趣的网络事件时,你必须提供一个通知时
使用的窗口句柄。那么在
你声明的感兴趣的网络事件发生时,对应的窗口将收到一个基于消息的通知。
  Windows Sockets允许对于一特定的套接口声明如下感兴趣的网络事件:
  *套接口已准备读数据。
  *套接口已准备写数据。
  *带外数据准备好。
  *套接口准备接收连接请求。
  *非阻塞连接操作结束。
  *连接关闭。
  4.3.2 异步支持例程
  异步数据库函数允许应用程序用异步方式请求信息。某些网络实现和/或配置, 需要
通过执行网络操作来应答
这些请求。WSAAsyncGetXByY()函数允许应用程序开发者不必象在使用Berkeley标准函数时
阻塞整个Windows环境。
WSACancelAsyncRequest()函数可以允许一个应用程序取消任何未完成的异步的WSAAsyncG
etXByY()请求。
  4.3.3 阻塞钩子函数方法
  正如4.1.1节所讲述的,Windows Sockets实现以这样一种方式阻塞一个操作,Window
s消息处理可以继续, 发
出调用的应用程序仍然可以收到Windows消息。但在某些情况下, 应用程序可能希望影响
或改变这种伪阻塞的实现
方式 。WSASetBlockingHook()函数就提供了这样一种功能。它使得应用程序可以替换Win
dows Sockets实现在“阻
塞”操作中放弃处理器时调用的例程。
  4.3.4 错误处理
  为了与基于线程的环境兼容,API调用的错误细节可以通过WSAGetLastError()调用得
到。虽然已经为大家接收
的Berkeley风格的机制是通过“errno”得到关于套接口的网络错误的, 这种机制不能够
保证在多线程环境中错误
代码的完整性和正确性。WSAGetLastError()允许程序员能够得到对应于每一线程的最近的
错误代码。   
  WSAGetLastError()所返回的错误代码尽量避免与标准的Microsoft C错误代码冲突。
但是某些Windows Socket
s例程返回的错误代码是在Microsoft C定义的标准错误代码之内的。如果你使用的应用程
序开发环境中的错误代码
定义与Microsoft C不同,那么我们建议你使用Windows Sockets错误代码前缀“WSA”来保
证准确的检测错误。
  这份规范定义了一个推荐的错误代码的集合,而且列举了每一个函数有可能返回的错
误。但是某些Windows So
ckets实现也有可能返回一些在我们列举之外的错误代码。应用程序应该具备能够处理在每
个API描述下列举的错误
代码之外的错误的能力 。然而Windows Sockets实现不能返回在附录4.1中列举的合法Win
dows Sockets错误之外的
任何数值。
  4.3.5 通过中介DLL调用Windows Sockets DLL
  Windows Sockets DLL既可以直接从应用程序中调用也可以通过中介DLL调用。通过中
介DLL的例子是:使用Win
dows Sockets为应用程序实现一个提供通用网络功能的虚拟网络API层,这样的DLL可以同
时被多个应用程序使用。
担这样的DLL必须对WSAStartup()和WSACleanup()这两个函数非常警惕,它们必须保证在任
何一个使用Windows Soc
kets调用的任务前后均调用了WSAStartup()和WSACleanup()。这是因为Windows Sockets
DLL需要一个对WSAStartu
p()的调用来为每个任务初始化其数据结构,也需要一个对WSACleanup()的调用来释放为任
务分配的所有资源。
  有至少两种方法去完成这一任务。最简单的方法是中介DLL具有与WSAStarup()和WSAC
leanup()类似的调用提供
给应用程序使用,DLL将在这些例程中调用WSAStartup()和WSACleanup()。另一种机制就是
中介DLL建立一个任务句
柄列表。任务句柄是从GetCurrentTask()这一个Windows API中获得的。在中介DLL的每一
个入口处检查对于当前任
务WSAStartup()函数是否已被调用, 并且在必要的时候调用WSACleanup()函数。
  在Windows NT环境中,这一点是没有必要的。因为Windows NT中的DLL结构与流程是与
Windows不同的。在Wind
ows NT中,中介DLL只需简单的在它的DLL初始化例程中调用WSAStartup()即可。这个例程
将在任何一个新的进程试
图使用DLL的开始时刻被执行。
  如果中介DLL调用了阻塞操作而又没有安装任何它自己的阻塞钩子,那么DLL作者必须
清楚地认识到控制有可能
会通过应用程序安装的阻塞钩子或缺省的阻塞钩子回到应用程序手中。这样应用程序有可
能通过WSACancelBlockin
gCall()来取消中介DLL的阻塞操作, 如果这种情况发生了,中介DLL的阻塞操作会失败并
返回错误代码WSAEINTR。
这时候,中介DLL必须尽快地把控制交还给调用它的任务。因为用户有可能按了Cancel或者
Close按钮。应用程序正
在急切地盼望获得CPU的控制权。我们推荐中介DLL在进行阻塞调用时安装自己的阻塞钩子
来防止不可预见的中介DL
L和应用程序之间的互相影响。
  4.3.6 Windows Sockets实现内部对消息的使用
  为了把Windows Sockets实现成一个纯粹的DLL, 有时在DLL内部互相发送消息来通讯
和定时是必要的。这是非
常合法的。但是Windows DLL不应该无缘无故地发送消息给一个由客户打开的窗口句柄,
除非应用程序要求这些消
息 。所以为了自身的目的而需要使用消息的Windows Sockets DLL打开了一个隐藏的窗口
,并且发送必要的消息给
这个窗口的句柄。
  4.3.7 私有的API接口
  附录B.3中的WINSOCK.DEF文件列出了Windows Sockets API功能调用的序数。除了已经
列出的序数值外, 所有
小于999的序数都是保留给将来的Windows Sockets使用的。对于一个Windows Sockets实现
来说, 提供附加的私有
的接口也是很方便的。这是完全可以接受的,只要这些调用的序数大于1000,要注意的是
,任何使用了某个特定Wi
ndows Sockets DLL私有的API的应用程序极有可能在任何其他供应商的Windows Sockets
DLL上无法工作。 应该注
意到,只有使用在这份规范中定义的API才能可以保证每一个Windows Sockets实现都支持

  如果一个应用程序使用了某个供应商的Windows Sockets DLL的特定接口,最好不要把
应用程序与DLL静态连接
,而通过Windows Sockets例程LoadLibrary()和GetProcAddress()动态载入,这就使得应
用程序在其他不支持同样
的扩展功能集的Windows Sockets DLL系统上运行时,可以得到适当的错误信息。

下面是WinSock API函数:
__WSAFDIsSet
accept
AcceptEx
Arecv
Asend
bind
closesocket
closesockinfo
connect
dn_expand
EnumProtocolsA
EnumProtocolsW
GetAcceptExSockaddrs
GetAddressByNameA
GetAddressByNameW
gethostbyaddr
gethostbyname
gethostname
GetNameByTypeA
GetNameByTypeW
getnetbyname
getpeername
getprotobyname
getprotobynumber
getservbyname
getservbyport
GetServiceA
GetServiceW
getsockname
getsockopt
GetTypeByNameA
GetTypeByNameW
htonl
htons
inet_addr
inet_network
inet_ntoa
ioctlsocket
listen
MigrateWinsockConfiguration
NPLoadNameSpaces
NSPStartup
ntohl
ntohs
rcmd
recv
recv
rexec
rresvport
s_perror
select
send
sendto
sethostname
SetServiceA
SetServiceW
setsockopt
shutdown
socket
TransmitFile
WEP
WSAAsyncGetHostByAddr
WSAAsyncGetHostByName
WSAAsyncGetProtoByName
WSAAsyncGetProtoByNumber
WSAAsyncGetServByName
WSAAsyncGetServByPort
WSAAsyncSelect
WSACancelAsyncRequest
WSACancelBlockingCall
WSACleanup
WSAGetLastError
WSAIsBlocking
WSApSetPostRoutine
WSARecvEx
WSASetBlockingHook
WSASetLastError
WSAStartup
WSAUnhookBlockingHook
WsControl
WSHEnumProtocols

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值