小白学习之路,网络编程(上)

一,计算机网络基础

在讲网络编程以前,先跟你们简单的介绍一下一些网络相关的知识。前端

在最先以前,两台电脑之间通讯是经过电脑的mac地址找到对方,并实现相互通讯。固然每台电脑都只存在惟一的mac地址,在生产时就已经固定了。后来慢慢的想用一个相似编号的来代替mac地址,也是后来的ip地址。ip地址能够看出是由四个点分十进制构成,因为一个占8位,最大为255,因此ip地址中最大能够表示为255.255.255.255,最小为0.0.0.0。固然这是ipv4,随着如今愈来愈多的计算机,因此出现了ipv6,让更多的计算机能够分配到本身固有的ip地址。ipv6跟ipv4差很少,只是是由六个点分十进制构成的。讲到ip地址,其中127.0.0.0/8被用做回环地址,回环地址表示本机的地址,经常使用于对本机的测试,用的最多的是127.0.0.1。其中经过ip地址找到mac地址是经过Arp协议找到的。子网掩码跟你的ip地址进行按位与运算就能得出一个机器所在的网段。mysql

一个ip地址可以找到一个固体的计算机,而后端口就表示你计算机具体运行的那个程序。端口号的范围在0-65535,咱们通常选择用8000之后的端口号。一些应用默认端口号有8000-酷狗音乐 ,22-ssh ,3306-mysql,oracle-1521,redis-6379,RabbitMQ-15672等等。因此固然知道惟一的ip跟端口号,就能肯定一个计算机上的惟一应用。redis

网络层次划分

为了使不一样计算机厂家生产的计算机可以相互通讯,以便在更大的范围内创建计算机网络,国际标准化组织(ISO)在1978年提出了“开放系统互联参考模型”,即著名的OSI/RM模型(Open System Interconnection/Reference Model)。它将计算机网络体系结构的通讯协议划分为七层,自下而上依次为:物理层(Physics Layer)、数据链路层(Data Link Layer)、网络层(Network Layer)、传输层(Transport Layer)、会话层(Session Layer)、表示层(Presentation Layer)、应用层(Application Layer)。其中第四层完成数据传送服务,上面三层面向用户。sql

  除了标准的OSI七层模型之外,常见的网络层次划分还有TCP/IP四层协议以及TCP/IP五层协议,它们之间的对应关系以下图所示:
固然咱们在这里具体对Tcp/ip5层模型就行介绍。每一个层对应的协议流程关系图以下:

TCP/UDP协议

TCP是面向链接的通讯协议,经过三次握手创建链接,通信完成时要拆除链接,因为TCP是面向链接的因此只能用于端到端的通信。TCP提供的是一种可靠的数据流服务,采用“带重传的确定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。数据库

UDP与TCP位于同一层,但它无论数据包的顺序、错误或重发。所以,UDP不被应用于那些使用虚电路的面向链接的服务,UDP主要用于那些面向查询---应答的服务,例如NFS。相对于FTP或Telnet,这些服务须要交换的信息量较小。编程

使用TCP的协议:FTP(文件传输协议)、Telnet(远程登陆协议)、SMTP(简单邮件传输协议)、POP3(和SMTP相对,用于接收邮件)、HTTP协议等。后端

使用UDP协议包括:TFTP(简单文件传输协议)、SNMP(简单网络管理协议)、DNS(域名解析协议)、NFS、BOOTP。浏览器

在谈到TCP的时候你们可能就很快能想到三次握手,四次挥手,我用个人理解来分析一下怎么回事。服务器

简单讲呢,其实就是两个之间创建通讯,你也能够理解为挖一条链接两个地方的通道。网络

TCP是因特网中的传输层协议,使用三次握手协议创建链接。当主动方发出SYN链接请求后,等待对方回答SYN+ACK[1],并最终对对方的 SYN 执行 ACK 确认。这种创建链接的方法能够防止产生错误的链接。[1] TCP三次握手的过程以下: 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。 三次握手完成,TCP客户端和服务器端成功地创建链接,能够开始传输数据了。

当应用程序但愿经过 TCP 与另外一个应用程序通讯时,它会发送一个通讯请求。这个请求必须被送到一个确切的地址。在双方“握手”以后,TCP 将在两个应用程序之间创建一个全双工 (full-duplex) 的通讯。

下面是方便理解的版本。画的比较丑,emmm,只有将就看。

有人就会想,为何是三次握手四次挥手,不是三次挥手呢。好吧,其实最开始我也是这样想的。

创建一个链接须要三次握手,而终止一个链接要通过四次握手,这是由TCP的半关闭(half-close)形成的。
(1) 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP因而发送一个FIN分节,表示数据发送完毕。
(2) 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。
注意:FIN的接收也做为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其余数据以后,由于,FIN的接收意味着接收端应用进程在相应链接上再无额外数据可接收。
(3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这致使它的TCP也发送一个FIN。
(4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
既然每一个方向都须要一个FIN和一个ACK,所以一般须要4个分节。
注意:
(1) “一般”是指,某些状况下,步骤1的FIN随数据一块儿发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。
(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。
(3) 当一个Unix进程不管自愿地(调用exit或从main函数返回)仍是非自愿地(收到一个终止本进程的信号)终止时,全部打开的描述符都被关闭,这也致使仍然打开的任何TCP链接上也发出一个FIN。
不管是客户仍是服务器,任何一端均可以执行主动关闭。一般状况是,客户执行主动关闭,可是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。

 UDP协议

  当应用程序但愿经过UDP与一个应用程序通讯时,传输数据以前源端和终端不创建链接。

  当它想传送时就简单地去抓取来自应用程序的数据,并尽量快地把它扔到网络上。

TCP与UDP比较

TCP---传输控制协议,提供的是面向链接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间创建一个TCP链接,以后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另外一端。
UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,可是并不能保证它们能到达目的地。因为UDP在传输数据报前不用在客户和服务器之间创建一个链接,且没有超时重发等机制,故而传输速度很快。

二,c/s,b/s架构

1,c/s架构

C/S 架构是一种典型的两层架构,其全称是Client/Server,即客户端服务器端架构。

其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端经过数据库链接访问服务器端的数据;另外一种是Socket服务器端,服务器端的程序经过Socket与客户端的程序通讯。

C/S 架构也能够看作是胖客户端架构。由于客户端须要实现绝大多数的业务逻辑和界面展现。这种架构中,做为客户端的部分须要承受很大的压力,由于显示逻辑和事务处理都包含在其中,经过与数据库的交互(一般是SQL或存储过程的实现)来达到持久化数据,以此知足实际项目的须要。

2,b/s架构

 B/S架构的全称为Browser/Server,即浏览器/服务器结构。

Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现,Browser客户端,WebApp服务器端和DB端构成所谓的三层架构。B/S架构的系统无须特别安装,只有Web浏览器便可。

B/S架构中,显示逻辑交给了Web浏览器,事务处理逻辑在放在了WebApp上,这样就避免了庞大的胖客户端,减小了客户端的压力。由于客户端包含的逻辑不多,所以也被成为瘦客户端。

B/S实际上是属于C/S中的一种特殊状况。可是如今随着internet的发展,不少人习惯于直接访问网页,因此B/S也变得更加的流行起来。

三,socket介绍

什么是socket?

Socket又称"套接字",应用程序一般经过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间能够通信。

首先先熟悉一下流程图,而后根据流程在进行具体的代码分析。

1,Socket Families(地址簇)

socket.AF_UNIX unix本机进程间通讯 

socket.AF_INET IPV4 

socket.AF_INET6  IPV6

2,Socket Types(传输协议)

socket.SOCK_STREAM  #for tcp

socket.SOCK_DGRAM   #for udp 

3,参数

  • family: 套接字家族可使AF_UNIX或者AF_INET
  • type: 套接字类型能够根据是面向链接的仍是非链接分为SOCK_STREAMSOCK_DGRAM
  • protocol: 通常不填默认为0

Python 中,咱们用 socket()函数来建立套接字,语法格式以下:

socket.socket([family[, type[, proto]]]),若是里面不传参数,默认为ipv4,TCP协议

4,socket经常使用方法

bind():绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。

listen():开始TCP监听。backlog指定在拒绝链接以前,操做系统能够挂起的最大链接数量。该值至少为1,大部分应用程序设为5就能够了。

accept() :被动接受TCP客户端链接,(阻塞式)等待链接的到来接受链接并返回(conn,addr),其中conn是新的套接字对象,能够用来接收和发送数据。addr是链接客户端的地址,

connect():主动初始化TCP服务器链接,。通常address的格式为元组(hostname,port),若是链接出错,返回socket.error错误。

recv():接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其余信息,一般能够忽略。

send():发送TCP数据,将string中的数据发送到链接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

recvfrom():接收UDP数据,与recv()相似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sendto():发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。

close():关闭套接字

四,简单的socket使用

前面讲的一些网络知识,其实在写代码的过程当中,没有用到,知识让你明白流程是如何的。下面就写一个简单的socket实现通讯的代码吧。

服务端(server)

 1 import socket
 2 server=socket.socket()
 3 server.bind(('127.0.0.1',1314))#绑定ip地址跟端口号
 4 server.listen()#打开监听
 5 conn,addr=server.accept()#接受链接并返回(conn,address),其中conn是新的套接字对象,能够用来接收和发送数据。address是链接客户端的地址
 6 date=conn.recv(1024)#收到客户端发来的消息(bytes类型)
 7 print(date.decode())
 8 conn.send('我爱你'.encode())#向客户端发送消息
 9 conn.close()#关闭与这个客户端的链接
10 server.close()#关闭
View Code

客户端(client)

1 import socket
2 client=socket.socket()
3 client.connect(('127.0.0.1',1314))#链接到这个ip地址和这个端口号
4 client.send(b'gmx')#向服务端发送消息
5 print(client.recv(1024).decode())#收到服务端发来的消息
View Code

固然,这只是最简单的例子了,咱们明白了基本的道理,能够在上面的基础上实现客户端跟服务端两个的聊天。

服务端(server)

 1 import socket
 2 server=socket.socket()
 3 server.bind(('127.0.0.1',1314))#绑定ip地址跟端口号
 4 server.listen()#打开监听
 5 while True:
 6     conn,addr=server.accept()#在一个客户端断开,还有其余的能连
 7     while True:
 8         recv_data=conn.recv(1024)
 9         print('客户端发来的消息:%s' %recv_data.decode())
10         send_data=input(">>>>")
11         conn.send(send_data.encode())
12     conn.close()
13 server.close()#关闭
View Code

客户端(client)

 1 import socket
 2 client=socket.socket()
 3 client.connect(('127.0.0.1',1314))#链接到这个ip地址和这个端口号
 4 while True:
 5     send_data=input('>>>')
 6     if not send_data:
 7         print('客户端断开')
 8         break
 9     client.send(send_data.encode())
10     recv_data = client.recv(1024)
11     print(recv_data.decode())
12 client.close()
View Code

固然前面的两个例子都是比较简单的socket通讯。后面咱们会讲到作一个简单的ssh,前面接收的数据只有1024字节,那若是在接收的过程当中,数据量比较大应该怎么办呢,还有一种状况就是若是同时发两条消息,而后前面的信息没接收完,后面的又发过去了,就会产生粘包如今,后面咱们会深刻讲到网络通讯的一些东西。

相关文章
相关标签/搜索