有没有SOCKET,网卡都会接收数据。网卡工作在数据链路层,它只认识链路上邻近的点。它甚至不认识它隔壁的隔壁,它又怎么可能知道传输层的信息呢(起点与终点,是传输层的信息)?。。。传输层的信息,只能由传输层来处理!
IP层存在同样的问题。因为它也“活(动)”在网络层。它也不处理,同样地它也不能处理本来位于第四层即传输层的与传输相关的信息。。当然,如果一个网络节点硬要处理它,当然也是可以的。因为高层的信息是被低层的信息所包裹着的。只是恐怕一般的机构没有这样的实力来做这个事情。因为那么多人的信息,凭一己之力,怎么可能或者什么时候才能读得完?!
由此可见,SOCKET只是整个网络系统的附属品。它并没有任何主“动”的能力。主“动”的能力全部把握在第三层以下。第四层及其以上各层,都不具有“动”的能力。。。。一个数据包,如果被传到了第四层,其实也就失去了其的动力,停止了其在网络上的旅行。因为它已经到了。
这意味着,如果从网络上随处给某个“SOCKET”发一个数据包,不管这个SOCKET是否真实存在,即:不管在内存中是否已经建立其对应的SOCKET对象,这个包都会被如期送达(如果至少这个“半相关”存在,并且假设网络通畅的话)。也就是说,以任一SOCKET地址为目标的数据包的到达与否,与在主机中是否建立相关的SOCKET对象是没有关系的。
当然没有关系!
一个SOCKET对象只是活在本地内存中的对象,而真正的数据包却是来自于网络层I/O操作。网络I/O工作在传输层以下,这就决定了网络I/O工作在SOCKET对象所在层即传输层以前,这就决定了与SOCKET工作有关的任何系统级或用户级操作,都是发生在包到达以后(在接收的时候)。
真正的发送工作更与SOCKET对象基本上没有任何关系。因为操作系统只要随便往一个IP包中填入一个地址与端口都可以把包给发出去(也许不填也可以。。。因为源地址显然地并不是路由所需要的必要信息)。
。。。
意思是,SOCKET并不是动者。通信能力的提供者是操作系统。操作系统提供所有的协议服务。这种服务,通过SOCKET暴露给应用程序的开发者。首先,在机器级别是不存在对象这个概念的。机器只知道两样事情:数据与指令。在运行时,SOCKET的代码是不存在的。存在的是SOCKET的代码的编译后指令。方法或函数在二进制世界其实只是指令集的界符。函数的概念其实只是为了区分运行时的指令集。机器需要这样的信息对运行时指令集进行划分。否则机器就只能执行顺序程序了(在原语言不提供其它的代码边界或标识的情况下)。源码的价值也在于其的二进制代表。否则其就不可能具有任何意义。这是可以使用SOCKET API来讨论网络通信的原因。因为它拥有真正的二进制代表。当我使用API这个词的时候,它的背后其实是它所代表的机器级指令。。。但是无论如何,SOCKET的API并不是通信的执行者。通信的执行者是操作系统的协议层。SOCKET API只是应用程序与操作系统的协议层之间的一座桥梁。它可以被看作应用程序与操作系统的通信服务之间的协议。即操作系统的通信服务协议。应用程序通过这种协议调用操作系统的通信服务。这显然意味着SOCKET并不是真正的通信者。真正的通信者是OS。另一个证据是, SOCKET并不执行任何TCP协议操作。所有的协议操作都是操作系统完成的。而应用程序则使用SOCKET调用这些服务。另一种说法它是一种机制,就是这个意思。因为机制意味着手段,渠道,中间者。是一样的意思。操作系统通过这种机制向外提供通信服务。
动者是操作系统(的协议层)。
因此, 说使用SOCKET进行通信是错误的。应该说使用SOCKET调用通信。因为它并不完成真正的通信。它的确通信,但是这种通信是为了与OS的真正通信服务进行通信以告诉OS为之提供服务。另一个方面,它只是个API,所做的全部只是在内存中的一些操作,这些操作如何能够完成任何真正的通信工作?真正的通信工作要求的是端口管理,分配,侦听,以及网络层即IP地址的管理,分配,安全等服务,还有按协议组装数据,路由,寻址及响应服务,和与网卡进行真正的I/O通信以将数据放至网络上传播。。。。。。所有这些工作,SOCKET一点都没有做。
因此,SOCKET,不管是“半相关”还是“全相关”,都只是内存里面的概念。这些概念存在的目的是为了构建整个调用机制。它们是为调用而存在的。它们只活在API里面。调用的目标则是系统的通信服务。 也可以认为这些是对OS服务的封装。但是如JDBC并不进行真正的数据库操作一样,必须清醒地意识到SOCKET只是个API,它也不进行任何真正的通信操作。如果它能进行,那么它就不会存在于JAVA语言中了。因为JAVA语言甚至不能提供对内存的直接存取,更何况对I/O设备(网卡)的直接存取呢?
SOCKET意思是,这么多的程序都要通信。你要插一脚,那好,就给你一个SOCKET。SOCKET在这里的意思是,插孔。槽。当用它来接收信息的时候,它用来区分具体的收信程序;用来发送信息的时候,它就只是个句柄。
如果绑定了地址,那么系统应该会尽可能在进行真正的通信工作时使用这个地址。比如,如果为服务端SOCKET绑定了地址,那么系统将尝试在这个地址上而不是别的地址上进行侦听(对操作系统来说,它将形成一个资源占用------也就是说,一旦绑定成功,其它的程序将不能绑定在相同的地址(网络地址---人为的,虚有的,自称的地址)上)。
附:
维基上面的Berkeley sockets.bind()方法的描述:
bind()
bind()
assigns a socket to an address. When a socket is created using socket()
, it is only given a protocol family, but not assigned an address. This association with an address must be performed with the bind() system call before the socket can accept connections to other hosts. bind()
takes three arguments:
sockfd
, a descriptor representing the socket to perform the bind on.my_addr
, a pointer to asockaddr
structure representing the address to bind to.addrlen
, asocklen_t
field specifying the size of thesockaddr
structure.
Bind() returns 0 on success and -1 if an error occurs.
-
Prototype
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
注意红色的文字。它解释说“绑定”是接受其它主机连接的前提条件。因为如果没有绑定,就没有注册。不注册,怎么侦听。OS不是神。OS通过这个函数得到在系统内部路由的信息------进程路由。