1.Windows通信相关驱动
netio.sys(Network I/O Subsystem)
ndis.sys(NDIS Driver)
ipnat.sys(IP Network Address Translator)
tcpip.sys(TCP/IP Driver)
tdtcp.sys(TCP Transport Driver)
tdi.sys(TDI wrapper)
afd.sys(Ancillary Function Driver for Winsock)
http.sys(HTTP Protocol Stack)
……
2.socket描述符(套接字句柄)
“在UNIX系统中,任何东西都是一个文件。”这句话描述了这样一个事实:在UNIX系统中,任何对I/O的操作,都是通过读或写一个文件描述符(File DescriptorFile了到对方发送的数据Port+Length+Checksum)来实现的。
一个文件描述符(FD)只是一个简单的整形数值,代表一个被打开的文件(这里的文件是广义的文件,并不只是代表不同的磁盘文件,它可以代表一个网络上的连接,一个先进先出的队列,一个终端显示屏等)。
既然在UNIX系统中任何东西都是一个文件,通过Internet和另外一台机器进行通讯也是基于文件描述符来实现的。这个文件描述符即套接字内核对象:intsockfd。在早期的UNIX/Linux系统中,可调用read()和write()直接对套接字进行类似文件的读写操作,尽管调用recv()和send()显得更为专业。
在Windoze系统中,内核对象往往交由一个句柄与外部交互,如文件句柄。在很多WinSock场合我们习惯使用“套接字句柄”这一称呼:typedefu_intSOCKET。实际上,WinSock中对于套接字的操作,很多也沿袭了文件操作的规范。例如,在Winsock 1中,应用程序可以针对套接字句柄调用ReadFile()和WriteFile(),同时指定重叠结构以利用重叠I/O模型,到Winsock 2中才正式替换为WSARecv()和WSASend(),以专用于套接字操作。
3.Windows Sockets规范
Sockets本来是UNIX操作系统下流行的一种网络编程接口(API),它是1983年在Berkeley(加州大学伯克利分校)4.2 BSD操作系统中被首先引入的,因此被称为“Berkeley Socket API”。
Windows Sockets是在Windows环境下使用的一套网络编程规范,常常简称为WinSock。在Winsock规范中把Winsock API函数集分为与BSD Socket(用在UNIX中)相兼容的基本函数、网络数据信息检索函数和Windows专用扩展函数三类。
Windows Socket 1规范的核心内容是符合Berkeley Socket风格的库函数,例如可以编写基于select模型的的socket跨平台库。select模型可以很好地实现跨平台,但对具体操作系统平台而言,并非性能最佳的I/O模型。为了使程序员能充分利用Windows消息驱动机制进行编程,又定义开发了一组针对Windows的扩展库函数,这就是Windows Socket 2规范。Winsock 2.x提供了基于Windows消息机制的WSAAsyncSelcet异步I/O网络事件通知模型,除此之外WinSock 2.x还提供了基于事件通知的异步I/O网络事件通知的WSAEventSelect模型和高效的重叠I/O模型。具体平台实现了各自高效的网络I/O管理模型,例如Windoze的IOCP模型、Linux的epoll模型,它们用来实现大规模高并发的通信应用程序。
目前常用的Winsock有两个版本:一个是16位的Winsock 1.1,由动态链接库WINSOCK.DLL提供支持;另一个是32位的Winsock 2.2,由动态链接库WSOCK32.DLL提供支持。
从Win98/NT4开始,Windows支持WinSock 2,而WinSock 1成为WinSock 2的功能子集。在32位系统下,16位的WINSOCK.DLL(Windows Socket 16-bit DLL)为Non-resident。
ws2_32.dll和mswsock.dll是WinSock 2真正的实现者。wsock32.dll只是映射了ws2_32.Dll和mswsock.dll两个文件的一些函数调用,并无具体实现。使用Dependency Walker可以看到wsock32.dll和mswsock.dll都依赖ws2_32.dll。
mswsock.dll提供了微软特有的WSA扩展,包括AcceptEx/GetAcceptExSockaddrs、ConnectEx/DisconnectEx、TransmitPackets/TransmitFile、WSARecvMsg。其中仅有AcceptEx/GetAcceptExSockaddrs和TransmitFile这三个函数真正从mswsock.dll导出。
如果要求编写符合Berkeley Socket API标准的程序,则只需要加载wsock32.dll使用WinSock 1.x规范(BSD Socket API for Wndows)就可以了。如果要结合Windows平台特性编写WinSock 2.x的程序,则可加载ws2_32.dll和mswsock.dll调用WSA系列(扩展)函数。加载WinSock库是通过WSAStartup()来指定的。
(1)加载WinSock 1.1
/* WINSOCK.H--definitions to be used with the WINSOCK.DLL
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This header file corresponds to version 1.1 of the Windows Sockets specification.
*
* (1)Basic system type definitions, taken from the BSD file sys/types.h.
* (2)Structure used in select() call, taken from the BSD file sys/time.h.
* (3)Commands for ioctlsocket(), taken from the BSD file fcntl.h.
* (4)Structures returned by network data base library, taken from the BSD file netdb.h.
* (5)Constants and structures defined by the internet system, Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
* (6)Definitions related to sockets: types, address families, options, taken from the BSD file sys/socket.h.
*
* (7)Microsoft Windows Extension function prototypes:WSA开头的WSAStartup、WSACleanup等Windows Sockets API。
* (8)Microsoft Windows Extended data types:typedef了SOCKADDR、SOCKADDR_IN等宏。
*/
#include<WinSock.h>
#pragmacomment(lib,"WSock32.Lib")
LoadLibrary("C://WINDOWS//system32/wsock32.dll");// Windows Socket 32-Bit DLL
Windows Mobile下对应winsock.h/winsock.lib/winsock.dll。
(2)加载WinSock 2.2
/* Winsock2.h -- definitions to be used with the WinSock 2 DLL and
* WinSock 2 applications.
*
* This header file corresponds to version 2.2.x of the WinSock API
* specification.
*
* #define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
*/
#include<WinSock2.h>
#pragmacomment(lib,"WS2_32.lib")
LoadLibrary("C://WINDOWS//system32//ws2_32.dll");// Windows Socket 2.0 32-Bit DLL
Windows Mobile下对应winsock2.h/ws2.lib/ws2.dll。
(3)加载Microsoft Windows-Specific Extension Functions
/*++
Module Name:
mswsock.h
Abstract:
This module contains the Microsoft-specific extensions to the Windows Sockets API.
--*/
#include<Mswsock.h>
#pragmacomment(lib,"MsWSock.Lib")
LoadLibrary("C://WINDOWS//system32//mswsock.dll");// Microsoft Windows Socket 2.0 Service Provider
二.套接字通信基础
至此,我还不打算直接进入套接字的一些诸如recv()和send()操作。在正式使用套接字进行通信编程之前,有必要先了解一下通信所涉及到地址识别、字节顺序等知识点。
1.套接字地址(sockaddr)、TCP/IP套接字地址(sockaddr_in)和IP地址in_addr
1.1 structsockaddr
structsockaddr结构用来存储套接字地址。
/*
* Structure used by kernel to store most addresses.
*/
structsockaddr {
u_shortsa_family;/* address family,AF_X */
char sa_data[14];/* up to 14 bytes of direct address */
};
sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一起的。sa_data域的定义有些不确定性,注释暗示内容可能超过14个字节。这种不确定性是经过深思熟虑的。套接字是个非常强大的接口。多数人可能认为比Internet接口强不到哪里——大多数应用现在很可能都用它——套接字可被用于几乎任何种类的进程间通信,Internet(更精确的说是IP)只是其支持的协议簇中的一种。
#defineSOCK_MAXADDRLEN 255 /*可能的最长的地址长度*/
socket层涉及到地址的API都是用sockaddr结构,这些API包括bind(服务器绑定本地地址+端口)、connect(连接服务器)/accept(接受客户端)、recvfrom/sendto。
intbind(intsockfd, structsockaddr *my_addr,intaddrlen);
intaccept(intsockfd, structsockaddr *addr,int*addrlen);
intconnect(intsockfd, const structsockaddr *serv_addr,intaddrlen);
1.2 structsockaddr_in
Sockets API提供了structsockaddr的TCP/IP版本——structsockaddr_in,其中in代表“internet”,故sockaddr_in.sa_family=AF_INET。
/*
* Socket address, internet style.
*/
structsockaddr_in {
short sin_family;/* internet address family */
u_shortsin_port;/* port number */
struct in_addrsin_addr;/* internet address */
charsin_zero[8];/* padding bits */
};
这个结构提供了方便的手段来访问socket address(structsockaddr)结构中的每一个元素。注意sin_zero[8]是为了使sockaddr和sockaddr_in结构具有相同的尺寸,使用sockaddr_in的时候要把