Socket 深入理解

Socket

计算机网络基础

image

数据交互过程
image

各层主要协议
image

TCP/IP接口

image

套接字

在TCP/IP网络环境中,可以使用套接字来建立网络连接,实现主机之间的数据传输。

套接字编程接口的起源与发展

在20世纪80年代早期,美国国防部高级研究计划署(Defense Advanced Research Projects Agency,ARPA)资助了加州大学伯克利分校开发并推广了一个包括TCP/IP协议的UNIX,
称为BSD UNIX(Berkeley Software Distribution UNIX)操作系统,Socket编程接口是这个操作系统的一部分,称为Berkeley Sockets。
后来许多计算机供应商将BSD系统移植到他们的硬件上,并将其作为商业操作系统产品的基础,广泛地应用于各种计算机上。
由于BSD UNIX系统的广泛应用,大多数人已经接受了Socket编程接口,后来的许多操作系统并没有另外开发一套其他的编程接口,而是选择了支持Socket编程接口。

套接字(Socket),在网络通信中是支持TCP/IP网络通信的基本操作单元,可以看作是一个接口,
该接口在操作系统控制下帮助本地主机建立或拥有的应用程序与其他(远程)应用进程相互发送和接收数据。
这意味着Socket用来让一个进程和其他进程互通信息,就像用电话和其他人交流一样,通过Socket为客户和服务器建立了一个双向的连接管道。

作为连接应用程序和协议实现的桥梁,Socket在应用程序中创建,通过绑定应用程序所在的IP地址和端口号,与系统的协议实现建立关系。
此后,应用程序送给Socket的数据,由Socket交给协议实现向网络上发送出去,计算机从网络上收到与该Socket绑定IP地址和端口号相关的数据后,由系统协议实现交给Socket,
应用程序便可从该Socket中提取接收到的数据,网络应用程序就是这样通过Socket进行数据的发送与接收的。

套接字接口并没有直接使用协议类型来标识通信时的协议,而是采用一种更灵活的方式——协议簇+套接字类型,以方便网络应用程序在多协议簇的同类套接字程序中移植。

在Socket通信中,常用的协议簇有:

● PF_INET:IPv4协议簇。

● PF_INET6:IPv6协议簇。

● PF_IPX:IPX/SPX协议簇。

● PF_NETBIOS:NetBIOS协议簇。

在Socket通信中,常用套接字类型包括三类:

●流式套接字(SOCK_STREAM)。流式套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收,数据传输可以是双向的字节流。

● 数据报套接字(SOCK_DGRAM)。数据报套接字用于提供无连接的数据传输服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或重复,且无法保证顺序地接收到数据。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

● 原始套接字(SOCK_RAW)。当使用前两种套接字无法完成数据收发任务时,原始套接字提供了更加灵活的数据访问接口,使用它可以在网络层上对Socket进行编程,发送和接收网络层上的原始数据包。

套接字接口层的位置与内容
关于这些关系要注意四点:

1)一个程序可以同时使用多个套接字,不同套接字完成不同的传输任务。

2)多个应用程序可以同时使用同一个套接字,不过这种情况并不常见。

3)每个套接字都有一个关联的本地TCP或UDP端口,它用于把传入的分组指引到应该接收它们的应用程序。
端口,标识了主机上的套接字,进而标识了主机上的特定应用程序。

4)TCP和UDP的端口号是独立使用的,有时候一个TCP的端口号也会关联多个套接字,因此不能仅仅用端口来标识套接字,
不过尽管如此,TCP仍然有能力清晰地区分开关联在一个端口上的多个套接字。

image

套接字通信

进行网络通信时至少需要一对套接字,其中一个运行在客户端,称之为客户套接字,另一个运行于服务器端,称之为服务器套接字。网络应用程序的通信总是以套接字为线索,以五元组(源IP、源端口、目的IP、目的端口、协议)为通信基础进行数据传输,其基本过程如下:

1)建立一个Socket。

2)配置Socket。

3)连接Socket(可选)。

4)通过Socket发送数据。

5)通过Socket接收数据。

6)关闭Socket。

由此可见,与文件操作类似,作为一类特殊的文件操作,网络操作以Socket为网络描述符,通过其指向的数据结构存储了与当前通信相关的五元组信息,并在数据发送和接收时对该数据结构的内容进行读写访问,当结束网络操作后,通过Socket释放已分配的资源。

使用套接字进行数据处理有两种基本模式:同步和异步。
同步模式的特点是在通过Socket进行连接、接收、发送数据时,客户和服务器在接收到对方响应前会处于阻塞状态,
即一直等到I/O条件满足才继续执行下面的操作。同步模式只适用于数据处理不太多的场合。
当程序执行的任务很多时,长时间的等待可能会让用户无法忍受。

异步模式的特点是在通过Socket进行连接、接收、发送操作时,客户或服务器会利用多种机制获知I/O条件满足的事件,
然后再进行连接、接收、发送处理,这样就可以更灵活、高效地处理网络通信。异步套接字更加适用于进行大量数据处理、复杂网络I/O的场合。

流式套接字

TCP连接的建立与终止

为了建立一条TCP连接,需要以下三个基本步骤:

1)请求端(通常称为客户)发送一个SYN报文段指明客户打算连接的服务器端口号,以及初始序号(Initial Sequence Number,ISN),SYN请求发送后,客户进入SYN_SENT状态。

2)服务器启动后首先进入LISTEN状态,当它收到客户发来的SYN请求后,进入SYN_RCV状态,发回包含服务器的初始序号的SYN报文段作为应答,同时将确认序号设置为客户的初始序号加1,对客户的SYN报文段进行确认。一个SYN将占用一个序号。

3)客户接收到服务器的确认报文后进入ESTABLISHED状态,表明本方连接已成功建立,客户将确认序号设置为服务器的ISN加1,对服务器的SYN报文段进行确认,当服务器接收到该确认报文后,也进入ESTABLISHED状态。

这三个报文段完成连接的建立,这个过程称为“三次握手”,如图5-3所示。
image

图5-4显示了终止一个连接的典型握手顺序。首先进行关闭的一方(即发送第一个FIN)将执行主动关闭,而另一方(收到这个FIN)执行被动关闭,
具体步骤如下:

1)客户的应用进程主动发起关闭连接请求,它将导致TCP客户发送一个FIN报文段,用来关闭从客户到服务器的数据传送,此时客户进入FIN_WAIT_1状态。

2)当服务器收到这个FIN,它发回一个ACK,进入CLOSE_WAIT状态,确认序号为收到的序号加1。与SYN一样,一个FIN将占用一个序号。客户收到该确认后进入FIN_WAIT_2状态,表明本方连接已关闭,但仍可以接收服务器发来的数据。

3)接着服务器程序关闭本方连接,其TCP端发送一个FIN报文段,进入LAST_AC状态,当客户接收到该报文段后进入TIME_WAIT状态。

4)客户在收到服务器发来的FIN请求后,发回一个确认,并将确认序号设置为收到的序号加1。发送FIN将导致应用程序关闭它们的连接,服务器接收到该确认后,连接关闭。这些FIN的ACK是由TCP软件自动产生的。

图5-4 TCP四次交互关闭连接
image

为什么需要TIME_WAIT状态呢?设立TIME_WAIT有两个目的:

1)当由主动关闭方发送的最后的ACK丢失并导致另一方重新发送FIN时,TIME_WAIT维护连接状态。
当最后的ACK发生丢失时,由于执行被动关闭的一方没有接收到最后序号的ACK,则会运行超时并重新传输FIN。
假如执行主动关闭的一方不进入TIME_WAIT状态就关闭了连接,那么此时重传的FIN到达时,由于TCP已经不再有连接的信息了,
所以它就用RST(重置连接)报文段应答,导致对等方进入错误状态而不是有序终止状态
。由此看来,TIME_WAIT状态延长了TCP对当前连接的维护信息,对于正确处理连接的正常关闭过程中确认报文丢失是很有必要的。

2)TIME_WAIT为连接中“离群的段”提供从网络中消失的时间。
IP数据包在广域网传输中不仅可能会丢失,还可能延迟。如果延迟或重传报文段在连接关闭之后到达,通常情况下,因为TCP仅仅丢弃该数据并响应RST,
当该报文段到达发出延时报文段的主机时,因为该主机也没有记录该连接的任何信息,所以它也丢弃该报文段。
然而如果两个相同主机之间又建立了一个具有相同端口号的新连接,那么离群的段就可能被看成是属于新连接的,
如果离群的段中数据的任何序号恰好处在新连接的当前接收窗口中,数据就会被新连接接收,其结果是破坏新连接,
使TCP不能保证以顺序的方式递交数据。
因此TIME_WAIT状态确保了旧连接的报文段在网络上消失之前不会被重用,从而防止其在上述情况下扰乱新连接。

流式套接字的通信过程
(1)基于流式套接字的服务器进程的通信过程

在通信过程中,服务器进程作为服务提供方,被动接受连接请求,决定接受或拒绝该请求,并在已建立好的连接上完成数据通信。其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用TCP(可靠的传输服务)进行通信;

3)指定本地地址和通信端口;

4)等待客户的连接请求;

5)进行数据传输;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。

(2)基于流式套接字的客户进程的通信过程

在通信过程中,客户进程作为服务请求方,主动请求建立连接,等待服务器的连接确认,并在已建立好的连接上完成数据通信。其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用TCP(可靠的传输服务)进行通信;

3)指定服务器地址和通信端口;

4)向服务器发送连接请求;

5)进行数据传输;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。

image

数据报套接字

TCP缺点
首先,使用TCP协议传输数据的代价相对于UDP而言要高许多。
如果使用TCP协议实现一次请求-应答交换,由于TCP协议使用3次握手建立连接,并且在关闭连接时要进行4次交互,
那么最小事务处理时间将是2×RTT+SPT,其中RTT表示客户与服务器之间的往返时间,SPT表示客户请求的服务器处理时间。
相比之下,UDP没有连接建立和释放,就单个UDP请求-应答交换而言的最小事务处理时间仅为RTT+SPT,比TCP减少了一个RTT。
因此,传输代价是使用TCP协议时必须要考虑的一个损失。

其次,连接的存在意味着连接维护的代价。
服务器要为每一个已经建立连接的客户分配单独使用的资源,如用于数据接收和发送的TCP缓冲区、存储连接相关参数的TCP变量等,
这对于有可能为同时来自数百个不同客户的请求提供服务的服务器来说,会严重增加该服务器的负担,甚至可能造成服务器资源的过耗。

最后,在每个连接的通信过程中,TCP拥塞控制中的慢启动策略会起作用,使得每个TCP连接都要起始于慢启动阶段。
由此带来的结果是数据通信的效率不会马上达到TCP的最大传输性能,也因此增大了使用TCP协议进行网络通信的传输延迟。

UDP协议是一个无连接的传输层协议,提供面向事务的简单、不可靠的信息传送服务。

UDP协议的传输特点表现在以下方面:

● 多对多通信。UDP在通信实体的数据量上具有更大的灵活性,多个发送方可以向一个接收方发送报文,一个发送方也可以向多个接收方发送数据,更重要的是,UDP能让应用使用底层网络的广播或组播设施交付报文。

不可靠服务。UDP提供的服务是不可靠交付的,即报文可以丢失、重复或失序,它没有重传设施,如果发生故障,也不会通知发送方。

缺乏流量控制。UDP不提供流量控制,当数据包到达的速度比接收系统或应用的处理速度快时,只是将其丢弃而不会发出警告或提示。

报文模式。UDP提供了面向报文的传输方式,在需要传输数据时,发送方准确指明要发送的数据的字节数,UDP将这些数据放置在一个外发报文中,
在接收方,UDP一次交付一个传入报文。因此当有数据交付时,接收到的数据拥有和发送方应用程序所指定的一样的报文边界。

数据报套接字编程的适用场合

1)音频、视频的实时传输应用。 
2)广播或多播的传输应用。
3)简单高效需求大于可靠需求的传输应用。

数据报套接字的通信过程

使用数据报套接字传送数据类似于生活中的信件发送,与流式套接字的通信过程有所不同,数据报套接字不需要建立连接,而是直接根据目的地址构造数据包进行传送。

(1)基于数据报套接字的服务器进程的通信过程

在通信过程中,服务器进程作为服务提供方,被动接收客户的请求,使用UDP协议与客户交互,其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用UDP(无连接的传输服务)进行通信;

3)指定本地地址和通信端口;

4)等待客户的数据请求;

5)进行数据传输;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。

(2)基于数据报套接字的客户进程的通信过程

在通信过程中,客户进程作为服务请求方,主动向服务器发送服务器请求,使用UDP协议与服务器交互,其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用UDP(无连接的传输服务)进行通信;

3)指定服务器地址和通信端口;

4)向服务器发送数据请求;

5)进行数据传输;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。

image

原始套接字

原始套接字是允许访问底层传输协议的一种套接字类型,提供了普通套接字所不具备的功能,能够对网络数据包进行某种程度的控制操作。
因此原始套接字通常用于开发简单网络性能监视程序以及网络探测、网络攻击等的工具。
由于这种套接字类型给攻击者带来了数据包操控上的便利,在引入Windows环境时备受争议,甚至在MSDN中明确对该套接字的使用给出了警告。

image

原始套接字提供普通TCP和UDP套接字不提供的以下三种能力:

1)发送和接收ICMPv4、IGMPv4和ICMPv6等分组。
原始套接字能够处理在IP头中预定义的网络层上的协议分组,如ICMP、IGMP等。
举例来说,ping程序使用原始套接字发送ICMP回射请求并接收ICMP回射应答。多播路由守护程序也使用原始套接字发送和接收IGMPv4分组。
这个能力还使得使用ICMP和IGMP构造的应用程序能够完全作为用户进程处理,而不必往内核中额外添加代码。

2)发送和接收内核不处理其协议字段的IPv4数据包。
对于8位IPv4协议字段,大多数内核仅仅处理该字段值为1(ICMP协议)、2(IGMP协议)、6(TCP协议)、17(UDP协议)的数据报,然而为协议字段定义的其他值还有很多,在IANA的"Protocol Numbers"中有详细的定义。
举例来说,OSPF路由协议既不使用TCP也不使用UDP,而是直接通过IP协议承载,协议类型为89。
如果想在一个没有安装OSPF路由协议的系统上处理OSPF数据报文,那么实现OSPF的程序必须使用原始套接字读写这些IP数据包,因为内核不知道如何处理协议字段为89的IPv4数据包,这个能力还延续到IPv6。

3)控制IPv4首部。
使用原始套接字不仅能够直接处理IP协议承载的协议分组,而且能够直接控制IP首部,
通过设置IP_HDRINCL套接字选项可以控制IPv4首部字段的自行构造。我们可以利用该选项构造特殊的IP首部以达到某些探测和访问需求。  

原始套接字的通信过程

基于上述对原始套接字应用场合的分析,使用此类套接字编写的程序往往面向特定应用,侧重于网络数据的构造与发送或者捕获与分析。

使用原始套接字传送数据与使用数据报套接字的过程类似,不需要建立连接,而是在网络层上直接根据目的地址构造IP分组进行数据传送。以下从发送和接收两个角度来分析原始套接字的通信过程。

(1)基于原始套接字的数据发送过程

在通信过程中,数据发送方根据协议要求,将要发送的数据填充进发送缓冲区,同时给发送数据附加上必要的协议首部,全部填写好后,将数据发送出去。其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用原始套接字进行通信,根据需要设置IP控制选项;

3)指定目的地址和通信端口;

4)填充首部和数据;

5)发送数据;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。

在数据发送前,应用程序需要首先进行Windows Sockets DLL初始化,并创建好原始套接字,为网络通信分配必要的资源。

发送数据需要填充目的地址并构造数据,在步骤2,根据应用的不同,原始套接字可以有两种选择:仅构造IP数据或构造IP首部和IP数据。此时程序设计人员需要根据实际需要对套接字选项进行配置。

(2)基于原始套接字的数据接收过程

在通信过程中,数据接收方设定好接收条件后,从网络中接收到与预设条件相匹配的网络数据,如果出现了噪声,对数据进行过滤。其基本通信过程如下:

1)Windows Sockets DLL初始化,协商版本号;

2)创建套接字,指定使用原始套接字进行通信,并声明特定的协议类型;

3)根据需要设定接收选项;

4)接收数据;

5)过滤数据;

6)关闭套接字;

7)结束对Windows Sockets DLL的使用,释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值