python网络编程

本文详细介绍了Python中的网络编程基础知识,包括IP地址与端口概念、TCP与UDP的区别、socket编程(创建、绑定、监听、连接、发送与接收)以及TCP服务器与客户端的实现。涵盖网络通信原理、常见协议及实战案例。
摘要由CSDN通过智能技术生成

python基础知识

python面向对象基础知识

所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信

计算机网络常识

首先介绍一些计算机网络的一些基本常识

ip地址

IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异

生活中的地址指的就是,找到某人或某机关或与其通信的指定地点。在网络编程中,
如果一台主机想和另一台主机进行沟通和共享数据,首先要做的第一件事情就是要找
到对方。在互联网通信中,我们使用IP地址来查询到各个主机。

ip地址的分类

每一个IP地址包括两部分:网络地址和主机地址。IP地址通常由点分十进制(例如:192.168.1.1)的方式来表示,IP地址要和子网掩码(用来区分网络位和主机位)配合使用。
在这里插入图片描述
注意事项:


每一个字节都为0的地址(“0.0.0.0”)对应于当前主机。
IP地址中的每一个字节都为1的IP地址(“255255255255”)
是当前子网的广播地址。
IP地址中凡是以“1111”开头的E类IP地址都保留用于将来和实验使用。
IP地址中不能以十进制“127”作为开头,该类地址中数字127001127255255255用于回路测试,如:127.0.0.1可以代表本机IP地址,
用 http://127.0.0.1 就可以测试本机中配置的Web服务器网络ID的第一
个8位组也不能全置为“0”,全“0”表示本地网络

DOS常用命令:
ipconfig:查看本机IP地址
ping IP地址:检查网络是否连通

特殊IP地址:
127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用

端口

端口号

端口是通过端口号来标记的,端口号只有整数,范围是从0到65535.端口号不是随意使用的,而是按照一定的规定进行分配

知名端口号

知名端口是众所周知的端口号,范围从0到1023,以理解为,一些常用的功能使用的号码是估计的,好比 电话号码110、10086、10010一样。一般情况下,如果一个程序需要使用知名端口的需要有root权限。

动态端口号

动态端口的范围是从1024到65535

之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。

动态分配是指当一个系统程序或应用程序程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。

当这个程序关闭时,同时也就释放了所占用的端口号

常用端口:

mysql:3306
sqlserver:1433
oracle:1521
tomcat:8080
浏览器:80

socket

socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:

它能实现不同主机间的进程间通信
网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用进程(进程)。 这样利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

socket类

python中提供了socket类,该类的常用方法如下

方法名说明
socket()获取socket类对象
socket(AddressFamily, Type)创建指定类型的套接字
bind(hostname,port)在指定主机的端口绑定监听
listen()在绑定端口上开启监听
accept()等待客户端连接,连接后返回客户端地址
send(data)发送数据
recv(buffer)接收数据
close()关闭套接字连接
connect()设置连接的主机名称与端口号
创建socket

在 Python 中 使用socket 模块的函数 socket 就可以完成:

socket()

import socket
socket.socket(AddressFamily, Type)

函数 socket.socket 创建一个 socket,该函数带有两个参数:

Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX
(用于同一台机器进程间通信),实际工作中常用AF_INET

Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者
 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
套接字类型说明
SOCK_STREAM提供顺序、可靠、双向和面向连接的字节流数据传输机制,使用TCP
SOCK_DGRAM支持无连接的数据报,使用UDP
SOCK_RAW原始套接字,可以用于接收本机网卡上的数据帧或者数据包

bind()函数

bind()函数可以将本地地址与一个Socket绑定在一起,函数原型如下:

参数address是一个双元素元组,格式是(host,port)。host代表主机,port代表端口号

socket.bind( address )

listen()函数

listen()函数可以将套接字设置为监听接入连接的状态,函数原型如下:

listen(size);

参数size指定等待连接队列的最大长度

accept()函数

在服务器端调用listen()函数监听接入连接后,可以调用accept()函数来等待接受连接请求。accept()的函数原型如下:

connection, address = socket.accept()

调用accept()方法后,socket会进入waiting状态。客户请求连接时,accept()方法会建立连接并返回服务器。accept()方法返回一个含有两个元素的元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素 address是客户的Internet地址。

send()函数

调用send()函数可以在已连接的Socket上发送数据。send()的函数原型如下:

sock.send(data)

参数sock是在已连接的Socket上发送数据。参数data是也要已连接的Socket上发送数据

recv()函数

调用recv()函数可以从已连接的Socket中接收数据。recv()的函数原型如下:

sock.recv(size)

参数sock是接收数据的socket对象,参数size指定接收数据的缓冲区的大小。recv()的函数的返回接收的数据

close()函数

close ()函数用于关闭一个Socket,释放其所占用的所有资源。socket()的函数原型如下:

socket.closesocket();

socket表示要关闭的Socket

tcp socket

sendto()函数

使用sendto()函数可以实现发送数据的功能,函数原型如下;

s.sendto(data,(addr,port))

参数说明如下:

data,要传输数据。
其中第二个参数是一个元组分别是
addr,接收数据的计算机的IP地址。
port,接收数据的计算机的端口

recvfrom()函数

使用recvfrom ()函数可以实现接收数据的功能,函数原型如下;

data,addr = s.recvfrom( bufsize);

参数说明如下:

bufsize,接收数据的缓冲区的长度,单位为字节。
data,接收数据的缓冲区。
addr,发送数据的客户端的地址

创建一个tcp socket(tcp套接字)

注意udp和tcp接收和发送的函数不一样上面是tcp的函数,接下来是udp的函数

import socket

# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ...这里是使用套接字的功能(省略)...

# 不用的时候,关闭套接字
s.close()

udp socket

创建一个udp socket(udp套接字)

import socket

# 创建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ...这里是使用套接字的功能(省略)...
# 不用的时候,关闭套接字
s.close()

套接字使用流程 与 文件的使用流程很类似

创建套接字
使用套接字收/发数据
关闭套接字

udp

UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议。在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似于生活中,“写信”

由于是一种无连接的处理协议,所以发送的报文可能根据网络环境而出现丢失的情况,但是udp占用的资源少,处理快等特点。

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输

例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议

在这里插入图片描述
udp网络程序-发送数据
创建一个基于udp的网络程序流程很简单,具体步骤如下:

创建客户端套接字
发送/接收数据
关闭套接字
udp发送数据
import socket
#1. 创建一个UDP的socket连接
udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#2. 获取用户输入的内容
msg=input('请输入要发送的内容:')
#3. 准备接收方的地址和端口号
#也可以将地址也成‘localhost’
#两个参数要放到一个元组里面
addr=('localhost',8888)
# 4. 将用户的输入内容进行编码,并发送到指定地址和端口
udp_socket.sendto(msg.encode('utf8'),addr)

udp_socket.close()
udp接收数据
import socket
# 1. 创建一个UDP的socket连接
udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 8888) #  ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)

# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) #  1024表示本次接收的最大字节数
#接收到的对象是一个元组,元组里有两个元素

# 4. 显示接收到的数据
print(recv_data) #(b'dyk666', ('127.0.0.1', 55563))
#元组里的第一个数据显示接收到内容
print(recv_data[0].decode('utf8'))
#元组里的第二个数据显示发送方的地址和端口号
print(recv_data[1][0]) #127.0.0.1
print(recv_data[1][1]) #55563

# 5. 关闭套接字
udp_socket.close()

一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化

一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的

TCP

TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

TCP通信需要经过创建连接、数据传送、终止连接三个步骤。

TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据

TCP特点

面向连接
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。

双方间的数据传输都可以通过这一个连接进行。

完成数据交换后,双方必须断开此连接,以释放系统资源。

这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议

可靠传输

TCP采用发送应答机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功

超时重传

发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。

TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。

错误校验
TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

流量控制和阻塞管理
流量控制用来避免主机发送得过快而使接收方来不及完全收下

TCP与UDP的区别

面向连接(三次握手,四次挥手。)
有序数据传输
重发丢失的数据包
舍弃重复的数据包
无差错的数据传输
阻塞/流量控制

在这里插入图片描述

tcp服务器端

TCP服务端
在程序中,如果想要完成一个tcp服务器的功能,需要的流程如下:

socket创建一个套接字
bind绑定ip和port
listen使套接字变为可以被动链接
accept等待客户端的链接
recv/send接收发送数据
import socket

#创建socket对象,基于internet地址和tcp协议
tcp_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

address=('127.0.0.1',10086)
#绑定到本地的10086端口
tcp_socket.bind(address)

# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
#监听10086端口,等待连接队列最大长度为128
tcp_socket.listen(128)

# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
# client_socket用来为这个客户端服务
# tcp_server_socket就可以省下来专门等待其他新客户端的链接
client_socket,clientaddr=tcp_socket.accept()

# 接收对方发送过来的数据
recive_data=client_socket.recv(1024) #接收1024个字节
print('接收到的数据为:'+recive_data.decode('utf8'))

# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
client_socket.close()

tcp客户端

import socket

#创建socket对象,基于internet地址和tcp协议
tcp_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

tcp_socket.connect(('127.0.0.1',10086))
msg=input('请输入要发送的信息:')
tcp_socket.send(msg.encode('utf8'))

tcp_socket.close()

TCP注意事项

tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器

tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机

tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的

当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信

当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务

listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而
accept返回的新套接字是标记这个新客户端的

关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链
接服务器,但是之前已经链接成功的客户端正常通信

关闭accept返回的套接字意味着这个客户端已经服务完毕

当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为
0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线

tcp文件下载

TCP服务器端:

from socket import *


def get_file_content(file_name):
    try:
        with open(file_name,'rb') as file:
            content=file.read()
            return content
    except:
        print('没有该文件')
# 创建socket
tcp_socket=socket(AF_INET, SOCK_STREAM)
# 绑定本地信息
tcp_socket.bind(('', 10086))
# 将主动套接字变为被动套接字
tcp_socket.listen(128)
while True:
    # 等待客户端的链接
    client_socket,client_addr=tcp_socket.accept()
    recv_data=client_socket.recv(1024)
    file_name=recv_data.decode('utf8')
    print('要下载的文件名称为: {}'.format(file_name))
    # 发送文件的数据给客户端
    # 因为获取打开文件时是以rb方式打开,所以file_content中的数据已经是二进制的格式,因此不需要encode编码
    file_content=get_file_content(file_name)
    if file_content:
        client_socket.send(file_content)
    # 关闭这个套接字
client_socket.close()
tcp_socket.close()

客户端

from socket import *

tcp_socket=socket(AF_INET,SOCK_STREAM)

# 目的信息
server_ip = input("请输入服务器ip:")
server_port = int(input("请输入服务器port:"))
# 链接服务器
tcp_socket.connect((server_ip,server_port))
# 输入需要下载的文件名
file_name = input("请输入要下载的文件名:")
tcp_socket.send(file_name.encode('utf8'))

# 接收对方发送过来的数据,最大接收1024个字节(1K)
recv_data = tcp_socket.recv(1024)
if recv_data:
        with open("[接收]"+file_name, "wb") as f:
            f.write(recv_data)

# 关闭套接字
tcp_socket.close()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值