网络编程(1)

一、网络编程(1)

  • 以下详情,看nick的博客。

1. 网络架构及其演变过程

(1)单机架构

  • 单机架构就是只有客户端的应用程序,即不需要联网的应用。例如:单机游戏和单机软件。

(2)C/S架构

  • C 是 Client (客户端) , S 是 Server (服务端)。例如一些需要联网的应用,QQ , 英雄联盟等
  • 优点: 数据分客户端和服务端分别存储,节省了网络资源
  • 缺点:数据的安全性和稳定性可能会有一定的问题。升级较麻烦

(3)B/S架构

  • B 是 Browser (浏览器) , S 是 Server (服务端) 。例如谷歌浏览器 , 而浏览器本身也是C/S架构 ,对于浏览器内部的内容,也就是一个个网站是 B/S架构

  • 优点:服务器统一处理数据,有更好的安全性和稳定性,且升级比较容易。

  • 缺点:服务器负担增加,占用网络资源较大。

2. 互联网协议(OSI协议)

(1)OSI协议 的人为分层

  • 人为的把分OSI协议分成了七层,也有分为五层的,四层的。

  • 七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

  • 五层:应用层、传输层、网络层、数据链路层、物理层

  • 四层:应用层、传输层、网络层、网络接口层

(1)物理层

  • 物理层功能:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0

    物理层字面意思解释:物理传输、硬件、物理特性。在深圳的你与北京的朋友聊天,你的电脑必须要能上网,物理体现是什么?是不是接一根网线,插个路由器,北京的朋友那边是不是也有根网线,也得插个路由器。也就是说计算机与计算机之间的通信,必须要有底层物理层方面的连通,就类似于你打电话,中间是不是必须得连电话线。

  • **中间的物理链接可以是光缆、电缆、双绞线、无线电波。中间传的是电信号,即010101...这些二进制位。 **

(2)数据链路层

  • 数据链路层由来:单纯的电信号0和1没有任何意义,必须规定电信号多少位一组,每组什么意思

    数据链路层的功能:定义了电信号的分组方式

1. 以太网协议
  • 早期的时候,数据链路层就是来对电信号来做分组的。以前每个公司都有自己的分组方式,后来形成了统一的标准,即以太网协议ethernet

    ethernet规定:一组电信号构成一个数据报,叫做'帧',每一数据帧分成:报头head和数据data两部分

  • 数据报的具体内容:head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送

2. Mac地址
  • head中包含的源和目标地址由来:ethernet规定接入internet的设备都必须具备网卡,发送端和接收端的地址便是指网卡的地址,即Mac地址

  • Mac地址:每块网卡出厂时都被烧制上一个世界唯一的Mac地址,长度为48位2进制,通常由12位16进制数表示(前六位是厂商编号,后六位是流水线号)

3. 广播地址
  • 就是局域网内,一台主机向局域网内的其他全部主机发送一个消息。所有人都收到了,但只有是ip地址是我要的那个的主机会响应,他会把自己的Mac地址填到这个消息里返回给我,别的主机会把这个消息丢弃。此时可以实现局域网内的通信。
4. 广播风暴
  • 就是一个局域网内多个主机都在同一时间广播,相当于广播1撞广播2。

  • 注意:在讲网络层之前,其实基于广播的这种通信就可以实现全世界通信了,你吼一声,如果全世界是一个局域网,全世界的计算机肯定可以听得见,从理论上似乎行得通,如果全世界的计算机都在吼,你想一想,这是不是一个灾难。因此,全世界不能是一个局域网。于是就有了网络层。

(3)网络层

  • 网络层功能:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址

  • 网络通信的方式:

    本质都是两个Mac地址通信。

    局域网内: 有了目标ip之后,通过广播,获取目标ip的Mac地址,两个主机就可以通信了

    互联网通信:有了目标ip之后,通过广播,广播到自己的网关 , 自己的网关通过目标ip找到在互联网里找到对方的网关,对方的网关在自己的局域网里广播,同上面的局域网通信。

(4)传输层

  • 传输层的由来:网络层的IP帮我们区分子网,以太网层的Mac帮我们找到主机,然后大家使用的都是应用程序,你的电脑上可能同时开启qq,暴风影音,等多个应用程序。

  • 那么我们通过IP和Mac找到了一台特定的主机,如何标识这台主机上的应用程序,答案就是端口,端口即应用程序与网卡关联的编号。

  • 传输层功能:建立端口到端口的通信

  • 补充:端口范围0-65535,0-1023为系统占用端口,我们一般取8000之后的端口号,8000之前的可能被现在很多软件占用了。

  • 有了Mac地址+IP地址+端口,我们就能确定世界上独一无二的一台计算机上的应用程序

  • TCP 和 UDP协议工作在这一层。

  • UDP,在传送数据前不需要先建立连接,远地的主机在收到UDP报文后也不需要给出任何确认。虽然UDP不提供可靠交付,但是正是因为这样,省去和很多的开销,使得它的速度比较快,比如一些对实时性要求较高的服务,就常常使用的是UDP。对应的应用层的协议主要有 DNS,TFTP,DHCP,SNMP,NFS 等。

    TCP,提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。因此TCP是一种可靠的的运输服务,但是正因为这样,不可避免的增加了许多的开销,比如确认,流量控制等。对应的应用层的协议主要有 SMTP,TELNET,HTTP,FTP 等。

  • TCP 的三次握手和四次挥手 (非常重要)

  • MSL 报文最大生存时间,任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃,tcp协议规定,这个时间可以自行更改。

  • 为什么是TCP三次握手而不是两次?

简单来说就是:防止 已过期或者说是先前 的连接请求报文突然又传送的服务器,因而造成错误。

发送端接收到接收端发送的报文,知道接收端刚才接收到了自己的消息,按理说,这个时候连接就建立了,该发数据了啊,为什么还要再确定一次呢?

这里我们用一个现实的例子来解释.就拿大家都喜欢的约会来解释.发送端相当一个男生,接收端是一个女生.一开始,男生发送一条微信告诉女生,今天晚上九点在公园见面呗,然后这条消息因为不可抗力,没有发送到女生的手机上,这时,这条消息有两个去路,一个是彻底消失,另一个是它迷失在网络中,没有找到方向.回来继续说,男生看女生没有回应,就又发了一条一样的微信,这次微信顺利的发过去了,男生女生也顺利的见面了,这一天也就这么过去了.到了第二天,那条迷失在网络中的微信重新找到了方向(真正的网络信息不可能滞留这么久,例子而已),发到了女生的手机上,女生一看,很高兴,毕竟昨天玩的很开心,以为今天又可以开心一次,就又去了,男生昨天玩了一晚上,身体跟不上,就在家躺着,也早忘了那条迷失的微信.就这样,女生在公园等了很久,很难受.

其实上面的例子已经说的很明白了,保险起见,再在具体连接里说一下.如果是两次连接,很可能发生上面的问题,如果有消息在一次tcp连接完成后才到达接收端,那么接收端以为是新的连接,就会发确认报文到接收端确认并建立连接,但发送端可能已经关闭,即使没关闭,在没有到达SYN-SENT状态时,也不会响应接收端的确认信息,接收端可能就这样等待,这在网络中就浪费了资源.

但是有了第三次报文确定就不一样了,第三次,发送端在此发送确认报文包接收端,接收端接收到后,也就知道了发送端接收到自己的确认信息了,如果在此发生上面的问题,接收端再次接收到了滞留在网络中的信息,发送确认信息给发送端,但是当发送端没有理会的时候,接收端也就知道这是错误信息,就不会等待,也就没有资源浪费了.

说句题外话,即使是三次握手也不能保证百分百的连接确定。

(5)应用层

  • 应用层由来:用户使用的都是应用程序,均工作于应用层,互联网是开发的,大家都可以开发自己的应用程序,数据多种多样,必须规定好数据的组织形式

    应用层功能:规定应用程序的数据格式。

3. socket

3.1 什么是socket

  • Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  • 注意:也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序,而程序的pid是同一台机器上不同进程或者线程的标识。

3.2 服务端套接字函数

方法 用途
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

3.3 客户端套接字函数

方法 用途
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

3.4 公共用途的套接字函数

方法 用途
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
posted @ 2019-10-17 16:24  BigSun丶  阅读(117)  评论(0编辑  收藏  举报