JAVA Socket 底层是怎样基于TCPIP 实现的

Python021

JAVA Socket 底层是怎样基于TCPIP 实现的,第1张

首先必须明确:TCP/IP模型中有四层结构: 应用层(Application Layer)、传输层(Transport Layer)、网络层(Internet Layer

)、链路层(LinkLayer)

其中Ip协议(Internet Protocol)是位于网络层的,TCP协议时位于传输层的。通过Ip协议可以使可以使两台计算机使用同一种语言,从而允许Internet上连接不同类型的计算机和不同操作系统的网络。Ip协议只保证计算机能够接收和发送分组数据。当计算机要和远程的计算机建立连接时,TCP协议会让他们建立连接:用于发送和接收数据的虚拟电路。

套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA

有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包,即ServerSocket不能接收实际的数据包。

套接字是基于TCP/IP实现的,它是用来提供一个访问TCP的服务接口,或者说套接字socket是TCP的应用编程接口API,通过它应用层就可以访问TCP提供的服务。

在JAVA中,我们用 ServerSocket、Socket类创建一个套接字连接,从套接字得到的结果是一个InputStream以及OutputStream对象,以便将连接作为一个IO流对象对待。通过IO流可以从流中读取数据或者写数据到流中,读写IO流会有异常IOException产生。

java 中集合类的关系

参考文献:

http://zhangshixi.iteye.com/blog/674856l

https://www.cnblogs.com/leesf456/p/5308358.html

ArrayList是List接口的可变数组非同步实现,并允许包括null在内的所有元素。

底层使用数组实现

该集合是可变长度数组,数组扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量增长大约是其容量的1.5倍,这种操作的代价很高。

采用了Fail-Fast机制,面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险

remove方法会让下标到数组末尾的元素向前移动一个单位,并把最后一位的值置空,方便GC

参考文献:

1. http://www.cnblogs.com/ITtangtang/p/3948610.htmll

2. https://www.cnblogs.com/leesf456/p/5308843.html

LinkedList是List接口的双向链表非同步实现,并允许包括null在内的所有元素。

底层的数据结构是基于双向链表的,该数据结构我们称为节点

双向链表节点对应的类Node的实例,Node中包含成员变量:prev,next,item。其中,prev是该节点的上一个节点,next是该节点的下一个节点,item是该节点所包含的值。

它的查找是分两半查找,先判断index是在链表的哪一半,然后再去对应区域查找,这样最多只要遍历链表的一半节点即可找到

参考文献: http://zhangshixi.iteye.com/blog/672697

参考文献: http://blog.csdn.net/lizhongkaide/article/details/50595719

HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键,但不保证映射的顺序。

底层使用数组实现,数组中每一项是个单向链表,即数组和链表的结合体;当链表长度大于一定阈值时,链表转换为红黑树,这样减少链表查询时间。

HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Node对象。HashMap底层采用一个Node[]数组来保存所有的key-value对,当需要存储一个Node对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Node时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Node。

HashMap进行数组扩容需要重新计算扩容后每个元素在数组中的位置,很耗性能

采用了Fail-Fast机制,通过一个modCount值记录修改次数,对HashMap内容的修改都将增加这个值。迭代器初始化过程中会将这个值赋给迭代器的expectedModCount,在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map,马上抛出异常

参考文献: http://blog.csdn.net/zheng0518/article/details/42199477

Hashtable是基于哈希表的Map接口的同步实现,不允许使用null值和null键

底层使用数组实现,数组中每一项是个单链表,即数组和链表的结合体

Hashtable在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。Hashtable底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

synchronized是针对整张Hash表的,即每次锁住整张表让线程独占

参考文献: http://blog.csdn.net/zheng0518/article/details/42199477

ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。

它使用了多个锁来控制对hash表的不同段进行的修改,每个段其实就是一个小的hashtable,它们有自己的锁。只要多个并发发生在不同的段上,它们就可以并发进行。

ConcurrentHashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。Hashtable底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

与HashMap不同的是,ConcurrentHashMap使用多个子Hash表,也就是段(Segment)

ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。如果使用传统的技术,如HashMap中的实现,如果允许可以在hash链的中间添加或删除元素,读操作不加锁将得到不一致的数据。ConcurrentHashMap实现技术是保证HashEntry几乎是不可变的。

参考文献: http://zhangshixi.iteye.com/blog/673143l

HashSet由哈希表(实际上是一个HashMap实例)支持,不保证set的迭代顺序,并允许使用null元素。

基于HashMap实现,API也是对HashMap的行为进行了封装,可参考HashMap

参考文献: http://zhangshixi.iteye.com/blog/673789l

LinkedHashMap继承于HashMap,底层使用哈希表和双向链表来保存所有元素,并且它是非同步,允许使用null值和null键。

基本操作与父类HashMap相似,通过重写HashMap相关方法,重新定义了数组中保存的元素Entry,来实现自己的链接列表特性。该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而构成了双向链接列表。

参考文献: http://zhangshixi.iteye.com/blog/673319l

对于LinkedHashSet而言,它继承与HashSet、又基于LinkedHashMap来实现的。LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同。