1、 客户端--服务器模型
每一个网络应用都是基于一个客户端进程和一个服务器进程建立起来的,服务器管理资源,客服端请求某种服务,客户端和服务器都是一个运行中的程序。典型的示意图如下:
我们以一个邮件客服端访问文件为例:
① 客户端发送一个浏览文件的请求给Web服务器;
② 服务器接收请求以后,解释它,从资源中取出相应的文件;
③ 服务器将文件发送到请求的客户端;
④ 客户端接收并显示在屏幕上。
2、网络
网络是连接客户端与服务器之间的通路,对于单个的主机而言,网络只是插在IO总线上的一种,从网络上接收的数据经过适配器-IO总线-桥-存储器总线-主存。
2.1、网桥
桥接工作在OSI网络参考模型的第二层数据链路层,网桥只有2个输入/出端口,是一种以MAC地址来作为判断依据来将网络划分成两个不同物理段的技术,其被广泛应用于早期的计算机网络当中。
我们都知道,以太网是一种共享网络传输介质的技术,在这种技术下,如果一台计算机发送数据的时候,在同一物理网络介质上的计算机都需要接收,在接收后分析目的MAC地址,如果是属于目的MAC地址和自己的MAC地址相同便进行封装提供给网络层,如果目的MAC地址不是自己的MAC地址,那么就丢弃数据包。
桥接的工作机制是将物理网络段(也就是常说的冲突域)进行分隔,根据MAC地址来判断连接两个物理网段的计算机的数据包发送。
下面,我们举个例子来为各位网友讲解:
在下图中的网络结构中,有两台集线器分别连接多台计算机,我们分别将A集线器和B集线器定为A冲突域和B冲突域。在这样的网络环境中,如果计算机A向计算机C发送数据包时,集线器A会将数据包在整个网络中的全部计算机(包括集线器B)发送一遍,而不管这些数据包是不是需要发送到另一台区域B。
我们再将集线器A和集线器B分别连接到网桥的两个端口上,如果计算机A再向计算机C发送数据包时会遇到什么样的情况呢?这时集线器A也是同样会将数据包在全网发送,当到达网桥后,网桥会进行数据包目的MAC地址的分析,然后对比自己学习到的MAC地址表,如果这个表中没有此MAC地址,网桥便会在两个网段上的发送数据包(通过网桥后全网发送),同时会将计算机A的MAC地址记录在自己的表当中。
经过多次这样的记录,网桥会将所有的MAC地址记录,并划分为两个段。这时计算机A再次发送数据包给B的时候,因为这两台计算机同处在一个物理段位上,数据包到达网桥时,网桥会将目的MAC地址和自己的表进行对比,并且判断计算机A和计算机B在同一个段位上,便不会转发到区域B当中,而如果不在同一个物理段当中,网桥便会允许数据包通过网桥。
2.2、交换机
交换同样工作在OSI网络参考模型的第二层数据链路层,也是一种以MAC地址来作为判断依据来将网络划分成两个不同段的技术,不同的是交换将物理网段划分到每一个端口当中,简单的理解就是一种多端口的网桥,它实际上是一种桥接技术的延伸。
在前面的了解当中,我们已经知道桥接是连接两个不同的物理网段(冲突域)的技术,交换是连接多个物理网段技术,典型的交换机通常都有多个端口,每个端口实际上就是一个网桥,当连接到交换机端口的计算机要发送数据包时,所有的端口都会判断这个数据包是否是发给自己的,如果不是就将其丢弃,这样就将冲突域的概念扩展到每个交换机端口上。
我们还是举例为大家说明,在下面的图中,我们可以看到计算机A、B分别连接到交换机的不同端口当中,当计算机A向B发送数据包时,假设这时A端口并没有学习到B端口的MAC地址,这时,A端口便会使用广播将数据包发送到除A端口以外的所有端口(广播域),当其他计算机接收到数据包后会与自己的MAC地址进行对比,然后简单的丢弃数据包;当B接收到数据包后,通过对比后接收数据包,并且记录源地址。通过反复这样的学习,交换机会构建一个基于所有端口的转发数据库,存储在交换机的内容可寻址存储器当中(CAM)。
在交换机学习到所有端口的信息后,计算机A再次发送数据包给B时,就不再广播地址,而是直接发送到转发数据库中所对应的B端口。通过这样的学习,在交换机上实现了微分段,每个连接到交换机端口的计算机都可以独享带宽。
2.3、路由器
路由工作在OSI参考模型的第三层网络层当中,它是基于第三层的IP地址信息来作为判断依据来将网络划分成不同段(IP子网)的技术,与桥接和交换不同,路由划分的是独立的逻辑网段,每个所连接的网段都具有独立的网络IP地址信息,而不是以MAC地址作为判断路径的依据,这样路由便有隔离广播的能力;而交换和桥接是划分物理网段,它们仅仅是将物理传输介质进行分段处理。同时路由具备路径选择的功能,会根据不同的目的IP地址来分析到达目的地最合适的路径。
如图1所示,当路由器收到一个IP报文的时候,将报文中的目的IP地址提取出来,然后与路由表中路由表项包含的目的地址进行比较。如果与某路由项中的目的地址相同,则认为与此路由项匹配;如果没有路由项能够匹配,则丢弃该IP报文。
http://images.51cto.com/files/uploadimg/20121207/1210130.jpg
3、数据包转发过程
应用层会指定发送的服务器的域名(或者IP)和端口号、以及要发送数据的内容,传递给下一层传输层。
传输层会在把应用层的报文当成自己的数据,然后在前面拼接源端口号,和目标端口号,其中源端口号就是客户端进程监听的端口号,这个端口号一般不是固定的,由操作系统在49152~65535范围内动态分配,而目标端口号就是服务器接收数据的端口号,一般是固定的,在java代码中会指明。
网络层会在传输层报文的基础上增加源IP和目标IP,其中源IP就是本地网卡的IP地址,目标IP是服务器的IP,如果java代码中指定的是服务器的域名,那么首先需要通过DNS服务器将域名解析为IP,域名解析的流程:先查浏览器缓存->操作系统缓存->hosts文件->DNS服务器。
数据链路层会在网络层的基础上增加源MAC地址和目标MAC地址,其中源MAC地址就是本机网卡的MAC地址,目标MAC地址是下一跳
网络设备(一般是交换机或路由器)的MAC地址,注意目标MAC地址一般不是服务器的MAC地址(如果客户端和服务器端在同一个网段,那么目标MAC地址就是服务器的MAC地址),因为客户端根本就无法得知服务器的MAC地址,所以数据链路层采用下一跳的机制转递数据,那么怎么知道我的下一跳是谁呢?下面就要请出ARP协议了,ARP会发出一个广播,告诉全世界,大家好,我的IP地址是192.168.1.6
,我的MAC地址是00-50-56-C0-88-01
,当同一个网段上的主机接收到ARP报文时,会将这些信息添加自己的ARP缓冲区中的ARP列表,同时将自己的IP地址和MAC地址回应给发送者,这样每个位于同一个网段的主机都有整个网段内各个主机的IP与MAC地址的对应关系了。
4、Socket套接字
4.1、什么是Socket套接字?
套接字的概念很简单,每台主机有一个唯一的主机地址标识,同时主机内还有标识自己进程的序号id,称作端口,将这两个标识符结合就构成了一个套接字(socket),这个套接字能唯一标识网络中的一个进程。(网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket, 又称为“套接字”。)
理解socket:Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的
4.2、如何使用Socket进行网络传输?
要创建套接字,必须使用套接字模块中的socket.socket()
函数,该函数具有一般语法
s = socket.socket (socket_family, socket_type, protocol = 0)
这里是上述参数的描述
-
socket_family - 它的值可以是:
AF_UNIX
或AF_INET
,如前所述。 -
socket_type - 它的值可以是:
SOCK_STREAM
或SOCK_DGRAM
。 -
protocol - 这通常被省略,默认为
0
。
当创建了套接字对象这后,就可以使用所需的函数来创建客户端或服务器程序。 以下是所需函数的列表:
服务器套接字方法
编号 | 方法 | 描述 |
---|---|---|
1 | s.bind() |
此方法将地址(主机名,端口号对)绑定到套接字。 |
2 | s.listen() |
此方法设置并启动TCP侦听器。 |
3 | s.accept() |
这被动地接受TCP客户端连接,等待直到连接到达(阻塞)。 |
客户端套接字方法
编号 | 方法 | 描述 |
---|---|---|
1 | s.connect() |
此方法主动启动TCP服务器连接。 |
通用套接字方法
编号 | 方法 | 描述 |
---|---|---|
1 | s.recv() |
此方法接收TCP消息。 |
2 | s.send() |
该方法发送TCP消息 |
3 | s.recvfrom() |
此方法接收UDP消息 |
4 | s.sendto() |
此方法发送UDP消息 |
5 | s.close() |
此方法关闭套接字 |
6 | socket.gethostname() |
返回主机名 |
4.3、TCP和UDP
TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。
UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。
我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:
- 客户端向服务器发送一个SYN J
- 服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
- 客户端再想服务器发一个确认ACK K+1
只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?请看下图:
从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。