25.Python 网络编程:TCP和UDP编程

简介: 25.Python 网络编程:TCP和UDP编程

1.TCP编程

IP(Internet protocol,互联网协议)属于网络层协议,为主机提供一种无连接、不可靠、尽力而为的数据报传输服务。IP 协议负责把数据从一台计算机通过网络发送到另一台计算机。互联网链路复杂,两台计算机之间存在多条线路,因此,路由器就负责决定如何转送一个IP包。IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证按顺序到达。


TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、安全可靠的、基于字节流的传输层协议。IP 层仅能够提供不可靠的包交换,TCP 协议通过3次握手在两台计算机之间建立稳定的连接,然后对每个IP包编号,确保对方按顺序接收,如果包丢失,就会自动重发,最后再通过4次挥手结束连接。当然,这种反复确认的过程,会影响传输效率。


很多高级的协议都是建立在TCP协议基础上的,如浏览器的HTTP协议、发送邮件的SMTP协议、文件传输的FTP协议。

TCP客户端

创建TCP连接时,主动发起连接的一方叫客户端,被动响应连接的一方叫服务器。开发TCP服务可以按如下步骤实现。

  1. 使用socket()创建一个套接字对象。该行为类似购买手机。
  2. 调用bind()方法绑定服务器的IP和端口号。该行为类似绑定手机卡。
  3. 调用listen()方法为套接字对象建立被动连接,监听客户请求。该行为类似待机状态。
  4. 使用accept()方法等待客户端的连接。该行为类似来电显示,接通电话。
  5. 使用recv()或send()方法接收或发送数据。该行为类似通话中的听和说。
  6. 调用close()方法关闭连接。该行为类似挂断电话。

示例1:设计一个请求/响应的TCP连接,由服务器向客户端发送问候语:Hello World,使用网页浏览器接收问候信息,并显示在页面中。

import socket
s = socket.socket() # 创建socket对象
s.bind(('127.0.0.1',12345)) # 绑定端口
s.listen(5) # 等待客户端连接
print('服务器处于监听状态中...')
while True:
    c,a = s.accept() # 建立客户端连接
    data = c.recv(1024).decode() # 获取客户端请求数据
    print(data) # 打印数据
    head = 'HTTP/1.1 200 OK\r\n\r\n' 
    body = '<html><head><title>客户端请求</title></head><body><meta charset="utf-8"><h1>Hello World</h1></body></html>'
    html = head + body
    c.sendall(html.encode()) # 向客户端发送数据
    c.close() # 关闭连接
# 执行该程序,打开浏览器输入127.0.0.1:12345,并可查看。

在发生客户端的字符串中,需要添加’HTTP/1.1 200 OK\r\n\r\n’前缀,设置HTTP头部消息。

示例2:创建一个基于TCP的客户端socket对象,并向百度的Web服务器请求网页信息。

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建一个socket对象
s.connect(('www.baidu.com.cn',80)) # 建立连接
s.send(b'GET / HTTP/1.1\r\n\r\n\r\n') # 发送数据,需要以二进制字节流形式
l = [] # 临时列表,初始为空
while True:
    d = s.recv(1024) # 每次最多接收1kb
    if d: # 如果接收到数据
        l.append(d) # 把数据推入列表中
    else:
        break # 接收完毕,跳出循环
data = b''.join(l) # 把接收的所有数据连接为一个字符串
s.close() # 关闭连接
header,html = data.split(b'\r\n\r\n',1) # 分隔HTTP头和网页内容
print(header.decode('utf-8')) # 打印解码后信息
with open('baidu.html','wb') as f: # 把接入的数据写入文件中
    f.write(html)
# 将生成的baidu.html文件使用浏览器打开,就可以看到百度的首页。

TCP服务器

创建TCP服务器时,首先要绑定一个服务器端口,然后开始监听该端口,如果接收到客户端的请求,服务器就与客户端建立socket连接,接下来通过这个socket连接与其进行通信。

每建立一个客户端连接,服务器都创建一个socket连接。由于服务器有大量来自不同的客户端的请求,所以,服务器要区分每一个socket连接分别属于哪个客户端。


如果希望服务器并发处理多个客户端的请求,那么就需要用到多进程或多线程技术,否则,在同一个时间内,服务器一次只能服务一个客户端。

示例3:设计一个简单的客户端与服务器无限聊天。客户端和服务器建立连接之后,客户端可以向服务器发送请求文字,服务器可以响应。

# 新建server3.py,输入以下命令,作为服务器端响应文件
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建TCP/IP套接字
s.bind((socket.gethostname(),8888)) # 绑定地址到套接字
s.listen(5) # 设置多连接数量
print('服务器处于监听状态中...\r\n')
c,a = s.accept() # 被动接收TCP客户端连接
print('已连接到客户端')
print('**提示,如果要退出,请输入esc后回车.\r\n')
d = c.recv(1024).decode()  # 接收客户端数据
while d != 'esc': # 判断是否退出
    if d:
        print('客户端说:'+d)
    send_data = input('服务器说:') # 发送消息
    c.send(send_data.encode()) # 发送TCP数据
    if send_data == 'esc': # 如果发送exit,则退出
        break
    d = c.recv(1024).decode() # 接收客户端数据
c.close()  # 关闭客户端套接字
s.close()  # 关闭服务器端套接字
# 新建client3.py,输入以下命令,作为客户端请求文件
import socket
s = socket.socket() # 创建套接字
s.connect((socket.gethostname(),8888)) # 连接TCP服务器
print('已连接到服务器.')
print('**提示,如果要退出,请输入esc后回车.\r\n')
d = ''
while d != 'esc': # 判断是否退出
    send_data = input('客户端说:') # 输入内容
    s.send(send_data.encode()) # 发送TCP数据
    if send_data == 'esc': # 如果发送exit,则退出
        break
    d = s.recv(1024).decode() # 接收服务器数据
    print('服务器说:'+d)
s.close() # 关闭套接字
# 分别执行两个文件,并可实现终端客户的和服务器进行聊天

示例4:设计服务器程序,用来接收客户端请求,把客户端发过来的字符串加上Hello前缀,再转发回去进行响应。

# 新建server4.py,输入以下命令,作为服务器端响应文件
import socket
import time
import threading
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建TCP/IP套接字
s.bind(('127.0.0.1',9999)) # 绑定地址到套接字
s.listen(5) # 设置多连接数量
print('Waiting for connection...')
def tcplink(c,a): # TCP 连接函数
    print('Accept new connection from %s:%s...'%(c,a))
    c.send(b'Welcome!') # 发送问候消息
    while True:
        d = c.recv(1024) # 接收消息
        time.sleep(1) # 睡眠1s
        if not d or d.decode('utf-8') == 'exit':
            break
        c.send(('Hello,%s!'% d.decode('utf-8')).encode('utf-8')) # 响应消息
    c.close() # 关闭连接
    print('Connection from %s:%s closed'%(c,a))
while True:
    c,a = s.accept() # 接收一个新连接
    t = threading.Thread(target=tcplink,args=(c,a))
    t.start() # 开启线程
# 新建client4.py,输入以下命令,作为客户端请求文件
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建套接字
s.connect(('127.0.0.1',9999)) # 连接TCP服务器
print(s.recv(1024).decode('utf-8')) # 接收欢迎消息
for d in [b'Michael',b'Tracy',b'Sarah']: # 循环请求,批量发送多个消息
    s.send(d) # 发送数据
    print(s.recv(1024).decode('utf-8')) # 打印接收信息
s.send(b'exit') # 发送结束命令
s.close() # 关闭连接
# 分别执行两个文件,并可实现客户端和服务器之间通信

2.UDP编程

UDP(user datagram protocol,用户数据协议)是一种无连接的通信协议,与TCP同属传输层协议,两者比较如下:

  • TCP是面向连接的传输控制协议,UDP是无连接的数据报服务协议。
  • TCP具有高可靠性,确保传输数据的正确性,不出现丢失或乱序等问题。UDP在传输数据时,不建立连接,会出现丢失、重复和乱序等问题。
  • UDP具有较好的实时性,工作效率比TCP高。
  • UDP数据结构比TCP数据结构简单,因此网络开销也小。
  • TCP协议可以保证接收端毫无差错地接收到发送端发出的字节流,为应用程序提供可靠的通信服务。对可靠性要求高的通信系统往往使用TCP传输数据。如HTTP运用TCP进行数据的传输。
  • UDP是面向消息的协议,一般用于多点通信和实时数据服务。即使丢失一两个数据包,也不会对接收结果产生太大的影响。如视频直播。

创建UDP服务器和客户端

  • 服务器
  • socket.bind()
  • data,addr = socket.recvfrom(1024)
  • socket.sendto(data,addr)
  • 客户端
  • socket.sendto(data,addr)
  • socket.recv()
# 新建server5.py,输入以下命令,作为服务器端响应文件
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 创建UDP套接字
s.bind(('127.0.0.1',9999)) # 绑定地址到套接字
while True:
    data,addr = s.recvfrom(1024) # 接收
    print(data,addr)
    s.sendto(b'Hello,%s'%data,addr) # 发送
# 新建client5.py,输入以下命令,作为客户端请求文件
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 创建套接字
for data in [b'a',b'b',b'c']:
    s.sendto(data,('127.0.0.1',9999)) # 发送
    print(s.recv(1024).decode('utf-8')) # 接收
s.close() # 关闭


示例5:设计一个简单的客户端与服务器之间的网络运算。服务器用来做计算,客户端用来显示结果。

# 新建server6.py,输入以下命令,作为服务器端响应文件
import socket
def f(n): # 定义阶乘函数
    j = 1
    for i in range(1,n+1):
        j = j*i
    return j

s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 创建UDP套接字
s.bind(('127.0.0.1',9999)) # 绑定地址到套接字
data,addr = s.recvfrom(1024) # 接收
data = f(int(data))  # 调用阶乘函数,计算阶乘结果
send_data = str(data) # 把数字转换为字符串
print(data,addr) # 打印客户消息
s.sendto(send_data.encode(),addr) # 发送客户端
s.close() # 关闭
# 新建client6.py,输入以下命令,作为客户端请求文件
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 创建套接字
data = int(input('请输入一个大于1的整数:'))
s.sendto(str(data).encode(),('127.0.0.1',9999)) # 发送
print('计算结果:',s.recv(1024).decode('utf-8')) # 接收
s.close() # 关闭

相关文章
|
16小时前
|
存储 开发者 Python
从理论到实践:Python中Trie树与Suffix Tree的完美结合,开启编程新篇章!
【7月更文挑战第19天】在编程实践中,Trie树和Suffix Tree优化了字符串处理。Trie树用于快速拼写检查,如在构建词库后,能高效判断单词是否存在。Suffix Tree则助力文本相似度检测,找寻共同子串。通过Python示例展示了Trie树插入和搜索方法,并指出Suffix Tree虽复杂但能提升性能。结合两者,实现复杂功能,展现数据结构的强大。
15 3
|
1天前
|
Python
告别低效!Python并查集:数据结构界的超级英雄,拯救你的编程人生!
【7月更文挑战第18天】并查集,数据结构超级英雄,用于不相交集合的合并与查询。Python实现包括初始化、查找根节点和合并操作。应用广泛,如社交网络分析、图论问题、集合划分等。示例代码展示了解决岛屿数量问题,统计连通的“1”单元格数。掌握并查集,提升编程效率,解决复杂问题。
15 6
|
1天前
|
网络协议 程序员
TCP报文格式全解析:网络小白变高手的必读指南
**TCP报文格式详解摘要** 探索TCP,传输层的关键协议,提供可靠数据传输。报文含源/目的端口(标识应用),32位序号(跟踪字节顺序),确认序号(确认接收),4位首部长度,6位标志(URG, ACK, PSH, RST, SYN, FIN),窗口大小(流量控制),检验和(数据完整性),紧急指针(优先数据)及可变长选项(如MSS, 时间戳)。了解这些字段,能更好地理解TCP连接的建立、管理和数据交换。
16 3
|
3天前
|
算法 程序员 计算机视觉
Python并查集:数据结构界的肌肉男,让你在编程路上无所畏惧!
【7月更文挑战第16天】并查集,一种处理不相交集合合并与查询的数据结构,被誉为编程的“肌肉男”。它提供Find(找根节点)和Union(合并集合)操作,常用于好友关系判断、图像处理、集合合并等。Python实现中,路径压缩和按秩合并优化效率。并查集的高效性能使其成为解决问题的强大工具,助力程序员应对复杂挑战。
18 0
|
3天前
|
Python
智慧之光!Python并查集:点亮你的编程思维,让复杂问题迎刃而解!
【7月更文挑战第16天】并查集,一种树型数据结构,用于处理不交集合并与查询。通过路径压缩和按秩合并优化,支持Find(查找元素集合)和Union(合并集合)操作。Python实现简单示例展示如何判断社交网络中用户是否互为好友,高效解决连通性问题,点亮编程思维。
8 0
|
3天前
|
网络协议 算法 程序员
提高网络稳定性的关键:TCP滑动窗口与拥塞控制解析
**TCP可靠传输与拥塞控制概要:** 小米讲解TCP如何确保数据可靠性。TCP通过分割数据、编号段、校验和、流量控制(滑动窗口)和拥塞控制(慢开始、拥塞避免、快重传、快恢复)保证数据安全传输。拥塞控制动态调整窗口大小,防止网络过载,提升效率。当连续收到3个相同ACK时执行快重传,快恢复避免剧烈波动。关注“软件求生”获取更多技术内容。
19 4
提高网络稳定性的关键:TCP滑动窗口与拥塞控制解析
|
5天前
|
数据挖掘 开发者 Python
如何自学Python编程?
【7月更文挑战第14天】如何自学Python编程?
19 4
|
7天前
|
网络协议 程序员 定位技术
学习网络的第一步:全面解析OSI与TCP/IP模型
**网络基础知识概览:** 探索网络通信的关键模型——OSI七层模型和TCP/IP五层模型。OSI模型(物理、数据链路、网络、传输、会话、表示、应用层)提供理论框架,而TCP/IP模型(物理、数据链路、网络、传输、应用层)更为实际,合并了会话、表示和应用层。两者帮助理解数据在网络中的传输过程,为网络设计和管理提供理论支持。了解这些模型,如同在复杂的网络世界中持有了地图。
16 2
|
8天前
|
Python
不容错过!Python中图的精妙表示与高效遍历策略,提升你的编程艺术感
【7月更文挑战第11天】在Python编程中,图以邻接表或邻接矩阵表示,前者节省空间,后者利于查询连接。通过字典实现邻接表,二维列表构建邻接矩阵。图的遍历包括深度优先搜索(DFS)和广度优先搜索(BFS)。DFS使用递归,BFS借助队列。这些基础技巧对于解决复杂数据关系问题,如社交网络分析或迷宫求解,至关重要,能提升编程艺术。
16 5
|
10天前
|
数据采集 大数据 数据安全/隐私保护
Python编程:如何有效等待套接字的读取与关闭
Python网络编程中,套接字事件处理至关重要。利用`selectors`模块和代理IP能增强程序的稳定性和可靠性。代码示例展示了如何通过代理连接目标服务器,注册套接字的读写事件并高效处理。在代理IP配置、连接创建、事件循环及回调函数中,实现了数据收发与连接管理,有效应对网络爬虫或聊天应用的需求,同时保护了真实IP。
Python编程:如何有效等待套接字的读取与关闭