Linux网络编程【1】(概念)

390 阅读11分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

1 进程间通信方式:七种

  1. 无名管道

  2. 有名管道

  3. 信号通信

  4. 消息队列

  5. 共享内存

  6. 信号灯集

  7. socket(套接字)通信

网络编程就是最后一种进程间通信方式套接字通信

套接字通信:前六种进程间通信方式只能实现同一台主机的多个进程通信,但是套接字通信可以实现==不同主机==的多个进程间通信

2 发展历史

发展阶段:

Arpanet

TCP/IP协议:一共有两个协议

网络体系结构概念,发明了OSI开放系统互联模型

TCP/IP协议族:有很多个协议组成

2.1 ARPAnet

是网络的最早的雏形,

使用NCP协议

==不能互联不同类型的计算机不同类型的操作系统没有纠错功能==

2.2 TCP/IP两个协议

TCP/IP协议分成了两个不同的协议:

用来检测网络传输中差错的传输控制协议TCP

专门负责对不同网络进行互联的互联网协议IP

3 网络体系结构以及OSI开放系统互联模型

3.1 网络体系结构

网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务网络体系结构即指网络的层次结构和每层所使用协议的集合。

3.2 OSI开放系统互联模型

OSI是ISO(国际标准化组织)提出的一个网络体系结构

OSI因为层次结构太过于复杂,所以到目前也没有使用,但是他是最早提出的网络体系结构,所以其他结构都是基于OSI来改的。

OSI模型一共有七层:

  1. 应用层:面向用户的,应用程序
  2. 表示层:对数据进行加密和解密
  3. 会话层:建立逻辑名字和物理名字之间的关系
  4. 传输层:用于控制数据的有效传输
  5. 网络层:数据分组、路由选择
  6. 链路层:将数据组成发送或者接收的帧数据
  7. 物理层:选择物理介质

注意:每个层次之间的顺序是不能变的

3.3 TCP/IP协议族

由于OSI层次过于复杂,所以目前也没有去使用,所以后期基于OSI又发明了TCP/IP协议族,这个协议族中有很多个协议组成

TCP/IP协议族一共4层

  1. 应用层

  2. 传输层

  3. 网络层

  4. 网络接口与物理层

虽然TCP/IP只有四层结构,但是所做的事情基本跟OSI是一样的

图片.png

图片.png

3.4常用协议

应用层:

  1. HTTP(Hypertext Transfer Protocol) 超文本传输协议

    ​ 万维网的数据通信的基础

  2. FTP(File Transfer Protocol) 文件传输协议

    ​ 是用于在网络上进行文件传输的一套标准协议,使用TCP传输

  3. TFTP(Trivial File Transfer Protocol) 简单文件传输协议

    ​ 是用于在网络上进行文件传输的一套标准协议,使用UDP传输

  4. SMTP(Simple Mail Transfer Protocol) 简单邮件传输协议

    ​ 一种提供可靠且有效的电子邮件传输的协议

  5. DNS 域名解析协议

    ​ 通过url地址转换为IP地址

传输层:

TCP(Transport Control Protocol) 传输控制协议

是一种面向连接的、可靠的、基于字节流的传输层通信协议

UDP(User Datagram Protocol) 用户数据报协议

是一种无连接、不可靠、快速传输的传输层通信协议

网络层:

IP(Internetworking Protocol) 网际互连协议

是指能够在多个不同网络间实现信息传输的协议

ICMP(Internet Control Message Protocol) 互联网控制信息协议

用于在IP主机、路由器之间传递控制消息

IGMP(Internet Group Management Protocol) 互联网组管理

是一个组播协议,用于主机和组播路由器之间通信

网络接口与物理层

ARP(Address Resolution Protocol) 地址解析协议

通过IP地址获取对方mac地址

RARP(Reverse Address Resolution Protocol) 逆向地址解析协议

通过mac地址获取对方ip地址

注意事项:每层应该用哪个协议是由下层协议决定的,不能乱用

图片.png 数据的封装和解包过程:

图片.png

图片.png

MTU:最大传输单元,linux是1500个字节

4 TCP和UDP的异同点

相同点:

同为传输层协议

不同点:

TCP有连接,是可靠的数据传输协议

UDP无连接,是不可靠的数据传输协议

TCP(即传输控制协议)概念:

​ 是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信),TCP有回传机制

适用情况:

适合于对传输质量要求较高,以及传输大量数据的通信。

在需要可靠数据传输的场合,通常使用TCP协议

MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议

UDP(User Datagram Protocol)用户数据报协议是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

适用情况:

发送小尺寸数据(如对DNS服务器进行IP地址查询时)

在接收到数据,给出应答较困难的网络中使用UDP。(如:无线网络)

适合于广播/组播式通信中。

MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常

采用UDP 协议

流媒体、VOD、VoIP、IPTV等网络多媒体服务中通常采用UDP方式进行

实时数据传输

5 编程相关的概念内容

字节序

socket

ip地址

端口号

5.1 字节序

不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO):

小端序(little-endian) - 低序字节存储在低地址

将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式;

大端序(big-endian)- 高序字节存储在低地址

将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用

图片.png

测试主机字节序:

#include <stdio.h>

//判断主机字节序

int main(int argc, char const *argv[])
{
    int a = 0x12345678;
    char *p = (char *)&a;

    printf("*p = %#x\n", *p);

    if(*p == 0x78)
    {
        printf("小端存储\n");
    }
    else 
    {
        printf("大端存储\n");
    }

    return 0;
}

如果多台主机在通信的时候字节序不一样,则接收到的数据与发送的数据就有可能不一样,所以为了保证每台主机接收和发送的数据没有问题,发明了网络字节序,意味着只要是将数据发送给对方,就必须将数据先转换成网络字节序再发送,接收者接收到的数据是网络字节序的数据,所以需要将其转化为主机字节序再解析

网络字节序是大端存储

什么时候需要转化,转化的数据有什么性质:

主机字节序不确定是否一样时需要转化,如果一样不转化也可以

如果说数据是按照一个字节为单位的,是不需要转化的,只有将两个字节以上的内容作为一个整体才需要转化

#include <arpa/inet.h>

将主机字节序转化为网络字节序
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);

将网络字节序,转化为主机字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

//操作码
code = ntohs(*(unsigned short *)buf);
//块编号或者差错码
num = ntohs(*(unsigned short *)(buf + 2));

验证主机字节序转网络字节序

#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, const char *argv[])
{
    	unsigned int a = 0x12345678;
    	unsigned int b = htonl(a);

    	printf("%#x --> %#x\n", a, b);
	
	return 0;
}

执行结果

图片.png

5.2 socket

socket,也就是套接字通信原本只能实现一台主机的多个进程间通信,称之为本地通信,后期加入了TCP/IP协议族,实现了不同主机的进程间通信

socket是一个函数,会产生一个文件描述符,所以只要对这个文件描述符进行操作,就可以实现通信,所以把套接字也称之为一个文件描述符

socket不光在tcp/ip协议族中使用,在其他网络体系结构中要使用

套接字类型:

  1. 流式套接字(SOCK_STREAM) --- TCP

    ​ 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。

  2. 数据报套接字(SOCK_DGRAM) --- UDP

    ​ 提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。

  3. 原始套接字(SOCK_RAW),

    ​ 可以对较低层次协议如IP、ICMP直接访问。

    ==网络套接字可不是==

5.3 IP地址

MAC地址是每一个网卡在出厂的时候分配的一个编号,所以mac一般用于在局域网中通信,是局域网中确定唯一一台主机的编号

mac地址占6个字节

IP地址是网络中唯一确定一台主机的编号

IP地址的分类:

IPV4:占4个字节,占32位

IPV6:占16个字节,占128位

IPV4地址的表示形式:

人为识别的表示形式:

点分十进制,例如192.168.71.70,将4个字节按照一个字节为单位,用.将其隔开,是一个字符串

网络中ipv4的表示形式:无符号的4字节整数

图片.png

IPV4地址的分类:(前八位来区分)

A类 0000 0000 - 0111 1111 0.x.x.x - 127.x.x.x

B类 1000 0000 - 1011 1111 128.x.x.x - 191.x.x.x

C类 1100 0000 - 1101 1111 192.x.x.x - 223.x.x.x

D类 1110 0000 - 1110 1111 224.x.x.x - 239.x.x.x

E类 1111 0000 - 1111 1111 240.x.x.x - 255.x.x.x

特殊的IP地址:

E类:属于保留测试

D类:属于组播地址

127.x.x.x:表示本机地址,主要用于一台主机的多个进程间

​ 通信时使用

局域网IP地址:任意一个ip地址都可以通过路由器下分局域

​ 网ip地址

图片.png

C类ip地址某一个网段例如192.168.70特殊IP地址:

192.168.70.0 表示网段,或者叫做网络号

192.168.70.255 表示广播地址

192.168.70.1 表示网关地址,就是路由器的ip地址

所以一个网段的最大主机的连接数理论是256个,实际是254个

子网掩码:

子网掩码可以区分一个ipv4地址的网络号和主机号,进而可以判断出当前网段连接主机的最大数

子网掩码是由连续的1和连续的0组成,连续的1对应的ip地址的位表示网络号,连续的0对应的ip地址的位表示主机号,有多少位0,就表示可以连接的主机最大数

默认的子网掩码:

A类 255.0.0.0

B类 255.255.0.0

C类 255.255.255.0

图片.png 192.168.70网段,设置的子网掩码255.255.255.128,请问理论连接的最大主机数是128个,实际连接的是126个,实际分配的ip地址的范围是192.168.70.129 - 192.168.70.254

我们是的点分十进制ip地址和计算机识别的无符号4字节整数ip地址之间的转换

图片.png

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

将点分十进制字符串ip地址转化为网络字节序的无符号4字节整数ip地址
in_addr_t inet_addr(const char *cp);

将网络字节序的无符号4字节整数ip地址转化为点分十进制字符串ip地址
char *inet_ntoa(struct in_addr in);
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    unsigned char ip_str[] = "192.168.70.71";
    unsigned int ip_int;

    ip_int = inet_addr(ip_str);

    printf("ip_int = %u\n", ip_int);

    unsigned char *p = (unsigned char *)&ip_int;

    printf("%d.%d.%d.%d\n", *p, *(p+1), *(p+2), *(p+3));

    return 0;
}

5.4 端口号

进程号是唯一标识一台主机的一个进程的,但是进程如果结束在开启,一般进程号都会改变,这样不利于去控制和操作,所以发明了端口号,端口号是人为设置的对一台主机的唯一一个进程的标识

端口号一般由IANA (Internet Assigned Numbers Authority) 管理

众所周知端口:11023(1255之间为众所周知端口,

​ 256~1023端口通常由UNIX系统占用)

已登记端口:1024~49151

动态或私有端口:49152~65535

可以在文件/etc/services中查看已经被占用的端口号

一般我们可以使用 6666 7777 8888 9999 10000 10001

常用协议端口号:

http 80,8080

SMTP 25

FTP 20,21

TFTP 69

DNS 53