美文网首页LinuxLinux学习之路
APUE读书笔记-16网络通信(1)

APUE读书笔记-16网络通信(1)

作者: QuietHeart | 来源:发表于2020-07-25 13:37 被阅读0次

1、简介

在前面的章节,我们查看了pipes,FIFOs,消息队列,信号量,和共享内存这些unix提供的经典的IPC方式。这些机制允许运行在同一台机器上面的进程之间相互通信。本部分内容将会介绍在不同机器上运行的进程之间的通信(通过一个公共的网络),即网络通信。

本部分内容中我们讨论网络IPC的套接字接口,通过这个接口,进程可以和本地或者别的机器上面的进程进行通信。这也是套接字的一个目的,无论在同一个机器还是不同的机器上面通信都使用同一套接口。尽管可以使用套接字通过不同的网络协议实现通信,这里我们将范围限制在Tcp/Ip协议上面,这也是因特网上事实的标准。

POSIX.1上面定义的套接字API是基于4.4BSD的。尽管随着时间的逝去,接口有了些许的变化,但是当前的套接字接口和之前被引入的早期的原来的1980年的4.2BSD的套接字接口还是非常类似的。

本部分内容只对套接字进行了简单的介绍,更详细的资料请参见其他资料。

译者注

原文参考

参考: APUE2/ch16lev1sec1.html

2、套接字描述符

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

为了创建一个套接字,我们需要调用socket函数。

#include <sys/socket.h>
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 <sys/socket.h>
int shutdown (int sockfd, int how);

返回值:如果成功,返回0;如果出错,返回1。

如果参数how是SHUT_RD,那么就无法从套接字里面读取数据。如果how参数是SHUT_WR,那么我们无法使用套接字来传输数据。我们可以使用SHUT_RDWR来禁止发送和接收数据。

既然我们可以对一个套接字进行close那么为什么还需要shutdown呢?这有许多的原因。首先,close将会只在最后一个引用的进程关闭的时候才会关闭网络末端。这也意味着,如果我们复制了套接字(例如通过dup),那么套接字只有在最后一个引用它的文件描述符号关闭的时候才会被释放。 shutdown函数允许我们不用考虑有几个进程引用文件描述符号,就可以释放套接字 。另外,有时候使用shutdown来关闭一个方向的连接也非常的方便。例如,我们想要关闭一个socket的写入,但是我们还想让我们正在通信的进程可以在我们传输完数据的时候可以进行处理,同时也允许我们使用套接字来接收进程发送给我们的数据。

译者注

原文参考

参考: APUE2/ch16lev1sec2.html

相关文章

  • APUE读书笔记-16网络通信(1)

    1、简介 在前面的章节,我们查看了pipes,FIFOs,消息队列,信号量,和共享内存这些unix提供的经典的IP...

  • APUE读书笔记-16网络通信(2)

    3、寻址 在前面的小节里面,我们学到了如何创建和销毁一个套接字。在我们使用套接字之前,我们需要知道如何定位到我们交...

  • APUE读书笔记-16网络通信(5)

    4、建立连接 如果我们处理一个面向连接的网络服务(SOCK_STREAM或者SOCK_SEQPACKET),那么在...

  • APUE读书笔记-16网络通信(9)

    6、套接字选项 套接字机制提供了两个套接字选项接口来控制套接字的行为。一个接口用来设置选项,另外一个接口用来允许我...

  • APUE读书笔记-16网络通信(4)

    (4)将地址和套接字进行关联 客户的套接字关联的地址并不是重点,我们可以让系统选择一个默认的地址。但是对于一个服务...

  • APUE读书笔记-16网络通信(7)

    面向连接与面向无连接通讯举例 面向连接的客户端的例子 下面的程序,显示了一个客户的命令,这个命令和服务进行通信,从...

  • APUE读书笔记-16网络通信(10)

    7、带外数据 带外数据是一个被一些通信协议支持的可选的特性,它允许比普通数据优先级高的数据被传送。带外数据会被优先...

  • APUE读书笔记-16网络通信(6)

    5、数据传输 由于socket末端使用文件描述符号来替代,当被连接起来的时候,我们就可以使用read和write来...

  • APUE读书笔记-16网络通信(3)

    (3)地址查询 理想情况,一个应用程序不用知道套接字地址的内部结构。如果一个应用程序简单地把套接字地址作为sock...

  • APUE读书笔记-16网络通信(8)

    无连接客户的例子 下面的程序就是使用数据包接口的uptime客户端程序。 基于数据包的客户端的main函数和面向连...

网友评论

    本文标题:APUE读书笔记-16网络通信(1)

    本文链接:https://www.haomeiwen.com/subject/gxijlktx.html