Linux网络编程【Socket编程预备】

1. 网络通信的本质

表面上来看两台主机之间进行网络通信是数据从一台主机传输到另一台主机,但是发送数据的是人,是我们用户。我们在学系统的时候就说过进程就是用户的代表,我们在手机电脑上打开一个APP或者点击浏览器本质上是启动一个进程。因此,我们将数据给到进程,也就是我们用户拿到数据了!!

所以,我们可以得出结论数据传输到目标主机不是我们用户的目的,而是我们用户之间进行数据交互的手段,而我们真正的目的是将数据交给主机内部的进程!!

我们在上网的时候,只有两种行为:1.从远端服务器上获取数据。2.把本地数据上传到远端服务器上。这时候就涉及到两台不同主机之间的进程间通信了!!所以,网络通信的本质就是进程间通信!而它们需要通信就需要看到同一份资源,而这个资源就是网络!!

2. 认识端口号 

不过,这里又会引发一个新的问题:当数据传输到目标主机的时候,目标主机内存中存在着大量的进程。数据是如何发送给目标主机的呢??这就需要再网络的背景下,在系统中标识进程的唯一性

端口号【port】是传输层协议的内容,他是一个2个字节16位的整数。端口号用来唯一标识一个进程,告诉操作系统,当前数据需要交付给那个进程。所以,IP地址+端口号就可以标识网络上某一台主机的某一个进程。

一个进程原则上来说只占用一个端口号,但是也有例外。不过,要确保一个端口号只能找到一个进程。

端口号范围划分:

• 0 - 1023 :知名端口号,HTTP, FTP, SSH 等这些广为使用的应用层协议,他们的端口号都是固定的.

• 1024 - 65535 :操作系统动态分配的端口号.客户端程序的端口号,就是由操作系统从这个范围分配的.

在系统当中,进程pid也可以标识进程的唯一性,为什么在网络传输层设计的时候需要需要用端口号标识进程的唯一性呢??主要原因就是:进程pid时系统的概念,如果系统进程pid发生变化,那么网络出传输层也需要发生变化。如此一来,系统和网络就有强耦合了。所以这样设计并没有性价比,为了解耦合,网络传输层就设计了端口号来唯一标识进程

总结一下:

• 综上, IP 地址用来标识互联网中唯⼀的⼀台主机, port 用来标识该主机上唯⼀的⼀个网络进程。

• IP+Port 就能表示互联网中唯⼀的⼀个进程。

• 所以,通信的时候,本质是两个互联网进程代表人来进行通信,{srcIp,srcPort,dstIp,dstPort} 这样的4元组就能标识互联网中唯⼆的两个进程。

• 所以,网络通信的本质,也是进程间通信。

• 我们把 ip+port 叫做套接字 socket。

3. 初识TCP和UDP协议

现在我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的,那么我们要通 过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的网络通信。

> 此处我们先对 TCP ( Transmission Control Protocol 传输控制协议)有⼀个直观的认识;后面我们再详细讨论TCP的⼀些细节问题。

特点:• 传输层协议 • 有连接 • 可靠传输 • 面向字节流

> 此处我们也是对 UDP ( User Datagram Protocol 用户数据报协议)有⼀个直观的认识;后面再详细讨论。

特点:• 传输层协议 • 无连接 • 不可靠传输 • 面向数据报

因为我们暂时还没有深入了解 tcp 、 udp 协议,此处只做了解即可。

注意:在上面的的特点当中可靠与不可靠并不是褒义或者贬义,他是一个中性词。可靠传输会检查是否丢包,什么时候重新传输数据,做各种检查和工作。所以它势必会更加复杂,占用的资源也就很多了!!所谓的不可靠指的是我给你传输数据后我就不管你了,这就意味着它很简单,占用资源少。【所以,一般在直播都是使用的UDP协议的!!】这要结合不同场景来灵活运用对应的协议。

4. 网络字节序 

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于 文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分.那么如何定义网络数据流的地址呢?

• 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;

• 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;

• 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.

• TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.

• 不管这台主机是大端机还是小端机,都会按照这个TCP/IP规定的网络字节序来发送/接收数据;

• 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可;

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换

• 这些函数名很好记, h表示host , n 表示network , l 表示32位长整数, s 表示16位短整数

• 例如 htonl 表示 将 32 位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。

• 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;

• 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

5. Socket编程接口 

Socket常见API:

// 创建 socket ⽂件描述符 (TCP/UDP, 客⼾端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端⼝号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr *address, socklen_t *address_len);
// 建⽴连接 (TCP, 客⼾端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

在上面的接口当中sockaddr结构出现了三次,其实Socket是遵守POSIX标准的。所以在网络通信中,他一定是有一套规范的接口的!!但是,Socket还支持本地间的进程间通信。Socket的设计者为了避免设计两套接口,索性就合二为一了。通过sockaddr来设计:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋风起,再归来~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值