Java Socket 多线程编程、通信模型及socket协议详解

1.         什么是TCP/IP、UDP?
2.         Socket在哪里呢?
3.         Socket是什么呢?
4.         你会使用它们吗?
5.         深入补充:socket通信协议:


        1,什么是TCP/IPUDP

         TCP/IPTransmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
         UDPUser Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
         这里有一张图,表明了这些协议的关系。

                                                                               

                                                                        图1

       TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IPUDP的关系了吧。


        2,Socket在哪里呢?
      
在图1中,我们没有看到Socket的影子,那么它到底在哪里呢?还是用图来说话,一目了然。
2

       原来Socket在这里。


        3,Socket是什么呢?
      Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。


        4,你会使用它们吗?
      
前人已经给我们做了好多的事了,网络间的通信也就简单了许多,但毕竟还是有挺多工作要做的。以前听到Socket编程,觉得它是比较高深的编程知识,但是只要弄清Socket编程的工作原理,神秘的面纱也就揭开了。
       一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。   生活中的场景就解释了这工作原理,也许TCP/IP协议族就是诞生于生活中,这也不一定。

      

3

       先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。


   重要的Socket API:

   java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。

   . Accept方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。

   . getInputStream方法获得网络连接输入,同时返回一个IutputStream对象实例,。

   . getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。

   注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

      

        5,深入补充:socket通信协议:

        你或许会有这样的疑问:如果一个socket创建后并与80端口绑定后,是否就意味着该socket占用了80端口呢?如果是这样的,那么当其accept一个请求后,生成的新的socket到底使用的是什么端口呢(我一直以为系统会默认给其分配一个空闲的端口号)?如果是一个空闲的端口,那一定不是80端口了,于是以后的TCP数据包的目标端口就不是80了--防火墙一定会阻止其通过的!实际上,我们可以看到,防火墙并没有阻止这样的连接,而且这是最常见的连接请求和处理方式。我的不解就是,为什么防火墙没有阻止这样的连接?它是如何判定那条连接是因为connet80端口而生成的?是不是TCP数据包里有什么特别的标志?或者防火墙记住了什么东西?

        我们知道TCP和UDP,前者可以保证数据的正确和可靠性,后者则允许数据丢失。TCP/IP的协议栈的原理:在TCP和UDP同属于传输层,共同架设在IP层(网络层)之上。而IP层主要负责的是在节点之间(End to End)的数据包传送,这里的节点是一台网络设备,比如计算机。因为IP层只负责把数据送到节点,而不能区分上面的不同应用,所以TCP和UDP协议在其基础上加入了端口的信息,端口于是标识的是一个节点上的一个应用。除了增加端口信息,UPD协议基本就没有对IP层的数据进行任何的处理了。而TCP协议还加入了更加复杂的传输控制,比如滑动的数据发送窗口(Slice Window),以及接收确认和重发机制,以达到数据的可靠传送。不管应用层看到的是怎样一个稳定的TCP数据流,下面传送的都是一个个的IP数据包,需要由TCP协议来进行数据重组。
所以,我有理由怀疑,防火墙并没有足够的信息判断TCP数据包的更多信息,除了IP地址和端口号。而且,我们也看到,所谓的端口,是为了区分不同的应用的,以在不同的IP包来到的时候能够正确转发。
         TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如Win32编程接口一样,TCP/IP也必须对外提供编程接口,这就是Socket编程接口--原来是这么回事啊!
         在Socket编程接口里,设计者提出了一个很重要的概念,那就是socket。这个socket跟文件句柄很相似,实际上在BSD系统里就是跟文件句柄一样存放在一样的进程句柄表里。这个socket其实是一个序号,表示其在句柄表中的位置。这一点,我们已经见过很多了,比如文件句柄,窗口句柄等等。这些句柄,其实是代表了系统中的某些特定的对象,用于在各种函数中作为参数传入,以对特定的对象进行操作--这其实是C语言的问题,在C++语言里,这个句柄其实就是this指针,实际就是对象指针啦。
现在我们知道,socket跟TCP/IP并没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以,socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write等等。
         现在我们明白,如果一个程序创建了一个socket,并让其监听80端口,其实是向TCP/IP协议栈声明了其对80端口的占有。以后,所有目标是80端口的TCP数据包都会转发给该程序(这里的程序,因为使用的是Socket编程接口,所以首先由Socket层来处理)。所谓accept函数,其实抽象的是TCP的连接建立过程。accept函数返回的新socket其实指代的是本次创建的连接,而一个连接是包括两部分信息的,一个是源IP和源端口,另一个是宿IP和宿端口。所以,accept可以产生多个不同的socket,而这些socket里包含的宿IP和宿端口是不变的,变化的只是源IP和源端口。这样的话,这些socket宿端口就可以都是80,而Socket层还是能根据源/宿对来准确地分辨出IP包和socket的归属关系,从而完成对TCP/IP协议的操作封装!而同时,放火墙的对IP包的处理规则也是清晰明了,不存在前面设想的种种复杂的情形。
         明白socket只是对TCP/IP协议栈操作的抽象,而不是简单的映射关系,这很重要!

Per informazioni più dettagliate sulle ottimizzazioni basate su compilatore, vedere il nostro Avviso sull'ottimizzazione.
Contrassegni: