前言
在当今互联网时代,网络编程已成为程序员必备的核心技能之一。无论是开发即时通讯软件、网络游戏,还是构建Web应用,都离不开对网络通信原理的理解和掌握。本文将带你从零开始学习计算机网络基础知识,并手把手教你如何用Python开发TCP客户端和服务器端程序。
一、计算机网络基础概念
1. 什么是计算机网络?
计算机网络是将具有独立功能的多台计算机通过通信线路和通信设备连接起来,在网络管理软件及网络通信协议下,实现资源共享和信息传递的虚拟平台。
简单来说,计算机网络就是让多台计算机能够互相通信、共享资源的系统。
2. 为什么要学习网络编程?
学习网络编程的主要目的是能够编写基于网络通信的软件或程序。通过掌握网络编程,你可以:
- 开发即时通讯软件(如微信、QQ)
- 构建网络游戏
- 实现远程文件传输
- 开发Web服务器和客户端
- 创建分布式系统
3. IP地址详解
3.1 IP地址的概念
当我们在计算机中使用微信和朋友聊天时,信息是如何精准传递到对方计算机的呢?答案就是通过IP地址。
IP地址是分配给网络设备上网使用的数字标签,它能够标识网络中唯一的一台设备,好比现实中每个人都有一个手机号。
3.2 IP地址的表现形式
IP地址有两种主要版本:
- IPv4:目前广泛使用的IP地址格式,由4个0-255的数字组成,如
192.168.1.1
- IPv6:下一代IP地址格式,由8组4位十六进制数组成,如
2001:0db8:85a3:0000:0000:8a2e:0370:7334
IPv4地址示例:
IPv6地址示例:
3.3 查看计算机IP地址
- Linux/macOS:在终端输入
ifconfig
- Windows:在命令提示符输入
ipconfig
3.4 检查网络连接
使用ping
命令检查网络是否正常:
如果看到类似下面的响应,说明网络连接正常:
4. 端口和端口号
4.1 端口的概念
如果一台电脑上运行着多个网络程序(如微信、浏览器、邮件客户端等),它是如何区分这些程序并将数据正确传递给目标程序呢?
答案是通过端口。端口是传输数据的通道,每个网络程序都会使用一个特定的端口来收发数据。
4.2 端口号
为了统一管理众多端口,操作系统对端口进行了编号,这就是端口号。端口号是一个数字,范围从0到65535。
- 知名端口号:0-1023,通常分配给系统服务
- 80:HTTP服务
- 443:HTTPS服务
- 21:FTP服务
- 22:SSH服务
- 动态端口号:1024-65535,供普通程序使用
常见端口号及其服务:
端口号 | 服务名称 | 协议类型 | 主要功能描述 |
---|---|---|---|
20/21 | FTP | TCP | 文件传输协议 |
22 | SSH | TCP | 安全远程登录 |
80 | HTTP | TCP | 网页浏览 |
443 | HTTPS | TCP | 加密网页浏览 |
4.3 通信原理总结
网络通信的完整过程:
- 通过IP地址找到目标设备
- 通过端口号找到目标程序
- 通过端口将数据传输给应用程序
二、Socket套接字编程
1. 什么是Socket?
Socket(套接字)是计算机之间进行通信的一种约定或方式,socket套接字就是程序间进⾏⽹络通讯的⼯具。通过Socket,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。不夸张的说,只要跟⽹络相关的应⽤程序或者软件都使⽤到了socket。
Socket就像现实中的电话:
- 知道对方的电话号码(IP地址+端口号)
- 使用电话(Socket)进行通话(通信)
2. Socket的使用场景
几乎所有网络相关的应用程序都使用Socket:
- 网页浏览器
- 即时通讯软件
- 网络游戏
- 文件传输工具
- 远程控制软件
三、TCP协议和UDP协议详解
1. 为什么需要TCP和UDP协议?
仅仅知道IP地址和端口号还不够,在发送数据之前还需要选择网络传输方式(传输协议),确保程序之间按照指定的规则进行数据通信。
2. TCP协议和UDP协议特点
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信模型相当于生活中的"打电话":
- 建立连接(拨号)
- 传输数据(通话)
- 关闭连接(挂断)
TCP的主要特点:
- 面向连接:通信前必须先建立连接
- 可靠传输:确保数据准确送达
- 发送应答机制:每个报文段必须得到接收方应答
- 超时重传:未收到应答会重新发送
- 错误校验:校验数据是否有错误
- 流量控制:避免发送过快导致接收方来不及处理
UDP的主要特点:
无连接:不需要建立连接即可直接发送数据。
不可靠传输:不保证数据的可靠性,没有确认、重传和排序机制。
低延迟:由于没有连接建立和可靠性保障,传输速度较快。
面向报文:以数据报的形式传输,每个数据报独立处理。
简单高效:协议开销小,适合对可靠性要求不高但对速度要求较高的场景。
3. TCP vs UDP
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 | 无连接 |
可靠性 | 可靠 | 不可靠 |
传输速度 | 较慢 | 较快 |
适用场景 | 网页、邮件、文件传输 | 视频通话、在线游戏 |
4、TCP/IP、UDP、Socket的协议关系图
四、Python网络编程实践
1. 编码转换基础
在网络传输中,数据都是以二进制形式传输的,因此需要进行编码转换。
Python编码转换方法:
函数名 | 说明 |
encode | 编码 将 字符串 转化为 字节码 |
decode | 解码 将 字节码 转化为 字符串 |
mystr = input("请输入字符串:")# 编码
mystr_encode = mystr.encode(encoding="utf-8")
print(mystr_encode)# 解码:
mystr_decode = mystr_encode.decode(encoding="utf-8")
print(mystr_decode)
运行结果:
2. TCP客户端开发
开发流程介绍:
TCP客户端开发流程(五步走):
- 创建客户端套接字对象(买电话)
- 和服务端套接字建立连接(打电话)
- 发送数据(说话)
- 接收数据(听对方说)
- 关闭客户端套接字(挂电话)
开发客户端需要使用到的函数:
方法名 | 说明 |
connect | 和服务端套接字建立连接 |
send | 发送数据 |
recv | 接受数据 |
close | 关闭连接 |
TCP客户端代码示例:
# 导入socket模块,用于创建网络连接
import socket
while True:# 1、创建客户端套接字对象(买电话)# socket.AF_INET--- 使⽤IPv4协议,AF_INET6---使⽤IPv6协议# socket.SOCK_STREAM--- 使⽤TCP协议,SOCK_DGRAM---使⽤UDP协议client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2、和服务端套接字建立连接(打电话)(参数必须为一个元组)# 打电话给谁:连接的时候两个括号里面要写服务器的ip地址和端口号client_socket.connect(("127.0.0.1", 8080))# 3、发送数据(说话)my_str = input("请输入你要发送的数据:")client_socket.send(my_str.encode("utf-8"))# 4、接收数据(听对方说话)data = client_socket.recv(1024).decode("utf-8")print(f"接收到服务端回我的消息是:{data}")# 5、关闭客户端套接字(挂电话)client_socket.close()
但是这时候我们还没有服务端,怎么才能看到我们的效果呢?
我们使⽤⽹络调试查看,效果如下图所示:
下载地址:https://www.cmsoft.cn/resource/102.html
3. TCP服务器端开发
开发服务端需要使用到的函数:
⽅法名 | 说明 |
bind | 绑定IP地址和端⼝号 |
listen | 设置监听 |
accept | 等待接受客户端的连接请求 |
send | 发送数据 |
recv | 接收数据 |
TCP服务器端开发流程(七步走):
- 创建服务端套接字对象
- 绑定IP地址和端口号
- 设置监听
- 等待接受客户端的连接请求
- 接收数据
- 发送数据
- 关闭套接字
TCP服务器端代码示例:
import socket# 1、创建服务器套接字对象
# socket.AF_INET--- 使⽤IPv4协议,AF_INET6---使⽤IPv6协议
# socket.SOCK_STREAM--- 使⽤TCP协议,SOCK_DGRAM---使⽤UDP协议
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2、绑定IP地址和端口号
server_socket.bind(("127.0.0.1", 8080))
# 3、设置监听
server_socket.listen()
while True:# 4、等待接受客户端的连接请求# 连接建立后,返回一个元组 (client_socket, ip_port)# 其中 client_socket 用于与客户端通信,ip_port 是客户端的地址信息client_socket,ip_port = server_socket.accept()print(f"客户端的ip地址和端口号:{ip_port}")# 5、接收数据data = client_socket.recv(1024).decode("utf-8")print(f"接受到的数据:{data}")# 6、发送数据my_str = input("请输入你要发生的信息:")client_socket.send(my_str.encode("utf-8"))# 7、关闭套接字client_socket.close()
server_socket.close()
运行结果:(注意:要先运行服务端再运行客户端)
4. 面向对象的TCP服务器和客户端的实现
服务端面向对象编程:
# 导⼊socket模块,⽤于⽹络编程
import socket
# 定义⼀个WebServer类,⽤于创建服务器对象
class WebServer(object):# 初始化⽅法,设置服务器的套接字并监听指定端⼝def __init__(self):# 创建TCP套接字self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 绑定服务器地址和端⼝self.tcp_server_socket.bind(("", 8080))# 设置监听模式self.tcp_server_socket.listen(128)# 处理客户端请求的⽅法def handle_client_request(self, new_socket, ip_port):# 接收客户端发送的数据recv_data = new_socket.recv(1024)# 将接收到的数据解码为字符串recv_data = recv_data.decode('utf-8')# 打印客户端信息和消息内容print(f'{ip_port}客户端发送过来的消息:{recv_data}')# 构造响应消息并发送回客户端content = '信息已收到,over,over!'.encode('utf-8')new_socket.send(content)# 关闭与客户端的连接new_socket.close()# 启动服务器的⽅法,⽤于开始监听并处理客户端连接def start(self):while True:# 接受新的客户端连接new_socket, ip_port = self.tcp_server_socket.accept()# 调⽤⽅法处理客户端请求self.handle_client_request(new_socket, ip_port)
# 主程序⼊⼝,实例化WebServer类并启动
if __name__ == '__main__':# 创建WebServer实例ws = WebServer()# 启动服务器ws.start()
客户端面向对象编程:
# 客户端面向对象的封装
import socketclass Client(object):def __init__(self, host="127.0.0.1", port=8080):self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket.connect((host, port))def send_data(self, data):if not isinstance(data, str):raise TypeError("数据类型不是字符串")try:self.client_socket.send(data.encode("utf-8"))except socket.error as e:raise IOError(f"报错原因是: {e}")def receive_data(self, buffer_size=1024):return self.client_socket.recv(buffer_size).decode("utf-8")def close(self):try:if self.client_socket:self.client_socket.close()except Exception as e:print(f"报错原因: {e}")if __name__ == "__main__":client = Client()while True:try:data = input("请输入要发送的数据:")client.send_data(data)response = client.receive_data()print(f"接收到的数据为:{response}")except IOError as e:print(f"报错原因: {e}")breakclient.close()
五、TCP连接的核心机制
1. TCP三次握手
TCP建立连接需要三次握手:
- 第一次握手:客户端发送SYN报文(同步序列编号)到服务器,表示请求建 ⽴连接。
- 第二次握手:服务器收到SYN后,回复SYN+ACK报文,表示⾃⼰也想建⽴连接。
- 第三次握手:客户端收到SYN+ACK后,发送ACK报文,双方进入ESTABLISHED状态,连接建立完成。
2. TCP四次挥手
TCP断开连接需要四次挥手:
- 第一次挥手:客户端发送FIN报文,进入FIN_WAIT_1状态
- 第二次挥手:服务器收到FIN后,发送ACK报文,进入CLOSE_WAIT状态
- 第三次挥手:服务器处理完数据后,发送FIN报文,进入LAST_ACK状态
- 第四次挥手:客户端收到FIN后,发送ACK报文,进入TIME_WAIT状态,等待2MSL后关闭
六、开发注意事项
七、总结
通过本文的学习,你应该已经掌握了:
- 计算机网络的基本概念和通信原理
- IP地址和端口号的作用
- TCP协议的特点和工作机制
- 如何使用Python开发TCP客户端和服务器程序
- TCP连接的三次握手和四次挥手过程
- 网络编程中的常见问题和解决方案
网络编程是一个广阔的领域,本文只是入门基础。如果你想深入学习,可以进一步研究:
- 多线程/多进程服务器
- 异步IO编程(asyncio)
- HTTP协议和Web开发
- WebSocket实时通信
- 网络安全和加密通信
希望这篇教程能帮助你打开网络编程的大门,祝你编程愉快!