写点什么

网络编程方法

用户头像
Ya
关注
发布于: 2020 年 04 月 29 日
网络编程方法

网络编程概念


所谓网络编程,是指通过编程的手段,将一台主机上的信息通过网络发送到另一台主机上。而我们把这些能使得网络中的两台主机通信的程序称之为网络程序/网络应用/网络服务,如 DNS,FTP,Telnet,HTTP 等等。


网络编程通常采用的是经典的客户端-服务器模型,如面向连接的客户端服务器通信过程(以四层的 TCP/IP 模型说明):


1)同一个局域网:LAN


图1 局域网客户端-服务器通信流程图


2)不同局域网:WAN


图2 广域网客户端-服务器通信流程图


从上图中可以看到,客户端与服务器想要通信则必须调用操作系统提供的方法,完成协议栈的转换与数据交换。而网络环境错综复杂、网络介质种类不一,这时亟需要一种两个端点在网络中通信(交换数据)的抽象,使得上层的应用程序可以屏蔽掉下层这些网络细节,从而专注于实现具体的网络应用。


伯克利套接字的诞生


1983 年,加州大学伯克利分校发布 4.2BSD Unix 操作系统,包含其中的有一套网络应用程序编程接口库,简称伯克利套接字(全称 Internet Berkeley Sockets),由于其抽象的优雅性以及使用的便捷性,如今伯克利套接字已经是事实上的网络套接字标准。所有的现代操作系统 Socket 实现均源于伯克利套接字,包括微软 Windows 的 Winsock。


网络套接字设计


可以说,自上个世纪八十年代伯克利套接字诞生之日起,套接字基本上就是今天的样子(虽然中间有过几次小修补),足见其本身设计的优秀之处。所有的网络编程无一例外地使用套接字实现,套接字编程已然等同于网络编程。


1)理解 Socket 概念


Socket 是操作系统内核提供的一套 TCP/IP 协议栈的抽象,用于网络中两个端点(endpoint)的通信。从字面意思上理解,Socket 直译是插座的意思,可类比为物理上的插孔连接器,两个端点之间要想通过可视化的电缆通道(即网络)通信,则只需将端点上的插头(即应用程序)插入到插孔连接器(即插座)中即可(如封面图所示),而这其中插入的过程就是网络编程。


上面是站在应用层的角度看 Socket,如果站在操作系统内核的角度,Socket 到底是什么呢?


在 Unix 操作系统『一切皆文件』的设计哲学指导下,Socket 也被抽象为一种特殊类型的文件,可以通过统一的文件方法调用等来操作它,即 Socket 本质是一种字节流(a stream of bytes)。


:在《UNIX 网络编程卷 1:套接字网络 API》一书中,译者认为 Socket 一次翻译为『套接口』更为准确,而创建套接字返回的文件描述符则称为『套接字』。因为 Socket 实际上就是一套内核提供的 API 接口,无奈『套接字』的译法已被广泛接受。


不同类型的 Socket 有不同的属性,下面从创建 Socket 方法调用着手,看下操作系统具体支持哪些 socket 类型,以 Unix 操作系统的 POSIX.1 规范为例:

# include <sys/socket.h>// 创建Socket:若成功则返回文件(套接字)描述符,否则返回-1int socket(int domain, int type, int protocol);
复制代码

参数含义

  • domain:套接字通信域,决定 Socket 地址格式与寻址方式

  • AF_UNIX:UNIX 域,用于同一主机上的程序之间的通信。

  • AF_INET:IPv4 因特网域,用于互联网上不同主机上程序之间的通信。

  • AF_INET6:IPv4 因特网域。

  • AF_UNSPEC:未指定

  • type:所在通信域采用的套接字类型,决定 Socket 通信格式

  • SOCK_STREAM:有序、可靠、双向的面向连接的字节流,默认协议 TCP。

  • SOCK_DGRAM:长度固定、无链接的不可靠报文传递,默认协议为 UDP。

  • SOCK_RAW:IP 协议层的数据报接口

  • SOCK_SEQPACKET:长度固定、有序、可靠的面向连接报文传递,与 SOCK_STREAM 类似,但从该类型套接字是基于报文而不是基于字节流。默认协议 SCTP(该协议起步较晚,未广泛集成于 TCP/IP 协议栈中,目前主要用于电信领域)。

  • protocol:套接字类型支持的协议,决定 Socket 基于的通信协议


2)Socket 所在协议层位置


从根据上面图 1 与图 2 的客户端服务器模型可以看到套接字接口位于传输层与应用层之间,这样设计的好处是:


应用层与传输层之间的地方是网络应用与通信细节的分界点:应用层主要处理具体网络应用服务的所有细节,对通信细节了解甚少;传输层及以下对网络应用了解不多,但是要处理所有通信细节,如发送数据、等待确认,给无需到达的数据排序,计算并验证校验和等等。


所有现代操作系统均区分用户态与内核态:应用层构建的是用户态进程;传输层及以下通常作为操作系统内核实现的一部分。


凡事皆有例外。


在广域网(或互联网)中的路由器或三层交换机等网络设备(如上图 2)通常不要求实现传输层的协议,因为它们的所有操作均在 IP 层即可完成。然而,某些场景下网络设备也需要使用到 socket 相关信息,如 NAT,Qos 支持等,这就需要内核提供套接字接口直接访问下层的 IP 层(即此时需要自己构建协议首部)。为此,套接字标准的套接字类型定义了 SOCK_RAW 类型,专用于这些网络设备中,配合路由协议如 IGRP 和 OSPF 以及 ICMP。所以,套接字所在的准确网络层级位置如下图 3 所示


注:Linux 系统还增加了 SOCK_PACKET 类型,直接从网络驱动层获取报文,tcpdump 工具就是基于此实现的。


套接字编程方法


Socket 通常用于客户端与服务器之间通信(即交换信息)。典型的系统设计是服务器在一台机器上,客户端在另外一台机器上,然后客户端连接到服务器,交换信息,最后断开连接。所有现代操作系统均提供了一套 Socket API 用于编写网络应用,下面是基于 TCP 协议的 Socket API 流程

关于具体 API 细节,请自行 RTFM。


总结


本文介绍了网络编程中的概念与原理,以及从设计者的角度分析 Socket 实现的『知其所以然』部分。本文力求做到简单易懂,这并不意味着网络编程很简单(可不只是调用几个系统 API...)。实现一个网络应用程序(如 TCP/HTTP/WebSocket 服务器)不难,难的是基于当前业务场景针对具体操作系统与网络协议不断调优,提供一个高性能/高并发且稳定可靠的网络服务。


发布于: 2020 年 04 月 29 日阅读数: 73
用户头像

Ya

关注

to be a maker 2017.11.23 加入

腾讯高级工程师

评论

发布
暂无评论
网络编程方法