网络编程

Posted 一种清孤不等闲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程相关的知识,希望对你有一定的参考价值。

一,软件开发的架构

两个程序之间的通讯的应用大致可以分为两种:

第一种:应用类,需要安装的桌面应用

第二种:web类,使用浏览器访问就可以直接使用的应用

应用的本质就是两个程序之间的通讯。

1,C/S架构

C(Client)/S(Server)即:客户端与服务端架构。客户端一把泛指客户端应用程序exe,程序需要先安装,才能运行对操作系统环境依赖较大。

2,B/S架构

B(Browser)/S(Server)即:浏览器端和服务器端架构,其实也是一种客户端。只需在浏览器上过请求HTTP请求服务端相关的资源。

解耦分治的思想:统一入口

二,网络基础

1,IP地址和IP协议:规定网络地址的协议叫IP协议,它定义的地址称为IP地址,采用V4版本即ipv4,规定网络地址由32位2进制表示。IP地址是一台机器在网络上的位置。

范围:0.0.0.0---255.255.255.255,一个IP地址通常写成四段十进制数:例172.16.10.1

本地的回环地址:127.0.0.1

总结一下,IP协议的作用主要有两个,一个是为每一台计算机分配IP地址,另一个是确定哪些地址在同一个子网络。

 

2,mac地址

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

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

3,arp协议:查询IP地址与mac地址的对应关系

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。
  主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址。
  收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。

4,路由器

路由器(Router),是连接因特网中各局域网、广域网的设备,它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号。
路由器(Router)又称网关设备(Gateway)是用于连接多个逻辑上分开的网络,所谓逻辑网络是代表一个单独的网络或者一个子网。当数据从一个子网传输到另一个子网时,可通过路由器的路由功能来完成。
路由器只接受源站或其他路由器的信息,属网络层的一种互联设备。  

5,局域网

局域网:是指某一区域内多台计算机互联成的计算机组。 局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。 

6,子网掩码

子网掩码:所谓子网掩码,就是表示网络特征的一个参数。它形式上等同于ip地址,是一个32位二进制数字,网络部分全为1,主机部分全为0

就是将某个IP地址划分分成网络地址和主机地址两部分。
技术分享图片
比如,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?两者与子网掩码分别进行AND运算,

172.16.10.1:10101100.00010000.00001010.000000001
255255.255.255.0:11111111.11111111.11111111.00000000
AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0

 

172.16.10.2:10101100.00010000.00001010.000000010
255255.255.255.0:11111111.11111111.11111111.00000000
AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
结果都是172.16.10.0,因此它们在同一个子网络。

7,tcp协议和udp协议

端口:

端口,在计算机上每一个需要需要网络通信的程序都会开一个端口
 在同一时间只会有一个程序占用一个端口,不可能在同一机器上,同一时间 有两个程序占用同一个端口
端口范围:0-65535
一般情况下用8000之后的端口
ip,确定唯一一台机器;端口:确定唯一的程序
ip+端口:找到唯一的一台机器上的唯一一个程序

TCP协议:

tcp协议:当应用程序通过tcp与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“握手之后,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的半关闭(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。[1] 
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
注意:
(1) “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。[2] 
(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。
(3) 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。
无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。[2] 
终止连接:四次挥手

udp协议:

 当应用程序希望通过UDP与一个应用程序通信时,传输数据之前源端和终端不建立连接。

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

udp与tcp的对比:

tcp,传输控制协议,提供的面向连接、可靠的字节流服务,双方建立tcp连接之后,才能传输数据。

tcp提供超时重发,丢弃重复数据,可靠的,效率低。

udp,用户数据报协议,是一种无连接的协议,一个简单的面向数据报的运输层协议。不可靠,只是把数据传出去,并不能保证能到达目的地。传输数据报前不用建立连接,没超时重发等机制,孤传输速度很快。

技术分享图片
TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。
tcp协议和udp协议

 

8,互联网协议与osi模型

互联网协议按照功能不同分为osi七层/tcp/ip五层或tcp/ip四层

应用层

传输层          tcp与udp协议

网络层          IP协议

数据链路层   arp协议

物理层

三,socket(套接字)

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

socket有两种,分别是基于文件型的和基于网络型的。

2,socket(类似于模块)的使用

(1),基于tcp协议的socket(tcp是基于链接的,必须先动服务器,然后再启动客户端取链接服务端)

技术分享图片
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(bhi)        #向客户端发送信息
conn.close()       #关闭客户端套接字
sk.close()        #关闭服务器套接字(可选)
server端
技术分享图片
import socket
sk = socket.socket()           # 创建客户套接字
sk.connect((127.0.0.1,8898))    # 尝试连接服务器
sk.send(bhello!)
ret = sk.recv(1024)         # 对话(发送/接收)
print(ret)
sk.close()            # 关闭客户套接字
client端

(1.1)多个客户端链接服务端(同一时间只能连一个,等一个断开才能接收到另一个客户端。)

技术分享图片
import socket
#tcp协议
sk = socket.socket()     # 买手机 创建一个socket对象
sk.bind((127.0.0.1,8080))  # 给server端绑定一个ip和端口
sk.listen()              # py3.4
while True:
    conn,addr = sk.accept()  # 获取到一个客户端的连接, 已经完成了三次握手建立了一个连接
                             # 阻塞
    while True:
        msg = conn.recv(1024).decode(utf-8)    # 阻塞,直到收到一个客户端发来的消息
        print(msg)
        if msg == bye:break
        info = input(>>>)
        if info == bye:
            conn.send(bbye)
            break
        conn.send(info.encode(utf-8))     # 发消息
    conn.close()             # 关闭连接
sk.close()               # 关闭socket对象,如果不关闭,还能继续接收
# server client1 建立了长连接
# client2
server端
技术分享图片
import socket
sk = socket.socket()
sk.connect((127.0.0.1,8080))
while True:
    msg = input(>>>)
    if msg == bye:
        sk.send(bbye)
        break
    sk.send(msg.encode(utf-8))
    ret = sk.recv(1024).decode(utf-8)
    if ret == bye:break
    print(ret)
sk.close()
client1端
技术分享图片
import socket
sk = socket.socket()
sk.connect((127.0.0.1,8080))
while True:
    msg = input(client2:>>>)
    if msg == bye:
        sk.send(bbye)
        break
    sk.send((client2 :+msg).encode(utf-8))
    ret = sk.recv(1024).decode(utf-8)
    if ret == bye:break
    print(ret)
sk.close()
client2

(2)基于udp协议的socket(udp是无链接的,先启动哪一端都不会报错)

技术分享图片
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind((127.0.0.1,8090))

msg,addr=sk.recvfrom(1024)
print(msg.decode(utf-8))

sk.sendto(bbye,addr)
sk.close()
server端
技术分享图片
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
ip_port=((127.0.0.1,8090))

sk.sendto(bhi,ip_port)
ret,addr=sk.recvfrom(1024)

print(ret.decode(utf-8))
sk.close()
client端

简单聊天程序:

技术分享图片
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind((127.0.0.1,8090))
while  True:                                               #仅服务端有
    msg,addr=sk.recvfrom(1024)
    print(msg.decode(utf-8))
    if msg.decode(utf-8) == bye:
        break
    info = input(>>>>)
    if info==bye:
        sk.sendto(bbye, addr)
        break
    sk.sendto(info.encode(utf-8),addr)
sk.close()
server端
技术分享图片
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
ip_port=(127.0.0.1,8090)
while True:
    info=input(<<<)
    if info==bye:
        sk.sendto(bbye,ip_port)
        break
    sk.sendto(info.encode(utf-8),ip_port)

    ret,addr=sk.recvfrom(1024)
    if ret.decode(utf-8) == bye: break
    print(ret.decode(utf-8))

sk.close()
client端
技术分享图片
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
ip_port=(127.0.0.1,8090)
while True:
    info=input(<<<)
    if info==bye:
        sk.sendto(bbye,ip_port)
        break
    sk.sendto((第三个:+info).encode(utf-8),ip_port)
    ret,addr=sk.recvfrom(1024)
    if ret.decode(utf-8) == bye: break
    print(ret.decode(utf-8))

sk.close()
client端

 

时间服务器:

技术分享图片
import time
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind((127.0.0.1,8090))
msg,addr=sk.recvfrom(1024)
time_1=msg.decode(utf-8)
time.strftime(time_1)

sk.sendto((time.strftime(time_1)).encode(utf-8),addr)
sk.close()
server端
技术分享图片
import logging
import socket
logging.basicConfig(level=logging.DEBUG,
                    format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s,
                    datefmt=%a, %d %b %Y %H:%M:%S,
                    filename=test.log,
                    filemode=a)

sk=socket.socket(type=socket.SOCK_DGRAM)
ip_port=(127.0.0.1,8090)
sk.sendto((%Y-%m-%d %X).encode(utf-8),ip_port)
ret,addr=sk.recvfrom(1024)
print(ret.decode(utf-8))
logging.info(ret.decode(utf-8))

sk.close()
client端

 





以上是关于网络编程的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

使用 Pygments 检测代码片段的编程语言

面向面试编程代码片段之GC

如何在 Django Summernote 中显示编程片段的代码块?