Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5634904
  • 博文数量: 922
  • 博客积分: 19333
  • 博客等级: 上将
  • 技术积分: 11226
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-27 14:33
文章分类

全部博文(922)

文章存档

2023年(1)

2020年(2)

2019年(1)

2017年(1)

2016年(3)

2015年(10)

2014年(17)

2013年(49)

2012年(291)

2011年(266)

2010年(95)

2009年(54)

2008年(132)

分类: LINUX

2012-02-16 21:48:09

++++++APUE读书笔记-16网络通信-02套接字描述符++++++

 

2、套接字描述符
================================================
 套接字是一个通信端点。和在unix系统上面使用文件描述符号访问文件类似,应用程序可以使用套接字描述符号访问套接字。套接字描述符号在unix系统中使用文件描述符号实现。实际上,有许多可以用来处理文件描述符号的函数,例如read和write都可以用在套接字描述符号上面。

 为了创建一个套接字,我们需要调用socket函数。
 #include
 int socket(int domain, int type, int protocol);
 返回:如果成功返回文件(套接字)描述符号,如果错误返回1。
 domain参数决定通信的特性,包含地址格式(后面会详细说明)。下表列出来了POSIX.1所指定的domain。常量以AF_(address family)开始因为每个domain有它自己用来表示地址的格式。

  套接字通信domain
+-----------------------------------+
|  Domain   |      Description      |
|-----------+-----------------------|
| AF_INET   | IPv4 Internet domain  |
|-----------+-----------------------|
| AF_INET6  | IPv6 Internet domain  |
|-----------+-----------------------|
| AF_UNIX   | UNIX domain           |
|-----------+-----------------------|
| AF_UNSPEC | unspecified           |
+-----------------------------------+

 我们在后面讨论unix domain(unix 域)。大多数系统也定义了AF_LOCAL域,它是AF_UNIX的别名。AF_UNSPEC域是一个占位符号,表示“任何”域。历史上,有写平台支持额外的网络协议,例如AF_IPX网络协议族,但是相应于这些协议的domain常量并没有在POSIX.1标准中定义。
 type参数定义了套接字的类型,进而定义了通信的特性。下表列出了POSIX.1中指定的套接字类型。但是有些实现可以支持额外的类型。

      套接字类型
+---------------------------------------------------------------------------------------+
|      Type      |                             Description                              |
|----------------+----------------------------------------------------------------------|
| SOCK_DGRAM     | fixed-length, connectionless, unreliable messages                    |
|----------------+----------------------------------------------------------------------|
| SOCK_RAW       | datagram interface to IP (optional in POSIX.1)                       |
|----------------+----------------------------------------------------------------------|
| SOCK_SEQPACKET | fixed-length, sequenced, reliable, connection-oriented messages      |
|----------------+----------------------------------------------------------------------|
| SOCK_STREAM    | sequenced, reliable, bidirectional, connection-oriented byte streams |
+---------------------------------------------------------------------------------------+

 protocol参数一般是0,用来为给定的domain和type选定默认的协议。当多个协议都支持同样的domain和type的时候,我们可以使用protocol参数选择一个特定的协议。在AF_INET通信domain中默认的SOCK_STREAM套接字协议是TCP(传输控制协议),在AF_INET通信domain中默认的SOCK_DGRAM套接字协议是UDP(用户数据报协议)。
 在数据报(SOCK_DGRAM)接口中,通信双方不需要存在一个逻辑的链接。你所需要做的就只是发送一个指定好了另外一端使用的地址的消息。
 一个数据报因此提供了一个无连接服务。一个比特流(SOCK_STREAM)在另外一个方面要求,交换数据之前,你需要在你的套接字和另一方的套接字之间设置一个逻辑的链接。
 数据报是一个自包含的消息。发送数据报和给别人发送邮件类似。你可以发送许多信件,但是你不能保证接收的次序,并且同时有些也会可能丢失。每个信件包含接收者的地址,这样每个信都和其他信相互独立。每个信甚至可以发送到不同的接收者。
 相反,如果使用面向连接的协议,通信双方就像打电话。首先你需要建立一个连接用来打电话,但是建立连接之后,你就可以直接和对方通话了。连接是一个点对点的通信信道,你可以在其上说话,但是你的话语并不包含任何地址信息,就好象有一个点对点的虚拟连接联系这通话双方,连接本身就代表了特定的收发地址。
 经过SOCK_STREAM套接字,应用程序不用知道消息边界,因为套接字提供了一个字节流服务。也就是说当我们从一个socket中读取数据的时候,读取返回的数据数目可能和发送数据给我们的进程写入的字节数目不一样。我们将会获得发送给我们的任何东西,但是它们可能需要多个函数调用。
 SOCK_SEQPACKET套接字类似SOCK_STREAM套接字,不同的是我们获得的是一个基于消息的服务而不是基于字节流的服务。也就是说,从SOCK_SEQPACKET接收到的数据量和写入的数据量相同。流控制传输协议(SCTP)提供了在因特网的domain的顺序包协议。
 SOCK_RAW套接字提供一个直接面向底层网络层的数据报接口(在因特网的domain中叫做IP)。因为没有考虑传输协议(例如TCP和UDP),应用程序在使用这个接口的时候,需要建立他们自己的协议头。为了创建一个raw socket(原始套接字),需要具有超级用户权限,这样可以防止非法应用程序创建一个破坏安全机制的包。
 调用socket函数和调用open函数类似。两者都获得一个文件描述符号,可以用来进行I/O。当你操作完了文件描述符号的时候,你可以调用close断开和文件或者套接字的连接,释放文件描述符号以便以后可以再次利用。
 尽管套接字描述符号实际上是一个文件描述符号,但是却不能使用所有以操作文件描述符号为参数的函数来操作套接字描述符号。参考资料中就列出了这些函数。由于篇幅,这里就不详细列出了,具体可以参见参考资料。例如,lseek就无法作用于套接字,因为套接字不接受文件偏移的概念。

 套接字的通信是双工的,我们可以使用shutdown函数来关闭对套接字的I/O。
 #include
 int shutdown (int sockfd, int how);
 返回值:如果成功,返回0;如果出错,返回1。
 如果参数how是SHUT_RD,那么就无法从套接字里面读取数据。如果how参数是SHUT_WR,那么我们无法使用套接字来传输数据。我们可以使用SHUT_RDWR来禁止发送和接收数据。
 既然我们可以对一个套接字进行close那么为什么还需要shutdown呢?这有许多的原因。首先,close将会只在最后一个引用的进程关闭的时候才会关闭网络末端。这也意味着,如果我们复制了套接字(例如通过dup),那么套接字只有在最后一个引用它的文件描述符号关闭的时候才会被释放。shutdown函数允许我们不用考虑有几个进程引用文件描述符号,就可以释放套接字。另外,有时候使用shutdown来关闭一个方向的连接也非常的方便。例如,我们想要关闭一个socket的写入,但是我们还想让我们正在通信的进程可以在我们传输完数据的时候可以进行处理,同时也允许我们使用套接字来接收进程发送给我们的数据。

参考:

 

 

阅读(1146) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~