时光紧张,先记一笔,后续优化与完善。
本章重点讲解WindowsSockets的基本知识。协议特征,IP定址,TCP和UDP Socket应用程序所调用的windows Sockets API,套接字选项。
Windows Socket
应用程序与WindowsSockets的关系
套接字
应用程序最少可以应用两种套接字,即流套接字和数据报套接字。
流套接字:提供双向有序,无重复并且没有记录边界的数据流服务。
数据包套接字:虽然支持双向的数据流,但不保障数据是可靠的有序的和无重复的。也就是说,从数据报套接字接收数据有可能是重复的,或者和数据收回时的顺序不同。
type unsigned int u_int;
type u_int SOCKET;
WindowsSockets中除了INVALID_SOCKET不是一个有效的套接字外,在0~INVALID_SOCKET-1之间的数值都是有效的套接字。也就意味着在判断创建套接字是不是有效,则:SOCKET s=socket(_);
if(INVALID_SOCKET == s)
{ //失败}
INVALID_SOCKET的声明:#define INVALID_SOCKET (SOCKET)(~0)
协议特征
面向连接与面向无连接
网络服务分面向连接和面向无连接两种。对于面向连接服务,发送数据的源主机必须首先与目标主机连接。这种连接是通过三次握手方法建立起来的。建立连接的进程须要很多开支,花费必定的时光。当源主机与目标主机建立连接后,就能够停止数据传输了,当完成数据传输后释放连接。因为在数据传输进程中,会停止数据的验证等工作,所以大部分面向连接的服务能够保障传输数据的正确性。
在面向无连接服务中,每一个数据分组是在网络上传输的独立单元,称作数据报。发送数据的源主机和目标主机之间没有建立连接的进程。源主机将包括目标地址和源地址的数据报之间发送到网络上,该数据报是否正确到达目标主机不得而知。无连接服务因其省去许多数据保障机制,因此通信协议绝对简单,通信效率较高。
可靠性与次序性
通常情况下,可靠性、次序性与协议时面向连接还是面向无连接的性子有密切相关。可靠性是指源主机发送的数据都能到达目标主机。不具有可靠性的协议则不能保障数据完整无误的到达目标主机。大多数情况下,面向连接的协议能够保障数据的可靠性。
次序性是指能够对数据到达目标主机的顺序停止处置。具有次序性的协议保障接收到的数据顺序就是源主机发送的数据顺序。
面向无连接的协议一般不能保障数据的完整性和次序性,而面向连接的协议能够做到保障数据的完整性和次序性。
面向消息
对每一个离散命令来讲,如果传输协议包每条命令作为独立的消息停止传输,则称该协议是面向消息的。对接收端来讲,在接收数据时,每次接收的数据恰是对应发送端发送的每条离散消息。
如上图:源主机向目标主机发送64字节和32字节两条消息。目标主机会对应发送两条读取命令,虽然接收数据的缓冲区大小是128个字节,但是这两个读取命令分别返回64字节和32字节数据。目标主机的第一个读取调用,不会将这两个包都接收,这被称为”保护消息边界”,也就是美国数据都被作为一个独立的消息。
无保护消息边界的协议通常被称为“基于流的协议”。流服务的含义是指连续的数据传输。对发送端来讲,这意味着答应系统将原始数据分解成小的数据,或者将小的数据积累成一个较大的数据包,然后发送出去。是不是将几个数据包积累在一起,受到很多因素影响,例如最大传输单元,Nagle算法等。对于接收端来讲,数据一旦到达,网络堆栈就开始读取它,并将数据缓存起来,等待应用程序处置。在应用程序请求最大数据时,系统会在不溢出应用程序缓冲区的前提下,尽可能返回更多的数据。
如上图:源主机向目标主机发送64字节和32字节两条消息。但是,系统堆栈将这些数据聚合成一个大的数据包,发送给目标主机。在接收端,网络堆栈将全部进来的数据包聚合在一起,保存在既定进程中。有关目标主机执行一次128字节缓冲区的读取,则系统立即返回96字节数据,如果目标主机执行一次30字节数据读取,则系统返回30字节数据。
从容关闭
大多数面向连接协议都支持从容关闭。子啊这种关闭进程中,一方即使关闭连接,但对方仍然可以读取网络堆栈中的数据。如果面向连接的协议不支持从容关闭,则只有一方关闭了通信,都市致使连接立即中断和数据丢失,接收端不能读取这些数据。对于TCP协议来讲,只有连接双方都执行一次关闭,才能完整中断连接。
在WindowsSockets中,关闭套接字的连接和关闭套接字是不同的。关闭套接字的连接时双方要交换协议消息,按照必定顺序关闭连接。而关闭套接字是指关闭套接字句柄,释放占用资源。
WindowsSockets定义了从容关闭和“硬”关闭两种关闭连接的方法。在从容关闭方法下,先把等待发送的数据发送出去,然后才关闭连接。在“硬”关闭方法下,任何还没有发送的数据都将被丢失。
WindowsSocketsAPI提供了shutdown()和WSASendDisconnect()实现关闭连接的功能。closesocket()实现关闭套接字的功能,同时也隐含执行shutdown()。在应用程序中,虽然可以通过设置套接字选项来控制closesocket()的行为,但是应用程序可以应用上面方法,执行从容关闭,从而保障在关闭连接之前,数据都被接收。
如上图,客户端执行从容关闭的进程:
- 客户端以SD_SEND为参数调用shutdown(),开始关闭连接。该函数的调用说明客户端不再发送数据(客户端还可以接收数据)。
- 服务器接收到FD_CLOSE网络事件,得知客户端正在执行从容关闭,此时全部数据都被服务器接收。
- 服务器发送数据。
- 服务器以SD_SEND为参数调用shutdown(),通知客户端不再发送数据,然后调用closesocket()关闭套接字。
- 收到FD_READ网络事件后,客户端收到服务器发送的数据。接着客户端接收到FD_CLOSE网络事件。
- 客户端调用closesocket()关闭套接字。
IP定址
Windows系统一个有效的特征是能够同步支持多种不同的网络协议。由于WindowsSockets提供了与协议有关的编程接口,开辟人员就能够开辟直接应用任何一种协议的网络应用程序。尽管如此,要实现网络通信定位和网络连接,仍然必须了解如果为主机定址。每种协议都有一套不同的定址计划。本节重点讲解IP协议的定址方法。
IP定址
TCP协媾和UDP协议通过IP协议传输数据。WindowsSockets通过AF_INET地址家属为IP通信定址。A:address,F:family。AF_INET的声明:#define AF_INET 2
在WindowsSocket中,SOCKADDR_IN结构来指定IP地址和端口号,声明如下
struct sockaddr_in
{
short sin_family;地址家属;必须为AF_INET,以告知WindowsSockets应用程序应用IP地址家属
u_short sin_port;服务端口号;根据第二章分析的端口的范围分别,应取 1024~49151
struct in_addr sin_addr;in_addr类型的IP地址;sin_addr把一个IP地址保存为一个4字节的数值。
char sin_zero[8];填充该结构的大小,使之与SOCKADDR结构大小相同。
}
字节顺序问题
针对“大头”(big-endian)和“小头”(little-endian)形式的编号,不同计算机处置器的表现方法不同。在计算机中把IP地址和端口号指定为多字节数字时,这个数就按照“主机字节”(host-byte)顺序表现。但是在网络上指定IP地址和端口号,这个数必须按照”大头”形式来表现,也就是按照从最有意义的字节到最无意义的字节来表现数据,这里称为“网络字节”(network-byte)顺序。
htonl(),htons()实现从主机字节顺序转换为网络字节顺序的功能。
ntonl(),ntohs()实现从网络字节顺序转换为主机字节顺序的功能。
u_long htonl(u_long hostlong);u_short htons(u_short hostshort);
u_long ntohl(u_long netlong); u_short ntohs(u_short netshort);
h:host主机;n:net网络;l:long;s:short;to:转换
基本TCP套接字编程
开辟套接字应用程序时,首先应当停止WindowsSockets的初始化,加载WindowsSockets的实现,然后创建套接字,对TCP套接字来讲,须要在socket()或者WSASocket()中指明SOCK_STREAM套接字类型。当服务器和客户端通讯结束时,关闭套接字,释放WindowsSockets的实现。
基本UDP套接字编程
与面向连接的协议比拟,面向无连接协议极为不同,其中一个主要的不同点就是客户端与服务器之间不必建立连接。
套接字选项
创建套接字后,通过套接字选项对其各种属性停止设置,便可对套接字的行为产生影响。有的套接字选项只能用于返回套接字信息;有的选项不仅可以返回套接字信息,而且可以通过设置该选项影响套接字的行为。Getsockopt()返回套接字选项信息;setsockopt()设置套接字选项。
SOL_SOCKET选项级别
设置SOL_SOCKET选项级别时,调用setsockopt()和getsockopt()所设置或者获取的信息为套接字本身的特征,这些信息与基层协议有关。
SOL_SOCKET选项类型 |
||
选择 |
数据类型 |
说明 |
SO_ACCEPTCONN |
BOOL |
如果为真,表现套接字处于监听模式。SOCK_DGRAM类型的套接字不支持该选项 |
SO_BROADCAST |
BOOL |
如果为真,标明套接字已设置成为广播消息发送 |
SO_DEBUG |
BOOL |
如果为真,则答应输出调试信息 |
SO_DONTLINGER |
BOOL |
如果为真,则禁止SO_LINGER |
SO_DONTROUTE |
BOOL |
如果为真,则不会做出路由选择 |
SO_ERROR |
int |
返回和设置以具体套接字为基本的错误代码 |
SO_KEEPALIVE |
BOOL |
如果为真,则套接字在会话进程中发送”保持活动”消息。“保持活动”消息的发送要以少于2小时为时光间隔 |
SO_LINGER |
Struct linger FAR* |
设置或者获取当前的迁延值 |
SO_OOBINLINE |
BOOL |
如果为真,则带外数据会在普通数据流中返回 |
SO_RCVBUF |
int |
设置或获取接收发送数据的缓冲区长度 |
SO_REUSEADDR |
BOOL |
如果为真,套接字可与一个正在被其他套接字应用的地址绑定在一起 |
SO_SNDBUF |
int |
设置或获取发送数据缓冲区的大小 |
SO_TYPE |
int |
返回套接字的类型,如SOCK_DGRAM,SOCK_STREAM |
SO_SNDTIMEO |
int |
设置或获取套接字在发送数据的超时时光 |
SO_RCVTIMEO |
int |
设置或获取套接字在接收数据的超时时光 |
文章结束给大家分享下程序员的一些笑话语录: 人在天涯钻,哪儿能不挨砖?日啖板砖三百颗,不辞长做天涯人~
--------------------------------- 原创文章 By 数据和字 ---------------------------------