网络编程:
python27day26网络编程--------------------------------------------------------------------------------------------
网络基础-端口号:
端口号: 用来标记区分进程
⼀台拥有IP地址的主机可以提供许多服务, ⽐如HTTP(万维⽹服务) 、 FTP(⽂件传输) 、SMTP(电⼦邮件) 等,
这些服务完全可以通过1个IP地址来实现。 那么,主机是怎样区分不同的⽹络服务呢?显然不能只靠IP地址,
因为IP地址与⽹络服务的关系是⼀对多的关系。实际上是通过“IP地址+端⼝号”来区分不同的服务的。
端⼝号是一个数字,只有整数, 范围是从0到65535 (分为知名和动态两种)
知名端⼝是众所周知的端⼝号(用来做固定事情), 范围从0到1023
80端⼝分配给HTTP服务(网站)
21端⼝分配给FTP服务(文件下载)
可以理解为, ⼀些常⽤的功能使⽤的号码是固定的
动态端⼝的范围是从1024到65535之所以称为动态端⼝, 是因为它⼀般不固定分配某种服务, ⽽是动态分配。
动态分配是指当⼀个系统进程或应⽤程序进程需要⽹络通信时, 它向主机申请⼀个端⼝,
主机从可⽤的端⼝号中分配⼀个供它使⽤
网络基础-协议:
协议:约定好的规范
早期的计算机⽹络, 都是由各⼚商⾃⼰规定⼀套协议, IBM、 Apple和Microsoft都有各⾃的⽹络协议,
互不兼容(语言、方言、阿帕网)为了把全世界的所有不同类型的计算机都连接起来,
就必须规定⼀套全球通⽤的协议, 为了实现互联⽹这个⽬标, 互联⽹协议簇(Internet ProtocolSuite)
就是通⽤协议标准。因为互联⽹协议包含了上百种协议标准, 但是最重要的两个协议是TCP和IP协议,
所以, ⼤家把互联⽹的协议总称TCP/IP协议 (大家都遵循的最基本网络通信协议)
是完成进程之间通信的规范
根据TCP/IP协议簇功能的不同,将它分为了几种层次( TCP/IP协议簇层次划分)(重点记住)
网络接口层(链路层)
网络层
传输层
应用层
(写代码按四层划分)
物理层
数据链路层
网络层
传输层
会话层
表示层
应用层
(理论上由七层组成)
简称:应表会传网数物
在早期,不同的公司都推出了属于自己的私有网络协议,相互之间不能兼容
于是,ISO(国际标准化组织)站出来:干脆这样,我给大家制定一个通用的网络通信协议,该协议是国际标准
于是ISO博览众家之长,制订了“一堆”详细的,复杂的,繁琐的,精确的网络通信协议
不过这堆协议太复杂了,为了理清思路,便于学习,将他们分了7类(也就是分了7层),不同层代表不同的功能,
并把这些协议归到相应的层里面去。国际标准出来了,接下来就要软件/硬件厂商去实现了。
但实际上各厂商并没有完整实现7层协议,因为7层协议栈追求全能、完善,导致它太过复杂,实现起来太难了
于是,实际使用时,按4层划分(5层划分非官方)
OSI七层协议,是英文Open System Interconnect的缩写,中文翻译开放系统互联
TCP/IP定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准
4层的层级结构中,每一层都呼叫它的下一层所提供的网络来完成自己的需求
其中的应用层关注的是应用程序的细节,而不是数据在网络中的传输活动其他三层主要处理所有的通信细节,
对应用程序一无所知;
应用层:应用程序间沟通的层,不同的文件系统有不同的文件命名原则和不同的文本行表示方法等,
不同的系统之间传输文件还有各种不兼容问题,这些都将由应用层来处理
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,
这一层负责传送数据,并且确定数据已被送达并接收
网络层:负责提供基本的数据包传送功能,让每一块数据包都能够到达目的主机。
网络层接收由更低层发来的数据包,并把该数据包发送到更高层,相反,
IP层也把从TCP或UDP层接收来的数据包传送到更低层
网络接口层:对实际的网络媒体的管理,定义如何使用实际网络来传送数据(处理机械的、电气的和过程的接口)
socket:通过网络完成进程间通信的方式(区别于一台计算机之间进程通信)
Socket的英文原义是“插孔”。通常也称作"套接字“
Socket本质是编程接口(API): Socket 是对 TCP/IP 协议的封装,Socket 只是个编程接口不是协议,
通过 Socket 我们才能使用 TCP/IP 协议簇(程序员层面)
TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,
提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力
最重要的是,Socket是面向客户/服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认
创建Socket:
import socket
#导入套接字模块
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s此时是一个socket对象,拥有发送和接收网络数据的功能
该函数带有两个参数(参数必须写)
AF_INET(ipv4协议⽤于 Internet 进程间通信)
套接字类型, 可以是 SOCK_STREAM(流式套接字, ⽤于TCP 协议) 或者 SOCK_DGRAM(数据报套接字, ⽤于 UDP 协议)
TCP慢但是稳定不会丢数据
UDP快但是可能会丢数据(黑客攻击)
确定了IP地址端口号(ipv4协议),TCP或UDP协议之后,计算机之间可以进行通信
Socket编程-udp和tcp:
UDP --- User Data Protocol,用户数据报协议, 是⼀个⽆连接的简单的⾯向数据报的传输层协议。
UDP不提供可靠性, 它只是把应⽤程序传给IP层的数据报发送出去, 但是并不能保证它们能到达⽬的地。
由于UDP在传输数据报前不⽤在客户和服务器之间建⽴⼀个连接, 且没有超时重发等机制, 故⽽传输速度很快
UDP⼀般⽤于多点通信和实时的数据业务, ⽐如:
语⾳⼴播
视频
TFTP(简单⽂件传送)
可以理解为写信
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接
一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,只简单的描述下这三次对话的简单过程:
主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话
主机B向主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话
主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话
三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据
可以理解为打电话,先建立通道
TCP与UDP的区别:
1.基于连接与无连接
2.对系统资源的要求(TCP较多,UDP少)
3.UDP程序结构较简单
4.流模式与数据报模式
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
发送数据:
为看到效果先安装“网络调试助手”
from socket import *
s = socket(AF_INET, SOCK_DGRAM) #创建套接字
addr = ('192.168.1.17', 8080) #准备接收方地址
data = input("请输入:")
s.sendto(data.encode(),addr)
#发送数据时,python3需要将字符串转成byte
#encode(‘utf-8’)# 用utf-8对数据进行编码,获得bytes类型对象
#decode()反过来
s.close()
from socket import *
s = socket(AF_INET,SOCK_DGRAM)
addr = ("192.168.19.138",8080)
s.sendto("你好啊".encode("gb2312"),addr)
s.close()
发送数据给飞秋:
飞秋使用:2425端口
发送普通数据,飞秋不会响应,必须发送特殊格式的内容
1:123123:吴彦祖:吴彦祖-pc:32:haha
飞秋有自己的应用层协议
1,表示版本
后面的数字发送的时间,随便写
32代表发送消息
飞秋炸弹:循环不延时发消息(可能会造成卡死)
注意:IP和端口在网络通信中缺一不可,用到的协议也要匹配,例如飞秋用的是udp协议,使用TCP协议发数据是无效的
udp理解为写信(只有收件人地址),TCP理解为打电话(先拨号建立通路,需要通路稳定)
UDP协议:
导入模块:
from socket import *
准备接受方的地址
注意,要放在元组中
IP地址,放在字符串当中
addr = ("192.168.19.138",2425)
创建套接字对象
s1 = socket(AF_INET,SOCK_DGRAM)
发送消息,先写要发送的数据(要转成字节流,这是网络传输数据的规定)
后面要写接收方地址
s1.sendto("1:123:张达:张达-pc:32:你好啊".encode("gb2312"),addr)
s1.close()
接收数据
from socket import *
s = socket(AF_INET, SOCK_DGRAM) #创建套接字
addr = ('192.168.1.17', 8080) #准备接收方地址
data = input("请输入:")
s.sendto(data.encode(),addr)
#等待接收数据
redata = s.recvfrom(1024)
#1024表示本次接收的最大字节数
print(redata)
s.close()
from socket import *
s = socket(AF_INET,SOCK_DGRAM)
addr = ("192.168.19.138",8080)
s.sendto("你好啊".encode("gb2312"),addr)
redata = s.recvfrom(1024)
print(redata)
s.close()
绑定信息:
如果信息没有绑定,每发送一次信息,系统会随机分配一个端口
还要避免同一台计算机上的不同进程端口号相同的问题
绑定信息:让一个进程可以使用固定的端口
一般情况下,发送方不绑定端口,接收方会绑定
from socket import *
s = socket(AF_INET, SOCK_DGRAM) #创建套接字
s.bind(('', 8788)) #绑定一个端口,ip地址和端⼝号,ip⼀般不⽤写
addr = ('192.168.1.17', 8080) #准备接收方地址
data = input("请输入:")
s.sendto(data.encode(),addr)
redata = s.recvfrom(1024) #1024表示本次接收的最⼤字节数
print(redata)
s.close()
echo服务器:Echo服务是一种非常有用的用于调试和检测的工具。这个协议的作用也十分简单,
接收到什么原封发回
Socket编程-udp编程:
from socket import *
#1创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2绑定本地信息,不使用随机分配的端口
bindAddr = ("",7088)
udpSocket.bind(bindAddr)#绑定
num = 0
while True:
#接收对方发送的数据
recvData = udpSocket.recvfrom(1024)
print(recvData)
#将接收到的数据回发给对方
udpSocket.sendto(recvData[0],recvData[1])
num += 1
print("已将接收到的第%d个数据返回给对方,"%num)
udpSocket.close()
聊天室
from socket import *
import time
#1创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
bindAddr = ("",7088)
udpSocket.bind(bindAddr)#绑定
while True:
#接收对方发送的数据
recvData = udpSocket.recvfrom(1024)
print('【%s】 %s.%s' %(time.ctime(),recvData[1],recvData[0].decode("GB2312")))
a = input("请输入:")
udpSocket.sendto(a.encode('GB2312'),('192.168.1.17',8080))
#5关闭套接字
udpSocket.close()
udp网络通信过程:(类似于发快递)
1,应用层编写数据(你好),然后向下层传递2,传输层在数据前面加上端口号(包括发送端口和目的端口)
3,网络层继续在前面加上IP地址(包括原IP和目的IP)
4,链路层再在前面加上mac地址(mac:硬件地址,用来定义网络设备的位置)
此时数据变成了:mac地址 IP地址 端口号 数据内容
之后通过网络传输给另一台计算机的链路层开始逐步解析判断
练习:
使⽤多线程完成⼀个全双⼯的聊天程序
全双工(Full Duplex)是通讯传输的一个术语。通信允许数据在两个方向上同时传输(电话)
单工是只允许甲方向乙方传送信息,而乙方不能向甲方传送(收音机)
半双工:甲方发消息时乙方只能收不能发(对讲机)
字符集:
ASCII
英文字符集 1个字节
ISO8859-1
西欧字符集 1个字节
BIG5
台湾的大五码,表示繁体汉字 2个字节
GB2312
大陆使用最早、最广的简体中文字符集 2个字节
GBK
GB2312的扩展,可以表示繁体中文 2个字节
GB18030
最新GBK的扩展,可以表示汉字、维吾尔文、藏文等中华民族字符 2个字节
Unicode
国际通用字符集 2个字节
UDP协议:
导入模块:
from socket import *
准备接受方的地址
注意,要放在元组中
IP地址,放在字符串当中
addr = ("192.168.19.138",2425)
创建套接字对象
s1 = socket(AF_INET,SOCK_DGRAM)
data = input("请输入:")
发送消息,先写要发送的数据(要转成字节流,这是网络传输数据的规定)
后面要写接收方地址
s1.sendto(data.encode("gb2312"),addr)
s1.sendto("abc".encode("gb2312"),addr)
s1.close()