TCP基础知识点
TCP 特点:
- 优点
- 面向连接(这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。)
- 传输可靠,不丢包。(TCP采用发送应答机制,超时重传,错误校验,流量控制和阻塞管理)
- 缺点
- 传输速度慢,占用系统资源高
TCP和UDP区别:
TCP 面向连接; UDP 是不面向连接;
TCP 提供可靠的数据传输,也就是说,通过 TCP 连接传送的数据,无差错,不丢失,不重复,且按序到达; UDP 不保证可靠的数据传输,容易出现丢包情况;
TCP 需要连接传输速度慢,UDP 不需要连接传输速度快
TCP 不支持发广播; UDP 支持发广播
TCP 对系统资源要求较多,UDP 对系统资源要求较少。
TCP 适合发送大量数据,UDP 适合发送少量数据
TCP 有流量控制,UDP 没有流量控制
TCP网络程序流程:
TCP的三次握手,四次挥手:
SYN: 表示连接请求 ACK: 表示确认 FIN: 表示关闭连接 seq:表示报文序号 ack: 表示确认序号
图解流程图
第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack (number )=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
图解流程如下
第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送。
第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1。
第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送。
第四次挥手:Client收到FIN后,接着发送一个ACK给Server,确认序号为收到序号+1。
客户端发送数据
# 客户端发送数据步骤
# 1. 初始化socket
# 2. 连接
# 3. 发送数据
# 4. 关闭
import socket
def main():
"""客户端步骤"""
# 1.初始化socket
socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接
socket_client.connect(("127.0.0.1", 8081))
# 3. 发送数据
socket_client.send("我要发了".encode("utf-8"))
socket_client.send("我再发".encode("utf-8"))
# 4. 关闭
socket_client.close()
if __name__ == '__main__':
main()
客户端发送接收数据
# 客户端发送接收数据
# 1. 初始化socket
# 2. 连接
# 3. 发送数据
# 4. 接收数据
# 5. 关闭
import socket
def main():
"""tcp客户端"""
# 1.初始化socket
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接
tcp_client.connect(("127.0.0.1", 8081))
# 3. 发送数据
tcp_client.send("我要发了".encode("utf-8"))
# 4. 接收数据
tcp_client_data = tcp_client.recv(1024)
print(tcp_client_data)
print("解码:", tcp_client_data.decode("utf-8"))
# 5.关闭
tcp_client.close()
if __name__ == '__main__':
main()
tcp服务器端
# tcp服务器端
# 1. 初始化socket
# 2. 绑定端口及地址
# 3. 设置 被 动模块,设置 最大等待的客户端
# 4. 接收用户的请求
# 5. 处理客户端的请求
# 6. 关闭
import socket
def main():
"""tcp服务器端"""
# 1.初始化socket
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定端口与地址
tcp_server.bind(("", 8182))
# 3. 设置 被 动
tcp_server.listen(128)
# 4. 接收用户的请求
clinet, address = tcp_server.accept()
print(clinet)
print(address)
# 处理
clinet.send("我知道了".encode("utf-8"))
data = clinet.recv(1024)
print(data.decode("utf-8"))
# 6.关闭
clinet.close()
tcp_server.close()
if __name__ == '__main__':
main()
聊天机器人(没有添加多任务)
# 创建一个tcp服务器端
# 1. 初始化
# 2. 绑定端口
# 3. 设置被动模式
# 4. 循环接收用户的请求
# 5. 处理用户的请求
# 6. 关闭
import socket
def client_exec(client):
"""
这个客户端的处理
:param client: 客户端连接的对象
:return: NONE
"""
while True:
# 判断客户端是否关闭了,判断发送过来的数据,如果是空的,那么退出循环,如果不是空的,那回个信息
data = client.recv(1024)
# 判断是否有数据
if data:
# 说明有数据n
# 解析 数据
data_decode = data.decode("utf-8")
# 您的数据已收到
send_data = "您的数据已收到%s" % data_decode
client.send(send_data.encode("utf-8"))
else:
# 说明没有数据,
# 退出循环
break
# 关闭客户端
client.close()
def main():
"""聊天机器人"""
# 1.初始化
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定端口
tcp_server.bind(("", 8181))
# 3. 设置被动模式
tcp_server.listen(128)
# 4. 循环接收用户的请求
while True:
# 接收
client, address = tcp_server.accept()
# 处理用户的请求
# 一个函数一个功能
client_exec(client)
# 关闭
tcp_server.close()
if __name__ == '__main__':
main()
文件下载器服务器
# 1. 创建tcp服务器端
# 1.1 初始化socket
# 1.2 绑定 端口
# 1.3 设置被 动 128
# 1.4 循环接收客户端的文件路径
# 1.5 客户端的处理
# 1.6 关闭
# 2. 循环接收客户端发过来的文件路径
# 3. 判断一下文件是否存在
# 4. 文件存在,读取文件内容,一次读1024字节,循环发送给客户端
# 5. 没有文件,终止
# 6. 关闭
import os
import socket
def client_exec(client):
"""
客户端的处理
:param client: 与客户端连接的对象
:return: NONE
"""
# 接收的路径
file_path = client.recv(1024).decode("utf-8")
# 判断文件是否存在
# xx.if
if os.path.exists(file_path):
print("文件存在")
# 说明路径存在
# 打开文件,循环读取内容发送,一次读1024字节
with open(file_path, 'rb') as f:
# 循环读取我们的内容
while True:
# 一次读1024字节
content = f.read(1024)
# 判断当前的文件是否读完了
if content:
# 说明有内容
# 发送
client.send(content)
print("发送了数据")
else:
print("发送完毕")
# 说明没有内容
# 关闭
# 关闭客户端,函数结束
client.close()
return
else:
print("文件不存在")
# 说明路径不存在
client.close()
# 终止当前的函数
return
# 最后进行关闭
client.close()
def main():
"""文件下载服务器"""
# 1. 创建tcp服务器端
# 1.1 初始化socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 复用端口
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 1.2 绑定 端口
socket_server.bind(("", 8082))
# 1.3 设置被 动 128
socket_server.listen(128)
# 1.4 循环接收客户端的文件路径
while True:
client, address = socket_server.accept()
# 1.5 客户端的处理
# 一个函数一个功能
client_exec(client)
# 1.6 关闭
socket_server.close()
if __name__ == '__main__':
main()
文件下载客户端
# 1. 创建一个tcp客户端
# 2. 发送一个路径
# 3. 循环接收服务器端发送过来的数据
# 4. 判断当前的数据是否结束
# 5. 如果有数据,那么我保存到我们的下载的文件中
# 6. 没有数据,程序结束
import socket
def main():
"""文件下载客户端"""
# 创建一个tcp客户端
# 1.初始化socket
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接
tcp_client.connect(("127.0.0.1", 8082))
# 3. 发送数据
tcp_client.send("./1.gif".encode("utf-8"))
# 4. 循环接收我们的数据
while True:
# 接收的数据
data = tcp_client.recv(1024)
# 判断一下数据是否完毕
if data:
# 说明有数据
# 保存到文件中
with open("./1_back.gif", 'ab') as f:
f.write(data)
else:
# 说明没有数据
# 退出循环
break
# 5.关闭
tcp_client.close()
if __name__ == '__main__':
main()