网络编程

2019年11月24日 阅读数:156
这篇文章主要向大家介绍网络编程,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。
一 C\S架构,客户端服务端架构⑩
客户端(client) : 享受服务端提供的服务
服务端(server) : 给客户端提供服务
服务端:提供服务的
客户端:享受服务的
软件CS架构:京东,淘宝,qq,微信,暴风影音,快播
硬件CS架构:打印机
B\S 浏览器和服务端 B(browser) 谷歌,360,IE
二 网络通讯的整个流程(硬件\名词)
网卡: 接收电信号,网络插口:插网线
 
mac地址(物理地址): 8C-EC-4B-87-99-D7 ①
16进制的6个数表示,前三位厂商编号,后三位生产流水号
网络设备的惟一标识,全球惟一的,至关于身份证
广播\单播
广播: 信息发给全部人⑨
单播: 单独发给某我的或者说某个设备
广播风暴: 不安全, 容易拥堵网络
 
IP地址: 划分广播域,192.168.15.113 四个点分十进制组成②
IPv4 : 4个点分十进制
IPv4 地址:192.168.15.192
IPv6 : 6个冒号分十六进制
IPv6 地址: fe80::48c3:8f81:8474:c7d0%2
 
集线器 : 将全部连电脑设备连通起来
交换机: 升级版集线器⑤
DHCP协议 : 自动分配IP地址③
 
划分广播域--> IP网段 : 192.168.15.0 - 192.168.15.255 属于同一子网
192.168.16.0 - 192.168.16.255
子网掩码 : 计算目标IP地址是否和我们是同一网段(计算是否属于同一网段)⑥
同一网段的:广播发送
不一样网段的:发送给路由器
子网掩码: 255.255.255.0,
例外一个班的同窗的IP地址为:192.168.14.12
192.168.14.12
255.255.255.0
11000000.10101000.00001110.00001100
11111111.11111111.11111111.00000000
11000000.10101000.00001110.00000000
192.168.14.0
属于同一个网段的,咱们成为属于同一子网
路由器(内网的做用) : 管理局域网④
 
找外部网路的设备:
DNS服务器:域名: www.jd.com -->ip地址⑧
域名: www.jd.com --> IP地址
DNS服务器:记录着全部的域名和他网站对应的那台服务器的IP地址的对应关系,理解为一个字典
{' www.jd.com':192.168.15.12}
网关:在路由器这儿,把关你对外网的请求⑦
NAT技术: 网络地址转换,将你的IP地址,转换为网关的IP地址
外网又称为公网 ,网关的IP地址又称为外网IP地址或者公网IP地址
 
 
路由器(外网的做用) : 转发消息
路由器:管理网络,连通外网,而且路由转发,就是转发消息
路由协议 : 计算一个最优路径,而后进行路由转发
发到京东的路由器上,京东的路由器作了端口映射(看图)
 
端口:标识电脑上某个应用程序,范围0-65535 0-1024 属于电脑内部程序用的,咱们通常使用的都是8000之后的
端口:电脑给你建立的标识电脑上的程序用的.
ip加端口(“192.168.15.192”,1-65535)1024 以前都是电脑本身的不能用,用后面的。
经过IP地址+端口:我就能惟一肯定一台电脑上的某个应用程序
三初始socket(重点)
 
tcp与udp下socket差别图
 
    1 网络通讯协议
        osi七层 应示会偷网链物
        
 
osi七层
各层的功能简述:
    【1】物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各类传输介质的传输速率等。它的主要做用是传输比特流(就是由一、0转化为电流强弱来进行传输,到达目的地后在转化为一、0,也就是咱们常说的数模转换与模数转换),这一层的数据叫作比特。
 
  【2】数据链路层:定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问,这一层一般还提供错误检测和纠正,以确保数据的可靠传输。
 
  【3】网络层:在位于不一样地理位置的网络中的两个主机系统之间提供链接和路径选择,Internet的发展使得从世界各站点访问信息的用户数大大增长,而网络层正是管理这种链接的层。
 
  【4】传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性偏偏相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是经过这种方式传输的), 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组,经常把这一层数据叫作段。
 
  【5】会话层:经过传输层(端口号:传输端口与接收端口)创建数据传输的通路,主要在你的系统之间发起会话或者接受会话请求(设备之间须要互相认识能够是IP也能够是MAC或者是主机名)。
 
  【6】表示层:可确保一个系统的应用层所发送的信息能够被另外一个系统的应用层读取。例如,PC程序与另外一台计算机进行通讯,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另外一台则使用美国信息交换标准码(ASCII)来表示相同的字符。若有必要,表示层会经过使用一种通格式来实现多种数据格式之间的转换。
 
  【7】应用层: 是最靠近用户的OSI层,这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
 
各层中涉及的协议的简单解释:
应用层
  ·DHCP(动态主机分配协议)
  · DNS (域名解析)
  · FTP(File Transfer Protocol)文件传输协议
  · Gopher (英文原义:The Internet Gopher Protocol 中文释义:(RFC-1436)网际Gopher协议)
  · HTTP (Hypertext Transfer Protocol)超文本传输协议
  · IMAP4 (Internet Message Access Protocol 4) 即 Internet信息访问协议的第4版本
  · IRC (Internet Relay Chat )网络聊天协议
  · NNTP (Network News Transport Protocol)RFC-977)网络新闻传输协议
  · XMPP 可扩展消息处理现场协议
  · POP3 (Post Office Protocol 3)即邮局协议的第3个版本
  · SIP 信令控制协议
  · SMTP (Simple Mail Transfer Protocol)即简单邮件传输协议
  · SNMP (Simple Network Management Protocol,简单网络管理协议)
  · SSH (Secure Shell)安全外壳协议
  · TELNET 远程登陆协议
  · RPC (Remote Procedure Call Protocol)(RFC-1831)远程过程调用协议
  · RTCP (RTP Control Protocol)RTP 控制协议
  · RTSP (Real Time Streaming Protocol)实时流传输协议
  · TLS (Transport Layer Security Protocol)安全传输层协议
  · SDP( Session Description Protocol)会话描述协议
  · SOAP (Simple Object Access Protocol)简单对象访问协议
  · GTP 通用数据传输平台
  · STUN (Simple Traversal of UDP over NATs,NAT 的UDP简单穿越)是一种网络协议
  · NTP (Network Time Protocol)网络校时协议
传输层
  ·TCP(Transmission Control Protocol)传输控制协议
  · UDP (User Datagram Protocol)用户数据报协议
  · DCCP (Datagram Congestion Control Protocol)数据报拥塞控制协议
  · SCTP(STREAM CONTROL TRANSMISSION PROTOCOL)流控制传输协议
  · RTP(Real-time Transport Protocol或简写RTP)实时传送协议
  · RSVP (Resource ReSer Vation Protocol)资源预留协议
  · PPTP ( Point to Point Tunneling Protocol)点对点隧道协议
网络层
IP(IPv4 · IPv6) Internet Protocol(网络之间互连的协议)
ARP : Address Resolution Protocol即地址解析协议,实现经过IP地址得知其物理地址。
RARP :Reverse Address Resolution Protocol 反向地址转换协议容许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP 地址。
ICMP :(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
ICMPv6:
IGMP :Internet 组管理协议(IGMP)是因特网协议家族中的一个组播协议,用于IP 主机向任一个直接相邻的路由器报告他们的组成员状况。
RIP : 路由信息协议(RIP)是一种在网关与主机之间交换路由选择信息的标准。
OSPF : (Open Shortest Path First开放式最短路径优先).
BGP :(Border Gateway Protocol )边界网关协议,用来链接Internet上独立系统的路由选择协议
IS-IS:(Intermediate System to Intermediate System Routing Protocol)中间系统到中间系统的路由选择协议.
IPsec:“Internet 协议安全性”是一种开放标准的框架结构,经过使用加密的安全服务以确保在 Internet 协议 (IP) 网络上进行保密而安全的通信。
数据链路层
  802.11 · 802.16 · Wi-Fi · WiMAX · ATM · DTM · 令牌环 · 以太网 · FDDI · 帧中继 · GPRS · EVDO · HSPA · HDLC · PPP · L2TP · ISDN
物理层
  以太网物理层 · 调制解调器 · PLC · SONET/SDH · G.709 · 光导纤维 · 同轴电缆 · 双绞线
 
各层功能及协议的简单解释
 
        tcp\ip五层
            arp协议:经过IP地址找到mac地址
        传输层:TCP\UDP协议    
        tcp
            三次握手
                
            四次挥手
        
    2.tcp和udp的区别
        tcp协议:面向链接,消息可靠,相对udp来说,传输速度慢,消息是面向流的,无消息保护边界
        udp协议:面向无链接,消息不可靠,传输速度快,消息是面向包的,有消息保护边界.
 
 
 
        tcp代码和udp代码的区别看代码
            tcp协议下的socket
            udp协议下的socket
 
 
        
 
    tcp:属于长链接,与一个客户端进行链接了之后,其余的客户端要等待,要链接另一个,必须优雅的断开前面这个客户端的链接.
    
    容许地址重用:在bind IP地址和端口以前加上,# server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)  # 容许(IP地址和端口)地址重用
    
    
    缓冲区
        输入缓冲区  #recv
        输出缓冲区  #send
        
    粘包(tcp的两种粘包现象)
        1 连续发送小的数据,而且每次发送之间的时间间隔很短(输出缓冲区:两个消息在缓冲区黏在一块儿了)
            缘由是TCP为了传输效率,作了一个优化算法(Nagle),减小连续的小包发送(由于每一个消息被包裹之后,都会有两个过程:1 组包 2拆包)
            
        2 第一次服务端发送的数据比我客户端设置的一次接收消息的大小要大,那么接收不完,第二次再接收的时候,就会将第一次剩余的消息接收到
        
        粘包的根本缘由是由于:双方不知道对方发送消息的大小
        
    解决方案一:
        发送消息以前,先计算要发送消息的长度,而后先将消息长度发送过去,对方给你回一个确认收到长度的信息,而后根据接收到的消息长度来修改本身一次接收消息的大小
        这个过程多了一次交互
 
 
 
1.TCP模式下地址及端口如何重用
server:
    import socket
  sk = socket.socket()
  sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字
    sk.listen() #监听连接
    conn,addr = sk.accept() #接受客户端连接
    ret = conn.recv(1024) #接收客户端信息
  print(ret) #打印客户端信息
    conn.send(b'hi') #向客户端发送信息
    conn.close() #关闭客户端套接字
    sk.close() #关闭服务器套接字(可选)
server端

 

client:
    import socket
    sk = socket.socket() # 建立客户套接字
      sk.connect(('127.0.0.1',8898)) # 尝试链接服务器
      sk.send(b'hello!')
    ret = sk.recv(1024) # 对话(发送/接收)print(ret)
    sk.close() # 关闭客户套接字
client端

 

socket绑定IP和端口时可能出现下面的问题:
解决办法:
加入一条socket配置,重用ip和端口
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #在bind前加,容许地址重用
sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字
sk.listen() #监听连接
conn,addr = sk.accept() #接受客户端连接
ret = conn.recv(1024) #接收客户端信息print(ret) #打印客户端信息
conn.send(b'hi') #向客户端发送信息
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
可是若是你加上了上面的代码以后仍是出现这个问题:OSError: [WinError 10013] 以一种访问权限不容许的方式作了一个访问套接字的尝试。那么只能换端口了,由于你的电脑不支持端口重用。
    记住一点,用socket进行通讯,必须是一收一发对应好。
2.TCP长链接
  缘由解释:
    tcp属于长链接,长链接就是一直占用着这个连接,这个链接的端口被占用了,第二个客户端过来链接的时候,他是能够链接的,可是处于一个占线的状态,就只能等着去跟服务端创建链接,除非一个客户端断开了(优雅的断开能够,若是是强制断开就会报错,由于服务端的程序还在第一个循环里面),而后就能够进行和服务端的通讯了。什么是优雅的断开呢?看代码。
server端代码:
 1 import socket
 2 from socket import SOL_SOCKET,SO_REUSEADDR
 3 sk = socket.socket()
 4 sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #容许地址重用,这个东西都说能解决问题,我很是不建议你们这么作,容易出问题
 5 sk.bind(('127.0.0.1',8090))
 6 sk.listen()
 7 # 第二步演示,再加一层while循环while True: #下面的代码所有缩进进去,也就是循环创建链接,可是无论怎么聊,只能和一个聊,也就是另一个优雅的断了以后才能和另一个聊
 8 #它不能同时和好多人聊,仍是长链接的缘由,一直占用着这个端口的链接,udp是能够的,而后咱们学习udp
 9 conn,addr = sk.accept() #在这阻塞,等待客户端过来链接
10 while True:
11 ret = conn.recv(1024) #接收消息 在这仍是要阻塞,等待收消息
12 ret = ret.decode('utf-8') #字节类型转换为字符串中文
13 print(ret)
14 if ret == 'bye': #若是接到的消息为bye,退出
15 break
16 msg = input('服务端>>') #服务端发消息
17 conn.send(msg.encode('utf-8'))
18 if msg == 'bye':
19 break
20 conn.close()
server端

 

client端代码:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8090)) #链接服务端
 
while True:
msg = input('客户端>>>') #input阻塞,等待输入内容
sk.send(msg.encode('utf-8'))
if msg == 'bye':
break
ret = sk.recv(1024)
ret = ret.decode('utf-8')
print(ret)
if ret == 'bye':
break
# sk.close()
client端

 

强制断开链接以后的报错信息:
3.什么是缓冲区
每一个 socket 被建立后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。
 
write()/send() 并不当即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就能够成功返回,无论它们有没有到达目标机器,也无论它们什么时候被发送到网络,这些都是TCP协议负责的事情。
 
TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,屡次写入的数据被一次性发送到网络,这取决于当时的网络状况、当前线程是否空闲等诸多因素,不禁程序员控制。
 
read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。
 
这些I/O缓冲区特性可整理以下:
 
1.I/O缓冲区在每一个TCP套接字中单独存在;
2.I/O缓冲区在建立套接字时自动生成;
3.即便关闭套接字也会继续传送输出缓冲区中遗留的数据;
4.关闭套接字将丢失输入缓冲区中的数据。
 
输入输出缓冲区的默认大小通常都是 8K,能够经过 getsockopt() 函数获取:
 
1.unsigned optVal;
2.int optLen = sizeof(int);
3.getsockopt(servSock, SOL_SOCKET, SO_SNDBUF,(char*)&optVal,&optLen);
4.printf("Buffer length: %d\n", optVal);
 
4.引用subprocess
import subprocess
cmd = input('请输入指令>>>')
res = subprocess.Popen(
cmd, #字符串指令:'dir','ipconfig',等等
shell=True, #使用shell,就至关于使用cmd窗口
stderr=subprocess.PIPE, #标准错误输出,凡是输入错误指令,错误指令输出的报错信息就会被它拿到
stdout=subprocess.PIPE, #标准输出,正确指令的输出结果被它拿到)
print(res.stdout.read().decode('gbk'))
print(res.stderr.read().decode('gbk'))
       注意:
        若是是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端须要用GBK解码
        且只能从管道里读一次结果,PIPE称为管道。
 
下面是subprocess和windows上cmd下的指令的对应示意图:subprocess的stdout.read()和stderr.read(),拿到的结果是bytes类型,因此须要转换为字符串打印出来看。
5.TCP下的两种粘包现象,以及两种解决方式
tcp粘包演示(一):
      先从上面粘包现象中的第一种开始:接收方没有及时接收缓冲区的包,形成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候仍是从缓冲区拿上次遗留的数据,产生粘包)
    server: 
 1 from socket import *
 2  
 3 import subprocess
 4  
 5 ip_port = ('127.0.0.1', 8080)
 6 BUFSIZE = 1024
 7  
 8 tcp_socket_server = socket(AF_INET, SOCK_STREAM)
 9 tcp_socket_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
10 tcp_socket_server.bind(ip_port)
11 tcp_socket_server.listen(5)
12  
13 while True:
14 conn, addr = tcp_socket_server.accept()
15 print('客户端>>>', addr)
16  
17 while True:
18 cmd = conn.recv(BUFSIZE)
19 if len(cmd) == 0: break
20  
21 res = subprocess.Popen(cmd.decode('gbk'), shell=True,
22 stdout=subprocess.PIPE,
23 stdin=subprocess.PIPE,
24 stderr=subprocess.PIPE)
25  
26 stderr = res.stderr.read()
27 stdout = res.stdout.read()
28 conn.send(stderr)
29 conn.send(stdout)
server端

 

    client:
import socket
 
ip_port = ('127.0.0.1', 8080)
size = 1024
tcp_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
res = tcp_sk.connect(ip_port)
while True:
msg = input('>>: ').strip()
if len(msg) == 0: continue
if msg == 'quit': break
 
tcp_sk.send(msg.encode('utf-8'))
act_res = tcp_sk.recv(size)
print('接收的返回结果长度为>', len(act_res))
print('std>>>', act_res.decode('gbk')) # windows返回的内容须要用gbk来解码,由于windows系统的默认编码为gbk
client端

 

 tcp粘包演示(二):
            发送端须要等缓冲区满才发送出去,形成粘包(发送数据时间间隔很短,数据也很小,会合到一块儿,产生粘包)
    server端代码示例:(若是两次发送有必定的时间间隔,那么就不会出现这种粘包状况,试着在两次发送的中间加一个time.sleep(1))
 1 import socket
 2  
 3 server = socket.socket()
 4 server.bind(('127.0.0.1', 8820))
 5 server.listen()
 6 conn, addr = server.accept()
 7 from_client_msg1 = conn.recv(1024).decode("utf-8")
 8 from_client_msg2 = conn.recv(1024).decode('utf-8')
 9  
10 print('msg1:', from_client_msg1)
11 print('msg2:', from_client_msg2)
12 client端:
13 import socket
14  
15 client = socket.socket()
16 client.connect(('127.0.0.1', 8820))
17 client.send('hello'.encode('utf-8'))
18 client.send('sigui'.encode('utf-8'))
19  
20 client.close()
server端代码示例

 

  示例二的结果:所有被第一个recv接收了
TCP会粘包、UDP永远不会粘包
    看下面的解释缘由:
发送端能够是一K一K地发送数据,而接收端的应用程序能够两K两K地提走数据,固然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个总体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,所以TCP协议是面向流的协议,这也是容易出现粘包问题的缘由。而UDP是面向消息的协议,每一个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不一样的。怎样定义消息呢?能够认为对方一次性write/send的数据为一个消息,须要明白的是当对方send一条信息的时候,不管底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈如今内核缓冲区。
 
例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束
 
所谓粘包问题主要仍是由于接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所形成的。
 
此外,发送方引发的粘包是由TCP协议自己形成的,TCP为提升传输效率,发送方每每要收集到足够多的数据后才发送一个TCP段。若连续几回须要send的数据都不多,一般TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。
 
1.TCP(transport control protocol,传输控制协议)是面向链接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,所以,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将屡次间隔较小且数据量小的数据,合并成一个大的数据块,而后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制