Windows Sockets编程(一)概述

1、Windows socket是Windows平台下为网络编程开放的一个接口。

它不是一种网络协议,是独立于协议的。它是以Unix socket为基础,因此Windows socket中的许多函数名与Unix都是一样的。除此之外它还允许开发人员充分利用Windows的消息驱动机制进行程序设计开发。


2、Windows Sockets API(WSA)包括一组函数调用、数据结构和约定。

WSA为所有Windows应用提供针对底层网络协议栈的网络服务的标准访问。

WinSock应用的任务:提供良好的任务界面,以及格式化数据并解析数据;

WinSock协议栈的任务:利用标准的传输协议、驱动程序和网络介质发送和接收这些数据。


3、WinSock网络模型:由三部分构成:WinSock应用程序。网络系统。WinSock API。


1)会话层和表示层:

文件传输协议FTP:文件传输。

简单邮件传输协议SMTP:电子邮件服务。

远程登录Telnet:用于远程登录的终端协商。

域名服务DNS:主机名到IP地址的映射。

2)传输层:

用户数据报协议UDP:无连接数据传输。

传输控制协议TCP:可靠的数据传输。

3)网络层:

因特网协议IP:独立于硬件的寻址、路由、分片和数据包重组。

地址解析协议ARP:IP地址到硬件地址的映射。

因特网控制消息协议ICMP:错误和控制消息。


4、WinSock API提供了对传输层和网络层协议服务(即网络系统)的访问。高层协议不能通过WinSock API访问,而是必须借助WInSock应用程序来实现。

RFC是一种文档,用来详细描述标准协议在实施中的要求和允许的操作。


5、套接字是应用层到运输层的接口,用以表示一条连接的两端。每一个端点由IP和端口组成。因此套接字由两端点的IP和端口组成。

端口是运输层的概念,每个端口对应一个进程,因此一条连接表示一个进程与另一个进程建立联系。

应用程序可以使用两种套接字。流套接字和数据包套接字,分别对应TCP和UDP。

1)TCP提供面向连接的可靠的、无重复、有序的数据流服务。TCP提供的是一个流,这意味着它按需向每个数据包中注入或多或少的数据。

2)UDP提供面向数据包的服务,不保证数据是可靠的、有序的和无重复的,也不反馈接收验证的确认信息。它采用TCP/IP标准的校验和算法(16位字的1的补码和)。保持数据分组边界不属于TCP的功能。

3)IP提供数据包的寻址、路由、分片和重组。寻址使数据包能够从一台IP主机传输到另一台IP主机,路由意味着为传输选择路径,分片和重组使大的IP数据包能够通过“小数据包”网络传输。这些服务中的大多数对Windows Sockets应用而言是完全透明的。


6、每个Windows Sockets应用都会用到的一个IP服务就是寻址,对于一个使用TCP/IP与另一台网络主机联系的网络应用,必须使用一个有效的IP地址。

1)构成可靠数据传输的服务要素有:

被确认的传输。错误检测。确认超时后重传。维持数据的顺序。无重复的数据。流量控制。

2)ICMP是一个“支持协议”,它不传输数据,只是传递控制、报错、通告一类的消息。WSAGetLastError( )函数返回的错误值提示所接收的ICMP消息类型。

例如,若返回WSAHOSTUNREACH错误,说明收到了ICMP的“主机不可达”的错误消息。

3)重定向和源抑制是控制消息,提供直接的数据包重路由和流量控制服务。前者是TCP/IP协议栈之间的低层控制消息,后者是为了通知UDP应用程序它发送数据报的速度太快了。

4)域名服务通过域协议实现。虽然域协议本身是透明的,但是应用程序可以通过调用主机名解析函数来直接访问其服务,这些函数是:gethostbyname( ),gethostbyaddr( ),WSAAsyncGetHostByName( )和WSAAsyncGetHostByAddr()。


7、在Windows环境下,使用Windows socket API进行网络程序开发时,需要调用Windows操作系统的Windows socket动态库。在应用程序中需要包含Windows sockets头文件。windows sockets 2.2版本需要包含WINSOCK2.h头文件(不区分大小写)。同时还需要添加动态库。

一种方法是在头文件中添加。如:

#pragma  comment(lib,"WS2_32.lib")

另一种是在vc中添加。可以选择project ->settting,在link标签下添加wsock32.lib字符串。


8、客户端-服务器模型:

1)它们必须是同一种socket类型。要么都是流(TCP)类型,要么都是数据报(UDP)类型。

2)一个TCP/IP的socket名称包含IP地址、端口号以及协议。

当客户端socket成功联系上一个服务器端的socket时,两者的socket名称构成一个关联。

关联包含5个元素:

协议,客户端IP地址,客户端端口号,服务器IP地址,服务器端口号。

3)对于流类型,关联的生存期与虚电路的建立和撤销有关。大多数UDP应用程序在整个socket生存期中都使用同一个关联。

4)步骤:打开socket,命名socket,与另一个socket建立关联,在socket之间发送和接收数据。关闭socket。

5)在任何网络中,每一个关联都是唯一的。特定的关联决定了网络数据包的唯一性。它引导每个数据包在网络中的传输。关联两端的协议栈维持相关的信息,并把此信息插入在客户端与服务器之间所传输的每个网络层(IP)和传输层(TCP或UDP)数据单元的首部。接收端的协议栈利用其中的关联元素来识别其所属的socket。


9、Windows sockets中用定义的套接字类型SOCKET来表示套接字:

typedef unsigned int u_int;  

typedef u_int SOCKET;  

1)其实所谓的SOCKET的类型只不过是unsigned int的别名罢了。

2)INVALID_SOCKET表示一个无效的套接字,除此之外的0--INVALID_SOCKET-1都表示一个有效的套接字。因此在创建套接字后,都需要与INVALID_SOCKET比较,看创建的套接字是否有效。


10、Windows SOCKET可以支持多种不同的网络协议,并且提供与协议无关的编程接口。因此开发人员就可以相同的格式开发使用任一协议的网络应用程序,而不去关心各种协议的不同。

1)每种协议都有一套不同的IP定址方案(即表示主机地址的方式)。TCP协议和UDP协议通过IP协议传输数据。

而Windows SOCKET通过AF_INET地址家族为IP协议定址。
#define AF_INET 2  

2)网络中每台主机都有一个IP地址,用32位数字来表示。TCP和UDP必须指定端口号。

在Windows SOCKET中sockaddr_in 结构被用来指定IP和端口号。

struct sockaddr_in  

{   

    short    sin_family;  
    u_short   sin_port;  
    struct    in_addr sin_addr;  
    char   sin_zero[8];  

};  

--sin_family表示地址族。使用TCP/IP协议的应用程序必须为aF_INET,来告诉系统使用IP地址家族 。

---sin_port指定服务的端口号。这个无符号的16位的值用以标识服务器所采用的应用层协议。1025--5000范围内的数据被作为服务端口号,可以由用户自定义。 

---sin_addr的取值是为IP地址所设。调用bind( )函数时,它总是指向本地IP地址。 

---sin_zero字段作为填充字段。以便使得该结构与SOCKADDR结构长度相同。

3)函数getservbyname( )和WSAsyncGetServName( )提供了从服务数据库中检索给定了服务名称的端口号的功能。

4)in_addr的定义如下:

struct   in_addr {         
      union {                  
             struct{  
                         u_char s_b1,s_b2,s_b3,s_b4;   

                      }S_un_b;         
             struct {  
                         u_short s_w1,s_w2;   
                      } S_un_w;    
             u_long S_addr;     

                } S_un;  

}  

很显然它是一个存储IP地址的联合体,有三种表达方式:

第一种用四个字节来表示IP地址的四个数字;

第二种用两个双字节来表示IP地址;

第三种用一个长整型来表示IP地址。

5)给in_addr赋值的一种最简单方法是使用inet_addr函数,它可以把一个代表IP地址的字符串赋值转换为in_addr类型。

如 addrto.sin_addr.s_addr=inet_addr("192.168.0.2");

其反函数是inet_ntoa,可以把一个in_addr类型转换为一个字符串。

6)sockaddr类型是用来表示socket地址的类型,同上面的sockaddr_in类型相比,sockaddr的适用范围更广,因为sockaddr_in只适用于TCP/IP地址。


11、为了给socket命名 ,服务器会对socket的地址结构进行初始化,并调用bind( )函数。
sockaddr的定义如下: 

struct    sockaddr {   
                u_short    sa_family;    //地址族   

                char    sa_data[14];    //根据地址族的值定义的地址结构数据区

};    

可知sockaddr有16个字节,而sockaddr_in也有16个字节,所以sockaddr_in是可以强制类型转换为sockaddr的。事实上也往往使用这种方法。

1)不同cpu处理多字节时处理方式不同。Intel x86cpu对多字节的处理方式为高对高低对低。但是在网络上采用的是高对低,低对高的方式。因此也就存在所谓主机字节序和网络字节序的处理问题。

2)Htonl和htons函数实现主机字节顺序和网络字节序的转换功能。

H代表host,主机。N代表net。L代表long。S代表short。

注意:不要使用htonl转换short。

3)当然也有从网络字节序到主机字节序的转换函数:ntohl和ntohs。

你可能感兴趣的:(网络编程)