Socket 的功能
6.2.2
Socket 的英文原意就是“孔”或“插座”,现在,作为 BSD UNIX 的进程通讯机制,
取其后一种意义。日常生活中常见的插座,有的是信号插座,有的是电源插座,有的可以
接受信号(或能量) ,有的可以发送信号(或能量)。假如电话线与电话机之间安放一个插
座(相当于二者之间的接口,这一部分装置物理上是存在的)则 Socket 非常相似于电话插
座。
将电话系统与面向连接的 Socket 机制相比,有着惊人相似的地方。以一个国家级的电
话网为例。电话的通话双方相当于相互通信的两个进程;通话双方所在的地区(享有一个
全局唯一的区号)相当于一个网络,区号是它的网络地址;区内的一个单位的交换机相当
于一台主机,主机分配给每个用户的局内号码相当于 Socket 号(下面将谈到) 。
图 6-1 socket 接口示意图
任何用户在通话之前,首先要占有一部电话机,相当于申请一个 Socket 号;同时要知
道对方的电话号码,相当于对方有一个 Socket。然后向对方拨号呼叫,相当于发出连接请
求(假如对方不在同一区内,还要拨对方区号,相当于给出网络地址) 。对方假如在场并
空闲(相当于通信的另一主机开机且可以接受连接请求) ,拿起电话话筒,双方就可以正
式通话,相当于连接成功。双方通话的过程,是向电话机发出信号和从电话机接受信号的
过程,相当于向 Socket 发送数据和从 Socket 接受数据。通话结束后,一方挂起电话机,
相当于关闭 Socket,撤消连接。
在电话系统中,一般用户只能感受到本地电话机和对方电话号码的存在,建立通话的
过程、话音传输的过程以及整个电话系统的技术细节对它都是透明的,这也与 Socket 机制
非常相似。Socket 利用网间网通信设施实现进程通信,但它对通信设施的细节毫不关心,
只要通信设施能提供足够的通信能力,它就满足了。
至此,我们对 Socket 进行了直观的描述。抽象出来,Socket 实质上提供了进程通信的
端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互
通信的。正如打电话之前,双方必须各自拥有一台电话机一样。
每一个 Socket 都用一个半相关描述:
{协议,本地地址,本地端口}
一个完整的 Socket 则用一个相关描述
{协议,本地地址,本地端口,远程地址,远程端口}
每一个 Socket 有一个本地的唯一 Socket 号,由操作系统分配。
最重要的是,Socket 是面向客户-服务器模型而设计的,针对客户和服务器程序提供
不同的 Socket 系统调用。客户随机申请一个 Socket 号(相当于一个想打电话的人可以在
任何一台入网的电话上拨叫呼叫) ;服务器拥有全局公认的 Socket,任何客户都可以向它
发出连接请求和信息请求(相当于一个被呼叫的电话拥有一个呼叫方知道的电话号码) 。
Socket 利用客户— 服务器模式巧妙的解决了进程之间建立通信连接的问题。服务器
Socket 为全局所公认非常重要。两个完全随机的用户进程之间,因为没有任何一方的 Socket
是固定的,就像打电话却不知道别人的电话号码,要通话是不可能的。
套接字的三种类型
6.2.3
套接字有三种类型:流式套接字 (SOCK_STREAM),数据报套接字 (SOCK_DGRAM)
及原始套接字。
1.流式套接字(SOCK_STREAM)
流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺
序的数据: “1”“2”
、 。那么数据到达远程时候的顺序也是“1”“2” 、 。
流式套接字可以做什么呢?你听说过 Telnet 应用程序吗?听过?哦,最常用的 BBS 服
务,以及系统的远程登陆都是通过 Telnet 协议连接的。Telnet 就是一个流式连接。你是否
希望你在 Telnet 应用程序上输入的字符(或汉字)在到达远程应用程序的时候是以你输入
的顺序到达的?答案应该是肯定的吧。还有 WWW 浏览器,它使用的 HTTP 协议也是通过
流式套接字来获取网页的。事实上,如果你 Telnet 到一个 Web Site 的 80 端口上,然后输
入 “GET 网页路径名”然后按两下回车(或者是两下 Ctrl+回车)然后你就得到了“网页
路径名”所代表的网页!
流式套接字是怎样保证这种应用层次上的数据传输质量呢?它使用了 TCP ( The
Transmission Control Protocol)协议(可以参考 RFC-793 来得到 TCP 的细节) 。TCP 保证
了你的数据传输是正确的,并且是顺序的。TCP 是经常出现的 TCP/IP 中的前半部分。IP
代表 Internet Protocol(因特网协议,参考 RFC-791)IP 只处理网络路由。
图 6-2 面向连接的 socket 的工作流程
2.数据报套接字(SOCK_DGRAM)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序
的,并且不保证可靠,无差错。原始套接字允许对低层协议如 IP 或 ICMP 直接访问,主要
用于新的网络协议实现的测试等。
数据报套接字(Datagram Sockets)怎样呢?为什么它叫做“无连接”?应该怎样处理
它们呢?为什么它们是不可靠的?好的,这里有一些事实:
l 如果你发送了一个数据报,它可能不会到达。
l 它可能会以不同的顺序到达。
l 如果它到达了,它包含的数据中可能存在错误。
数据报套接字也使用 IP,但是它不使用 TCP,它使用使用者数据报协议 UDP(User
Datagram Protocol 可以参考 RFC 768)
为什么说它们是“无连接”的呢?因为它(UDP)不像流式套接字那样维护一个打开
的连接,你只需要把数据打成一个包,把远程的 IP 贴上去,然后把这个包发送出去。这个
过程是不需要建立连接的。UDP 的应用例子有: tftp, bootp 等。
那么,数据包既然会丢失,怎样能保证程序能够正常工作呢?事实上,每个使用 UDP
的程序都要有自己的对数据进行确认的协议。比如, TFTP 协议定义了对于每一个发送出
去的数据包,远程在接受到之后都要回送一个数据包告诉本地程序: “我已经拿到了!(一
”
个 “ACK” 包) 。如果数据包发的送者在 5 秒内没有的得到回应,它就会重新发送这个
数据包直到数据包接受者回送了 “ACK” 信号。这些知识对编写一个使用 UDP 协议的
程序员来说是非常必要的。
无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务
程序之间的相互作用。若使用无连接的套接字编程,程序的流程可以用图 6-3 表示。
图 6-3 无连接的 socket 工作流程
面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而
且往往是并发服务器。使用面向连接的套接字编程,可以通过图 6-2 来表示。
套接字工作过程如下:服务器首先启动,通过调用 socket()建立一个套接字,然后调用
bind()将该套接字和本地网络地址联系在一起,再调用 listen()使套接字做好侦听的准备,
并规定它的请求队列的长度,之后就调用 accept()来接收连接。客户在建立套接字后就可调
用 connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就可以通过调用 read()
和 write()来发送和接收数据。最后,待数据传送结束后,双方调用 close()关闭套接字。
3.原始套接字
原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是
没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。
6.2.2
Socket 的英文原意就是“孔”或“插座”,现在,作为 BSD UNIX 的进程通讯机制,
取其后一种意义。日常生活中常见的插座,有的是信号插座,有的是电源插座,有的可以
接受信号(或能量) ,有的可以发送信号(或能量)。假如电话线与电话机之间安放一个插
座(相当于二者之间的接口,这一部分装置物理上是存在的)则 Socket 非常相似于电话插
座。
将电话系统与面向连接的 Socket 机制相比,有着惊人相似的地方。以一个国家级的电
话网为例。电话的通话双方相当于相互通信的两个进程;通话双方所在的地区(享有一个
全局唯一的区号)相当于一个网络,区号是它的网络地址;区内的一个单位的交换机相当
于一台主机,主机分配给每个用户的局内号码相当于 Socket 号(下面将谈到) 。
图 6-1 socket 接口示意图
任何用户在通话之前,首先要占有一部电话机,相当于申请一个 Socket 号;同时要知
道对方的电话号码,相当于对方有一个 Socket。然后向对方拨号呼叫,相当于发出连接请
求(假如对方不在同一区内,还要拨对方区号,相当于给出网络地址) 。对方假如在场并
空闲(相当于通信的另一主机开机且可以接受连接请求) ,拿起电话话筒,双方就可以正
式通话,相当于连接成功。双方通话的过程,是向电话机发出信号和从电话机接受信号的
过程,相当于向 Socket 发送数据和从 Socket 接受数据。通话结束后,一方挂起电话机,
相当于关闭 Socket,撤消连接。
在电话系统中,一般用户只能感受到本地电话机和对方电话号码的存在,建立通话的
过程、话音传输的过程以及整个电话系统的技术细节对它都是透明的,这也与 Socket 机制
非常相似。Socket 利用网间网通信设施实现进程通信,但它对通信设施的细节毫不关心,
只要通信设施能提供足够的通信能力,它就满足了。
至此,我们对 Socket 进行了直观的描述。抽象出来,Socket 实质上提供了进程通信的
端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互
通信的。正如打电话之前,双方必须各自拥有一台电话机一样。
每一个 Socket 都用一个半相关描述:
{协议,本地地址,本地端口}
一个完整的 Socket 则用一个相关描述
{协议,本地地址,本地端口,远程地址,远程端口}
每一个 Socket 有一个本地的唯一 Socket 号,由操作系统分配。
最重要的是,Socket 是面向客户-服务器模型而设计的,针对客户和服务器程序提供
不同的 Socket 系统调用。客户随机申请一个 Socket 号(相当于一个想打电话的人可以在
任何一台入网的电话上拨叫呼叫) ;服务器拥有全局公认的 Socket,任何客户都可以向它
发出连接请求和信息请求(相当于一个被呼叫的电话拥有一个呼叫方知道的电话号码) 。
Socket 利用客户— 服务器模式巧妙的解决了进程之间建立通信连接的问题。服务器
Socket 为全局所公认非常重要。两个完全随机的用户进程之间,因为没有任何一方的 Socket
是固定的,就像打电话却不知道别人的电话号码,要通话是不可能的。
套接字的三种类型
6.2.3
套接字有三种类型:流式套接字 (SOCK_STREAM),数据报套接字 (SOCK_DGRAM)
及原始套接字。
1.流式套接字(SOCK_STREAM)
流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺
序的数据: “1”“2”
、 。那么数据到达远程时候的顺序也是“1”“2” 、 。
流式套接字可以做什么呢?你听说过 Telnet 应用程序吗?听过?哦,最常用的 BBS 服
务,以及系统的远程登陆都是通过 Telnet 协议连接的。Telnet 就是一个流式连接。你是否
希望你在 Telnet 应用程序上输入的字符(或汉字)在到达远程应用程序的时候是以你输入
的顺序到达的?答案应该是肯定的吧。还有 WWW 浏览器,它使用的 HTTP 协议也是通过
流式套接字来获取网页的。事实上,如果你 Telnet 到一个 Web Site 的 80 端口上,然后输
入 “GET 网页路径名”然后按两下回车(或者是两下 Ctrl+回车)然后你就得到了“网页
路径名”所代表的网页!
流式套接字是怎样保证这种应用层次上的数据传输质量呢?它使用了 TCP ( The
Transmission Control Protocol)协议(可以参考 RFC-793 来得到 TCP 的细节) 。TCP 保证
了你的数据传输是正确的,并且是顺序的。TCP 是经常出现的 TCP/IP 中的前半部分。IP
代表 Internet Protocol(因特网协议,参考 RFC-791)IP 只处理网络路由。
图 6-2 面向连接的 socket 的工作流程
2.数据报套接字(SOCK_DGRAM)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序
的,并且不保证可靠,无差错。原始套接字允许对低层协议如 IP 或 ICMP 直接访问,主要
用于新的网络协议实现的测试等。
数据报套接字(Datagram Sockets)怎样呢?为什么它叫做“无连接”?应该怎样处理
它们呢?为什么它们是不可靠的?好的,这里有一些事实:
l 如果你发送了一个数据报,它可能不会到达。
l 它可能会以不同的顺序到达。
l 如果它到达了,它包含的数据中可能存在错误。
数据报套接字也使用 IP,但是它不使用 TCP,它使用使用者数据报协议 UDP(User
Datagram Protocol 可以参考 RFC 768)
为什么说它们是“无连接”的呢?因为它(UDP)不像流式套接字那样维护一个打开
的连接,你只需要把数据打成一个包,把远程的 IP 贴上去,然后把这个包发送出去。这个
过程是不需要建立连接的。UDP 的应用例子有: tftp, bootp 等。
那么,数据包既然会丢失,怎样能保证程序能够正常工作呢?事实上,每个使用 UDP
的程序都要有自己的对数据进行确认的协议。比如, TFTP 协议定义了对于每一个发送出
去的数据包,远程在接受到之后都要回送一个数据包告诉本地程序: “我已经拿到了!(一
”
个 “ACK” 包) 。如果数据包发的送者在 5 秒内没有的得到回应,它就会重新发送这个
数据包直到数据包接受者回送了 “ACK” 信号。这些知识对编写一个使用 UDP 协议的
程序员来说是非常必要的。
无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务
程序之间的相互作用。若使用无连接的套接字编程,程序的流程可以用图 6-3 表示。
图 6-3 无连接的 socket 工作流程
面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而
且往往是并发服务器。使用面向连接的套接字编程,可以通过图 6-2 来表示。
套接字工作过程如下:服务器首先启动,通过调用 socket()建立一个套接字,然后调用
bind()将该套接字和本地网络地址联系在一起,再调用 listen()使套接字做好侦听的准备,
并规定它的请求队列的长度,之后就调用 accept()来接收连接。客户在建立套接字后就可调
用 connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就可以通过调用 read()
和 write()来发送和接收数据。最后,待数据传送结束后,双方调用 close()关闭套接字。
3.原始套接字
原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是
没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。