从 0 开始学习 Linux 系列之「26.网络编程基础 」

版权声明:本文为 cdeveloper 原创文章,可以随意转载,但必须在明确位置注明出处!

网络编程基础概念

网络编程中有许多基础概念必须了解,比如 OSI,TCP/IP,字节序列等,这些都是开发网络应用的基础,可以帮助我们更好的理解网络程序的工作原理,来一起学习下一些比较重要的概念。

OSI 开放系统互联模型

OSIOpen System Interconnection)是国际标准化组织(ISO)制定的计算机互联的标准,是设计和描述计算机网络通信的基本框架。OSI 模型把网络通信分为 7 层,如下图所示:

OSI

OSI 模型的设计目的是成为一个所有销售商都能实现的开放网络模型,来克服使用众多私有网络模型所带来的困难和低效性,我们熟知的 TCP/IP 协议也是以 OSI 为基础的。

TCP/IP 协议簇体系结构

TCP/IP 协议是在 OSI 模型之上开发的通信协议,简化为 4 层:

TCP_IP

TCP/IP 协议没有表示层和会话层,其中每层对应到 OSI 的协议主要有下面这些:

  • 应用层:TFTP,HTTP,FTP 等
  • 传输层:TCP,UDP
  • 网络层:IP,IGMP 等
  • 数据层:MTU 等
  • 物理层:ISO 2110,IEEE802 等

我们经常见到如:HTTP,TCP,UDP,IP,来了解下其中比较常用的 TCP 和 UDP 协议。

TCP/IP 协议基础

TCP/IP 包含许多协议,比如 TCP,UDP,IP,HTTP,FTP 等,平常上网都会使用到它们,必须要了解些概念:

  • TCP(Transport Control Protocol):传输控制协议
  • UDP(User Datagram Protocol):用户数据报协议
  • IP(Internetworking Protocol):网间协议
  • HTTP(Hypertext Transfer Protocol):超文本传输协议
  • FTP(File Transfer Protocol):文本传输协议

网络编程中主要使用 TCP 和 UDP 的概念,这里介绍这 2 者,先来看看 TCP 协议。

1. TCP 协议

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,它有如下的特点:

  • 面向连接的传输
  • 端到端的通信
  • 高可靠性,确保传输数据的正确性,不出现丢失或者乱序
  • 全双工方式传输
  • 采用字节流的方式,即以字节为单位传输字节序列
  • 紧急数据传送功能
  • 一对一传输

2. UDP 协议

UDP(User Datagram Protocol)的简称,即是用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,它有如下特点:

  • 面向无连接的传输
  • 不可靠的数据传输服务
  • 时间延迟小
  • 实时性强
  • 支持一对一,一对多,多对多的连接
  • 不含拥塞控制机制,进程能够以任意速率发送数据

TCP 和 UDP 的区别

两者主要有 5 点区别:

  • TCP 协议面向连接,UDP 面向非连接
  • TCP 传输慢,UDP 传输快
  • TCP 保证数据顺序,UDP 不保证
  • TCP 保证数据正确性,UDP 可能丢包
  • TCP 对系统资源要求多,UDP 要求少

TCP/IP 通信过程

两台主机使用 TCP/IP 相关的协议通信的基本过程是:假设应用层使用的是 HTTP 协议,除物理层是实际传输数据外,其他对等层只是虚拟通信,对等层一般需要遵循相同的协议,每一层传输数据只与相邻的上下层有关系。TCP 层及以下是由操作系统内核实现,是处理通信细节,而应用程序是通过 socket 来处理应用程序网络通信的细节。如下图所示:

TCP CON

TCP/IP 数据包

通信过程中传输的是一个个的数据包,因为通信协议包含许多层,所以数据包在每一层都会进行相关的处理。以 TCP 数据包为例,最后的数据包含有多个部分:

TCP DATA

数据包在传输到达目的主机后又会反向解析(从下到上去掉头部信息),最后只剩下用户数据发给指定程序。

Socket 简介

Socket 套接字是由 BSD(加州大学伯克利分校软件研发中心)开发的一套独立于具体协议的网络编程接口,应用程序可以用这个接口进行网络通信。但 Socket 实际上还是属于进程间通信(IPC),因为网络通信实质上是不同机器上的进程之间的通信。Socket 接口主要有下面这些特征:

  • 是一个编程接口
  • 是一个文件描述符(Linux 下一切皆文件)
  • 不局限与 TCP/IP 协议
  • 面向有连接协议(TCP)和无连接协议(UDP)

5 种 Socket 类型

在使用 socket 接口进行编程时,必须明确所使用的 socket 类型,主要有 5 种类型:

  • SOCK_STREAM:面向顺序,可靠,数据完整,基于字节流的 TCP 协议,是使用最多的类型
  • SOCK_DGRAM:面向无连接,固定长度,不可靠的 UDP 协议
  • SOCK_SEQPACKET:双线路,可靠,固定长度,必须把数据包完整的接受才能读取它
  • SOCK_RAW:提供原生的网络访问
  • SOCK_RDM:很少使用的类型,在大部分 OS 上没有实现

IP 地址和端口号

在 Socket 网络编程中经常使用下面的结构体来定义要连接的 IP 和端口:

struct sockaddr_in {
    // 地址家族,常用 AF_INET 代表 TCP/IP 协议簇
    short int sin_family;
    // 端口号,网络字节序
    unsigned short int sin_port;
    // IP 地址,网络字节序
    struct in_addr sin_addr;
}

// IP 地址的结构定义
typedef uint32_t in_addr_t;
struct in_addr {
    in_addr_t s_addr;
};

具体的代码初始化方法会在下一篇的 Web 服务器项目中介绍,这里以概念为主。

网络字节序

不同的机器在网络上以字节流的方式来传输数据,必须要保证数据从一端传输到另一端能够解析成原来的样子,但是不同的机器的字节序是不同的,所以在进行网络传输的时候必须统一传输的字节序。网络字节序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用 big endian(大端)排序方式

这里再介绍下机器的字节序:

  1. Little endian 小端:低位字节存储在低位地址
  2. Big endian 大端:高位字节存储在低位地址

例如,在内存中存储 0x01020304 的 2 种方式,括号中是内存地址 0x1000 - 0x1003:

  1. 小端存储:04(0x1000) 03(0x1001) 02(0x1002) 01(0x1003)
  2. 大端存储:01(0x1000) 02(0x1001) 03(0x1002) 04(0x1003)

端口字节序转换

在使用 socket 进行网络编程时要将 IP 和端口在网络字节序和主机字节序间相互转换,例如下面的端口字节序转换函数:

#include <arpa/inet.h>

// host to net long  主机序 -> 网络序
uint32_t htonl(uint32_t hostlong);

// host to net short 主机序 -> 网络序
uint16_t htons(uint16_t hostshort);

// net to host long  网络序 -> 主机序
uint32_t ntohl(uint32_t netlong);

// net to host short 网络序 -> 主机序
uint16_t ntohs(uint16_t netshort);

例如将端口 1234 转换成网络字节序的代码如下:

struct sockaddr_in myaddr;
// convert to net port
myaddr.sin_port = htons(1234);
// convert to host port
uint16_t port = ntohs(myaddr.sin_port);

IP 字节序转换

IP 字节序转换函数将 IP 字符串和对应的整数值相互转换,名称的命名与端口转换函数类似:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// inet address to network
int inet_aton(const char *cp, struct in_addr *inp);
// inet network to address
char *inet_ntoa(struct in_addr in);
// convert to network ip
in_addr_t inet_addr(const char *cp);

例如转换 IP:192.168.0.1 的代码如下:

struct in_addr my_addr;
// convert to network number
inet_aton("192.168.0.1", &my_addr);

// convert to address string
char *ip_string = inet_ntoa(my_addr);

// convert "127.0.0.1"
struct sockaddr_in client_addr;
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

域名和 IP 地址之间的转换

有时候需要通过网站的域名来获取它的 IP 地址,这时候就要用到下面的转换函数:

#include <netdb.h>

/* 
 * name: 是域名字符串,例如 "www.baidu.com"
 * return: 域名结构体
 */
struct hostent *gethostbyname(const char *name);

struct hostent {
    char  *h_name;            /* 地址名称 */
    char **h_aliases;         /* 地址别名 */
    int    h_addrtype;        /* 地址类型 */
    int    h_length;          /* ip 地址长度 */
    char **h_addr_list;       /* ip 地址数组,一个域名可能对应多个 IP */
}

// 第一个 IP 地址
#define h_addr h_addr_list[0]

例如根据百度域名来获取它的 IP:

// 获取百度的域名结构
struct hostent* baidu_host = gethostbyname("www.baidu.com");

// 获取第一个百度 IP
struct in_addr baidu_addr;
baidu_addr.s_addr = (uint32_t)(baidu_host->h_addr);

// 转换成主机地址
char *baidu_ip_addr = inet_ntoa(baidu_addr);

结语

关于 Linux 网络编程基础还有很多概念,本次主要介绍了一些很重要和很常见的点,这些技术点在实际的编程中都会使用到,所以必须要掌握。对于想要系统学习计算机网络的同学可以参考谢希任老师的《计算机网络》一书。

那么本次就介绍到这里,我们下次再见 :)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • 简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者...
    保川阅读 5,956评论 1 13
  • 1.这篇文章不是本人原创的,只是个人为了对这部分知识做一个整理和系统的输出而编辑成的,在此郑重地向本文所引用文章的...
    SOMCENT阅读 13,063评论 6 174
  • 运输层协议概述 从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是...
    srtianxia阅读 2,406评论 0 2
  • 个人认为,Goodboy1881先生的TCP /IP 协议详解学习博客系列博客是一部非常精彩的学习笔记,这虽然只是...
    贰零壹柒_fc10阅读 5,054评论 0 8
  • 你是否有时候觉得带孩子很吃力,使出了牛劲?但是最终结果不甚满意呢? 其实榜样的力量真的很好用,屡试不爽啊。我喜欢跑...
    徒木立信阅读 226评论 1 1