python网络编程

        网络编程指的是:在程序中实现两台计算机之间的通信。 Python提供了大量的内置模块和第三方模块用于支持各种网络访问,而且Python语言在网络通信方面的优点特别突出,远远领先其他语言。

目录

一,网络编程基本概念

1,什么是IP地址?

2,IP地址的分类

2.1 公有地址

2.2 私有地址

3,本地服务器IP地址

4,Windows下常用的ip命令

5,什么是子网?子网掩码?

6,什么是网关?

7,什么是交换机?

8,什么是路由器?

9,什么是路由?

10,子网下的设备如何访问互联网?

11,什么是端口?

11.1 端口分配

11.2 公认端口(Well Known Ports):

11.3 注册端口(Registered Ports):

二,网络通信协议

1,一张神图

2,OSI网络协议七层模型

3,TCP/IP协议模型

4,TCP和UDP的区别?

4.1 TCP

4.2 UDP

4.3 TCP和UDP区别

5,TCP建立链接的三次握手

6,TCP断开连接的四次挥手

7,数据包与处理流程

7.1 什么是数据包?

7.2 数据包处理流程

三,socket套接字编程

1,什么是套接字编程?

2,socket()函数介绍

3,socket对象的方法一览

4,UDP编程实例

4.1 单工最简案例

4.2 单工持续通信

4.3 双工持续通信

5,TCP/IP编程实例

5.1 TCP/IP编程简介

5.2 TCP编程的实现过程

5.3 TCP单工通信服务端

5.4 TCP单工通信客户端

5.5 TCP单工持续通信服务端

5.6 TCP单工持续通信客户端

5.7 TCP双工持续通信服务端

5.8 TCP双工持续通信客户端


一,网络编程基本概念

1,什么是IP地址?

        IP是Internet Protocol Address,即"互联网协议地址"。互联网之间的通信相当于快递收发,需要知道每个电脑的详细地址才能实现数据的准确收发。

        IP地址用来标识网络中的一个通信实体的地址。通信实体可以是计算机、 路由器等

        IP地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读。

2,IP地址的分类

2.1 公有地址

        公有地址(Public address)

Inter NIC

Internet Network Information Center互联网信息中心)负责。这些
IP
地址分配给注册并向Inter NIC
提出申请的组织机构。通过它直接访问互联网。

2.2 私有地址

        私有地址(Private address
)属于非注册地址,专门为组织机构内部使用。

3,本地服务器IP地址

        127.0.0.1本机地址。192.168.0.0–192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。

4,Windows下常用的ip命令

        windows下,我们可以通过命令 ipconfig 获取网卡信息。(Linux 和Mac,是 ifconfig ),通过 ping 查看网络连接:

        1,ping www.baidu.com 查看是否能上公网

        2,ping 192.168.1.100 查看是否和该计算机在同一个局域网

        3,ping 127.0.0.1 查看本机网卡是否可用

5,什么是子网?子网掩码?

        子网就是一个网中一个比较低级的网。子网掩码用来确定一个子网中的IP地址及数量,一个子网节点IP地址与子网掩码相与运算得到该子网下的IP地址。一般的子网掩码为255.255.255.0。通过子网掩码确定两个IP地址是否属于同一个子网。

6,什么是网关?

        网络关卡口的简称。他的作用就是:链接两个不同的网络,比如联通公司给你家装了宽带(相当于给你家装了一个网关),你家里的所有设备都是在一个局域子网中,这个局域网和互联网之间使用网关进行连接。

7,什么是交换机?

        交换机的作用就是分发数据,为设备提供IP地址。交换机直接与设备的网卡连接,数据通过指定的端口发送到指定的设备上,交换机只关心与其联系的设备的mac地址。

8,什么是路由器?

        路由器具备WAN口和多个LAN口。它实际上是网关和交换机的结合体。wan口与宽带公司机房相连,LAN口与局域网设备相连。

9,什么是路由?

        数据从一台电脑发送到另一台电脑的时所走过的路线就叫做路由。

10,子网下的设备如何访问互联网?

        通过网关设备里面的NAT技术,即网络地址转换技术。

11,什么是端口?

        同一台设备下有很多的应用程序,但是网卡只有一个,数据通过网卡获得和发送,如何确定接收的数据到底是哪一个程序的呢?发给QQ的数据不可能被微信接收。利用端口可以解决这个问题。

11.1 端口分配

        端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 端口的表示是一个16位的二进制整数,对应十进制的
0-65535
。 操作系统中一共提供了0~65535
可用端口范围。 按端口号分类:

11.2 公认端口(Well Known Ports):

        
0

1023
,它们紧密绑定(binding
)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80
端口实际上总是
HTTP
通讯。

11.3 注册端口(Registered Ports):

        从1024

65535
。它们松散地绑 定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同用于许多其它目的。例如:许多系统处理动态端口从1024
左右开始。 

二,网络通信协议

1,一张神图

2,OSI网络协议七层模型

        OSI模型制定的七层标准模型,分别是:应用层, 表示层,会话层,传输层,网络层,数据链路层,物理层。

3,TCP/IP协议模型

        虽然国际标准化组织制定了这样一个网络通信协议的模型,但是实际上互联网通讯使用最多的网络通信协议是TCP/IP
网络通信协议。 TCP/IP 是一个协议族,也是按照层次划分,共四层:应用层,传输层,互连网络层,网络接口层(物理+
数据链路层)。

        与OSI模型的区别如下:

4,TCP和UDP的区别?

        TCP 和
UDP
的优缺点无法简单地、绝对地去做比较:
TCP
用于在传输层有必要实现可靠传输的情况;UDP
主要用于那些对高速传输 和实时性有较高要求的通信或广播通信。TCP

UDP
应该根据应用的目的按需使用。主要在于他们传输数据的形式不同。

4.1 TCP

        TCP(
Transmission Control Protocol
,传输控制协议)。
TCP
方 式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。

4.2 UDP

        UDP(User Data Protocol
,用户数据报协议),UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。 在发送端,UDP
传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制; 在接收端, UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

        UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需 要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户 端无法获得。UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络 条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网 络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP
而不是
TCP

4.3 TCP和UDP区别

        这两种传输方式都在实际的网络编程中使用,重要的数据一般使用 TCP方式进行数据传输,而大量的非核心数据则可以通过
UDP
方式 进行传递,在一些程序中甚至结合使用这两种方式进行数据传递。 由于TCP
需要建立专用的虚拟连接以及确认传输是否正确,所以使 用TCP
方式的速度稍微慢一些,而且传输时产生的数据量要比
UDP稍微大一些。

5,TCP建立链接的三次握手

        TCP是面向连接的协议,也就是说,在收发数据前,必须和对方建 立可靠的连接。 一个TCP
连接必须要经过三次

对话

才能建立起 来,其中的过程非常复杂,只简单的描述下这三次对话的简单过程:

        1)主机
A
向主机
B
发出连接请求:

我想给你发数据,可以吗?

,这是第一次对话;

        2)主机
B
向主机
A
发送同意连接和要求同步 (同步就是两台主机一个在发送,一个在接收,协调工作)的数据包 :“
可以,你什么时候发?”
,这是第二次对话;

        3)主机
A
再发出一个数据包确认主机
B
的要求同步:

我现在就发, 你接着吧!”
, 这是第三次握手。

        三次“
对话

的目的是使数据包的发送和接收同步, 经过三次

对话
” 之后,主机A
才向主机
B
正式发送数据。

        三次握手建立TCP连接时的状态。

        第一步,客户端发送一个包含SYN
即同步(
Synchronize
)标志的
TCP
报文,
SYN
同步报文会指明客户端使用的端口以及TCP
连接的初始序号。

        第二步,服务器在收到客户端的SYN
报文后,将返回一个
SYN+ACK
的报文,表示客户端的请求被接受,同时TCP
序号被加一,
ACK
即确认(
Acknowledgement

        第三步,客户端也返回一个确认报文ACK
给服务器端,同样
TCP
序列号被加一,到此一个
TCP
连接完成。然后才开始通信的第二步:数据处理。

6,TCP断开连接的四次挥手

        第一次: 当主机A完成数据传输后,将控制位FIN1,提出停止TCP 连接的请求 ;

        第二次: 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,ACK1

        第三次: 由B 端再提出反方向的关闭请求,

FIN

1

        第四次: 主机A对主机B
的请求进行确认,将
ACK

1
,双方向的关闭结束

        由TCP的三次握手和四次断开可以看出,TCP
使用面向连接的通信方 式, 大大提高了数据通信的可靠性,使发送数据端和接收端在数据 正式传输前就有了交互, 为数据正式传输打下了可靠的基础。

7,数据包与处理流程

7.1 什么是数据包?

        通信传输中的数据单位,一般也称“
数据包

。在数据包中包括: 包、帧、数据包、段、消息。
网络中传输的数据包由两部分组成:一部分是协议所要用到的首 部,另一部分是上一层传过来的数据。首部的结构由协议的具体规 范详细定义。在数据包的首部,明确标明了协议应该如何读取数 据。反过来说,看到首部,也就能够了解该协议必要的信息以及所 要处理的数据。包首部就像协议的脸。

7.2 数据包处理流程

        详细流程如下图。

 

三,socket套接字编程

1,什么是套接字编程?

        TCP协议和
UDP
协议是传输层的两种协议。
Socket
是传输层供给应用层的编程接口,所以Socket
编程就分为
TCP
编程和
UDP
编程两类。

 

        Socket编程封装了常见的TCPUDP操作,可以实现非常方便的网络编程。

2,socket()函数介绍

        在Python语言标准库中,通过使用socket模块提供的socket对象,可以在计算机网络中建立可以互相通信的服务器与客户端。在服务器端需要建立一个socket对象,并等待客户端的连接。客户端使用socket对象与服务器端进行连接,一旦连接成功,客户端和服务器端就可以进行通信了。

        注意:我们可以看出socket通讯中,发送和接收数据,都 是通过操作系统控制网卡来进行。因此,我们在使用之后,必须关闭socket

        socket语法格式如下:socket.socket([family[, type[, proto]]])

        family的参数值有:AF_UNIX 或者 AF_INET AF 表示ADDRESS FAMILY 地址族,AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型;而AF_UNIX 则是 Unix 系统本地通信。

        type的参数值有:type : 套接字类型可以根据是面向连接的还是非连接分为 SOCK_STREAM SOCK_DGRAM

        protocol : 一般不填,默认为0

         Socket主要分为面向连接的Socket和无连接的Socket。 无连接Socket的主要协议是用户数据报协议,也就是常说的UDP, UDP Socket的名字是 SOCK_DGRAM 。创建套接字UDP/IP套接字,可以 调用 socket.socket() 。示例代码如下: udpSocket=socket.socket(AF_INET,SOCK_DGRAM)

3,socket对象的方法一览

4,UDP编程实例

4.1 单工最简案例

        UDP协议时,不需要建立连接,只需要知道对方的
IP
地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。虽然用UDP传输数据不可靠,但它的优点是和
TCP
比,速度快,对于不要 求可靠到达的数据,就可以使用UDP
协议。 创建Socket
时,
SOCK_DGRAM
指定了这个
Socket
的类型是
UDP
。绑定 端口和TCP
一样,但是不需要调用
listen()
方法,而是直接接收来自任何客户端的数据。
recvfrom()
方法返回数据和客户端的地址与端口,这样,服务器收到数据后,直接调用
sendto()
就可以把数据用
UDP
发给客户端。

        udp服务端:

from socket import *

# 最简化的UDP服务端代码
s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字对象
s.bind(("127.0.0.1", 8888))  # 绑定端口,ip可以不写
print("等待接收数据!")
recv_data = s.recvfrom(1024)  # 1024表示本次接收的最大字节数
print(f"收到远程信息:{recv_data[0].decode('gbk')},from {recv_data[1]}")

s.close()

        udp客户端:

from socket import *

# 最简化的UDP客户端发送消息代码
s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
server_addr = ("127.0.0.1", 8888)
data = input("请输入:")
s.sendto(data.encode("gbk"), server_addr)
s.close()

4.2 单工持续通信

        udp服务端:

from socket import *

# 持续通信
s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
s.bind(("127.0.0.1", 8888))  # 绑定端口,ip可以不写
print("等待接收数据!")
while True:
    recv_data = s.recvfrom(1024)  # 1024表示本次接收的最大字节数,recvfrom一直监听知道由数据被接受
    recv_content = recv_data[0].decode('gbk')
    print(f"收到远程信息:{recv_content},from {recv_data[1]}")
    if recv_content == "exit":
        print("结束聊天!")
        break

s.close()

        udp客户端:

from socket import *

# UDP客户端持续发送消息代码
s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
addr = ("127.0.0.1", 8888)

while True:
    data = input("请输入:")
    s.sendto(data.encode("gbk"), addr)
    if data == "exit":
        print("结束聊天!")
        break

s.close()

4.3 双工持续通信

        使用本地主机,开启两个接收和发送两个线程,实现双工通信。

        udp服务端:

from socket import *
from threading import Thread


def recv_data():
    while True:
        recv_data = s.recvfrom(1024)  # 1024表示本次接收的最大字节数
        recv_content = recv_data[0].decode('gbk')
        print(f"收到远程信息:{recv_content},from {recv_data[1]}")
        if recv_content == "exit":
            print("结束聊天!")
            break


def send_data():
    addr = ("127.0.0.1", 9999)
    while True:
        data = input("请输入:")
        s.sendto(data.encode("gbk"), addr)
        if data == "exit":
            print("结束聊天!")
            break


if __name__ == '__main__':
    s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
    s.bind(("127.0.0.1", 8888))  # 绑定端口,ip可以不写
    # 创建两个线程
    t1 = Thread(target=recv_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

        udp客户端:

from socket import *
from threading import Thread


def recv_data():
    while True:
        recv_data = s.recvfrom(1024)  # 1024表示本次接收的最大字节数
        recv_content = recv_data[0].decode('gbk')
        print(f"收到远程信息:{recv_content},from {recv_data[1]}")
        if recv_content == "exit":
            print("结束聊天!")
            break


def send_data():
    addr = ("127.0.0.1", 8888)
    while True:
        data = input("请输入:")
        s.sendto(data.encode("gbk"), addr)
        if data == "exit":
            print("结束聊天!")
            break


if __name__ == '__main__':
    s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
    s.bind(("127.0.0.1", 9999))  # 绑定端口,ip可以不写
    # 创建两个线程
    t1 = Thread(target=recv_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

5,TCP/IP编程实例

5.1 TCP/IP编程简介

        面向连接的Socket使用的协议是TCP协议。TCPSocket名称是SOCK_STREAM 。创建套接字TCP套接字,可以调用 socket.socket() 。示例代码如下:

 tcpSocket=socket.socket(AF_INET,SOCK_STREAM)

5.2 TCP编程的实现过程

        在Python
语言中创建
Socket
服务端程序,需要使用
socket
模块中的socket类。创建
Socket
服务器程序的步骤如下:

        (1) 创建
Socket
对象。

        (2) 绑定端口号。

        (3) 监听端口号。

        (4) 等待客户端Socket
的连接。

        (5) 读取客户端发送过来的数据。

        (6) 向客户端发送数据。

        (7) 关闭客户端Socket
连接。

        (8) 关闭服务端Socket
连接。

5.3 TCP单工通信服务端

from socket import *

server_socket = socket(AF_INET,SOCK_STREAM) #建立TCP套接字
server_socket.bind(("127.0.0.1",8899))  #本机监听8899端口
server_socket.listen(5)
print("等待接收连接!")
client_socket,client_info = server_socket.accept()
recv_data = client_socket.recv(1024)  #最大接收1024字节
print(f"收到信息:{recv_data.decode('gbk')},来自:{client_info}")

client_socket.close()
server_socket.close()

5.4 TCP单工通信客户端

from socket import *

client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(("127.0.0.1",8899))

client_socket.send("hello".encode("gbk"))
client_socket.close()
#注意:
# 1. tcp客户端已经链接好了服务器,所以在以后的数据发送中,不需要填写对方的ip和port----->打电话
# 2. udp在发送数据的时候,因为没有之前的链接,所以需要在每次的发送中,都要填写接收方的ip和port--->写信

5.5 TCP单工持续通信服务端

from socket import *

server_socket = socket(AF_INET,SOCK_STREAM) #建立TCP套接字
server_socket.bind(("127.0.0.1",8899))  #本机监听8899端口
server_socket.listen(5)
print("等待接收连接!")
client_socket,client_info = server_socket.accept()
print("一个客户端建立连接成功!")
while True:
    recv_data = client_socket.recv(1024)  #最大接收1024字节
    recv_content = recv_data.decode('gbk')
    print(f"客户端说:{recv_content},来自:{client_info}")
    if recv_content == "end":
        break
    msg = input(">")
    client_socket.send(msg.encode("gbk"))

client_socket.close()
server_socket.close()

5.6 TCP单工持续通信客户端

from socket import *

client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(("127.0.0.1",8899))
while True:
    #给服务端发消息
    msg = input(">")
    client_socket.send(msg.encode("gbk"))
    if msg =="end":
        break
    #接收服务器端数据
    recv_data = client_socket.recv(1024) #最大接收1024字节
    print(f"服务器端说:{recv_data.decode('gbk')}")

client_socket.close()

5.7 TCP双工持续通信服务端

from socket import *
from threading import Thread


def recv_data():
    while True:
        recv_data = client_socket.recv(1024)  # 最大接收1024字节
        recv_content = recv_data.decode("gbk")
        print(f"客户端说:{recv_content},来自:{client_info}")
        if recv_content == "end":
            print("结束接收消息!")
            break

def send_data():
    while True:
        msg = input(">")
        client_socket.send(msg.encode("gbk"))
        if msg == "end":
            print("结束发送消息!")
            break

if __name__ == '__main__':
    server_socket = socket(AF_INET, SOCK_STREAM)  # 建立TCP套接字
    server_socket.bind(("127.0.0.1", 8899))  # 本机监听8899端口
    server_socket.listen(5)
    print("等待接收连接!")
    client_socket, client_info = server_socket.accept()
    print("一个客户端建立连接成功!")

    t1 = Thread(target=recv_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()

    t1.join()
    t2.join()

    client_socket.close()
    server_socket.close()

5.8 TCP双工持续通信客户端

from socket import *
from threading import Thread


def recv_data():
    while True:
        # 接收服务器端数据
        recv_data = client_socket.recv(1024)  # 最大接收1024字节
        recv_content = recv_data.decode('gbk')
        print(f"服务器端说:{recv_content}")
        if recv_content == "end":
            print("结束接收消息")
            break

def send_data():
    while True:
        # 给服务端发消息
        msg = input(">")
        client_socket.send(msg.encode("gbk"))
        if msg == "end":
            break

if __name__ == '__main__':
    client_socket = socket(AF_INET, SOCK_STREAM)
    client_socket.connect(("127.0.0.1", 8899))

    t1 = Thread(target=recv_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    client_socket.close()

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注