网络编程中的TCP和UDP

 

什么是TCP协议

TCP( Transmission control protocol )即传输控制协议,是一种面向连接、可靠的数据传输协议,它是为了在不可靠的互联网上提供可靠的端到端字节流而专门设计的一个传输协议。

  • 面向连接 :数据传输之前客户端和服务器端必须建立连接

  • 可靠的 :数据传输是有序的 要对数据进行校验

 

TCP三次握手

为了保证客户端和服务器端的可靠连接,TCP建立连接时必须要进行三次会话,也叫TCP三次握手,进行三次握手的目的是为了确认双方的接收能力和发送能力是否正常。

  1. 第一次握手(呼叫请求)
    • 你(客户端):想要和某人通话,于是你拿起电话,拨打对方的号码。这个动作相当于TCP中的SYN(同步序列编号)包发送。你告诉对方(服务器):“嘿,我在这里,我想和你建立通话。”
  2. 第二次握手(接听确认)
    • 对方(服务器):听到电话铃声后,接起电话,并对你的呼叫做出响应。这相当于TCP中的SYN-ACK(同步确认)包发送。对方(服务器)说:“我听到了,我也在这里,我们可以开始通话了。”同时,对方(服务器)也确认了你的存在,并准备好接下来的通信。
  3. 第三次握手(确认接听)
    • 你(客户端):在听到对方的接听确认后,你回应一个确认信号,告诉对方你已经准备好开始通话了。这相当于TCP中的ACK(确认)包发送。你说:“好的,我已经准备好了,我们可以开始通话了。”

 

  • 第一次握手 TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT 同步已发送状态
  • 第二次握手 TCP服务器收到请求报文后,如果同意连接,则会向客户端发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了 SYN-RCVD 同步收到状态.
  • 第三次握手 TCP客户端收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED已建立连接状态 触发三次握手

三次握手主要作用:防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误

第一次握手: 客户端向服务器端发送报文 证明客户端的发送能力正常 第二次握手:服务器端接收到报文并向客户端发送报文 证明服务器端的接收能力、发送能力正常 第三次握手:客户端向服务器发送报文 证明客户端的接收能力正常


TCP四次挥手

建立TCP连接需要三次握手,终止TCP连接需要四次挥手。

张三:好的,那我先走了

李四:好的,那你走吧

李四:那我也走了?

张三:好的,你走吧  

 

Socket的定义

Socket的英文原义是“孔”或“插座”,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

建立网络通信连接至少要一对端口号(socket),socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。

Python 官方关于 Socket 的函数 socket — Low-level networking interface — Python 3.12.4 documentation

Socket的类型  

  • TCP发送数据时,已建立好TCP连接,所以不需要指定地址。UDP是面向无连接的, 每次发送要指定是发给谁。

  • 服务端与客户端不能直接发送列表,元组,字典。需要字节化(data)。

服务端socket函数:

客户端Socket函数

 

共有的函数 :

SOCKET函数描述
s.recv(bufsize[,flag])接受TCP,UDP套接字的数据。数据以字符串形式返回,bufsize指定要接收的最大数据量。
s.send(string[,flag])发送TCP,UDP数据。
s.sendall(string[,flag])完整发送TCP数据。
s.recvfrom(bufsize[.flag])接受UDP套接字的数据。与recv()类似,但返回值是(data,address)。
s.sendto(string[,flag],address)发送UDP数据。将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。
s.close()关闭套接字。
s.getpeername()返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname()返回套接字自己的地址。
s.setsockopt(level,optname,value)设置给定套接字选项的值。
s.getsockopt(level,optname[.buflen])设置给定套接字选项的值。
s.settimeout(timeout)设置套接字操作的超时期
s.gettimeout()返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.fileno()返回套接字的文件描述符。
s.setblocking(flag)如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。
s.makefile()创建一个与该套接字相关连的文件

TCP实现一对一的简单聊天

服务端代码:

from socket import *tcp_server = socket(AF_INET, SOCK_STREAM)# 绑定本地信息,TCP服务器程序监听所有网络接口上的88888端口
host_port = ('', 88888)  
tcp_server.bind(host_port)# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcp_server.listen(5)while True:newSocket, host_port = tcp_server.accept()while True:# 最大接收1024个字节recvData = newSocket.recv(1024)if len(recvData) > 0:print('recv:', recvData)else:breaksendData = input("send:")newSocket.send(sendData.encode('utf8'))newSocket.close()tcp_server.close()

客户端代码:

from socket import *tcp_client = socket(AF_INET, SOCK_STREAM)# 链接服务器
host_port = ('127.0.0.1', 88888)
tcp_client.connect(host_port)while True:sendData = input("send:")if len(sendData) > 0:tcp_client.send(sendData.encode('utf8'))else:break# 最大接收1024个字节recvData = tcp_client.recv(1024)print('recv:', recvData.decode('uft8'))tcp_client.close()

UDP

UDP ---(User Datagram Protocol) 用户数据报协议,是一个无连接的简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,没有超时重发等机制,所以传输速度很快。

UDP是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

UDP特点:

UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。 UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。 UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

【适用情况】 UDP是面向消息的协议,通信时不需要建立连接,数据的传输自然是不可靠的,UDP一般用于多点通信和实时的数据业务,比如

  • 语音广播

  • 视频

  • QQ

  • TFTP(简单文件传送)

  • 大型网络游戏

相比较于TCP注重速度流畅

UDP简单案例

服务端代码

import socketsk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定 IP 和端口号
sk.bind(('127.0.0.1', 88888))
while True:msg, addr = sk.recvfrom(1024)print('来自[%s:%s]的消息: %s' % (addr[0], addr[1], msg.decode('utf-8')))inp = input('>>>')sk.sendto(inp.encode('utf-8'), addr)sk.close()

 客户端代码:

import socketsk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ('127.0.0.1', 88888)
while True:msg = input('>>>')sk.sendto(msg.encode('utf-8'), addr)msg_recv, addr = sk.recvfrom(1024)print(msg_recv.decode('utf-8'))sk.close()

实现简单TFTP(基于UDP协议) 

实现一个简单的TFTP(Trivial File Transfer Protocol)服务器和客户端基于UDP协议是一个有趣的小练习。TFTP是一个简单的文件传输协议,它使用UDP协议,并且通常用于小文件的传输。

我们值实现最基本的功能:从服务器读取文件并发送到客户端。 

TFTP 服务器:

import socket  
import struct  def handle_client(sock, filename):  # 假设文件存在且小于65535字节  try:  with open(filename, 'rb') as file:  data = file.read(512)  # TFTP块大小为512字节  block_number = 1  while data:  # 发送DATA包:block_number + data  block_info = struct.pack('!H', block_number)  # 网络字节序的短整型  sock.sendto(block_info + data, client_address)  # 等待ACK  ack_data, _ = sock.recvfrom(2)  # 只接收block number  ack_block_number = struct.unpack('!H', ack_data)[0]  if ack_block_number != block_number:  print("Incorrect block number in ACK")  break  block_number += 1  data = file.read(512)  except FileNotFoundError:  # 发送ERROR包  error_code = 1  # File not found  error_msg = struct.pack('!HH', error_code, 0)  # TFTP错误消息格式  sock.sendto(error_msg, client_address)  def start_tftp_server(port, root_dir):  server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  server_socket.bind(('0.0.0.0', port))  print(f"TFTP server listening on port {port}...")  while True:  data, client_address = server_socket.recvfrom(1024)  # 接收RRQ或WRQ请求  # 这里简化处理,只处理RRQ  if data.startswith(b'\x00\x01'):  # RRQ的opcode  filename = data[2:].decode().split(b'\x00')[0]  filepath = f"{root_dir}/{filename}"  handle_client(server_socket, filepath)  if __name__ == "__main__":  start_tftp_server(69, './files') 

TFTP 客户端:

import socket  
import struct  def request_file(server_ip, server_port, filename):  client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 发送RRQ请求  rrq = b'\x00\x01' + filename.encode() + b'\x00' + b'octet' + b'\x00'  # mode为octet  client_socket.sendto(rrq, (server_ip, server_port))  block_number = 0  data = b''  while True:  # 接收DATA包  data_packet, _ = client_socket.recvfrom(514)  # 512字节数据 + 2字节块号  block_number = struct.unpack('!H', data_packet[:2])[0]  if block_number == 0:  # 假设块号为0表示文件结束或错误  break  data += data_packet[2:]  # 发送ACK  ack = struct.pack('!H', block_number)  client_socket.sendto(ack, (server_ip, server_port))  client_socket.close()  # 处理接收到的数据(例如,写入文件)  with open(filename, 'wb') as file:  file.write(data)  if __name__ == "__main__":  request_file('127.0.0.1', 69)file_name = 'example.txt'  request_file(server_addr, 69, file_name)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/48323.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web学习笔记(八十二)uniapp

目录 1.介绍uniapp 2.uniapp项目结构 3.自定义tabBer 4.uniapp条件编译 使用方法 5.uniapp的路由跳转 (1)js跳转 (2)标签跳转 获取参数 6.生命周期 6.1 全局生命周期 6.2 页面生命周期 1.介绍uniapp uniapp是一个基于…

Aouth2单点登录

信息来源B站 不改bug早点睡,北冥 时序图 -----------------------------总结描述 总体流程 浏览器 - 系统1 - 系统2 - 认证中心(SSO) 访问系统1 浏览器,访问系统1,询问认证中心是否登录 未登录,重定向一个登录页面返回给浏…

(二)原生js案例之数码时钟计时

原生js实现的数字时间上下切换显示时间的效果&#xff0c;有参考相关设计&#xff0c;思路比较难&#xff0c;代码其实很简单 效果 代码实现 必要的样式 <style>* {padding: 0;margin: 0;}.content{/* text-align: center; */display: flex;align-items: center;justif…

光盘防水嘛 ? DVD+R 刻录光盘泡水实验

首发日期 2024-07-20, 以下为原文内容: 同志们好, 欢迎来到 胖喵穷人实验室 ! 这里专注于 低成本, 低难度, 低风险 的 “三低” 小实验. 胖喵穷人实验室 (PM-PLab-E)正式名称: 紫腹巨蚊 (Toxorhynchites gravelyi) 系列穷人 (Poor people) 实验室风险警告: 低风险并不是零风险…

Python面试题:使用Python进行元编程:元类和元编程技巧

在 Python 中&#xff0c;元编程是一种编程技巧&#xff0c;它涉及到代码本身的结构和行为的编程。元编程允许你编写能够操作、修改或生成代码的代码。最常见的元编程技术包括使用元类、装饰器和类装饰器。以下是对 Python 元编程的详细讲解&#xff0c;包括元类和一些常用的元…

Nginx系列-5 root和alias和index和try_files

1.root和alias root和alias用于指定文件系统的路径。root一般定义在server块中&#xff0c;为每个server指定文件系统路径&#xff1b;alias只能定义在location块中&#xff0c;为具体的url指定文件系统。二者的差别还体现在&#xff1a; [1] root只能指定目录&#xff0c;而a…

人工智能与语音识别:技术进步与应用前景

引言 人工智能&#xff08;AI&#xff09;作为当今科技进步的核心驱动力&#xff0c;正在各个领域展现其变革力量。其中&#xff0c;语音识别技术作为人工智能的重要应用之一&#xff0c;已经深入到我们的日常生活和工作中。从智能助手如Siri、Google Assistant&#xff0c;到智…

kubernetes k8s Deployment 控制器配置管理 k8s 红蓝部署 金丝雀发布

目录 1、Deployment控制器&#xff1a;概念、原理解读 1.1 Deployment概述 1.2 Deployment工作原理&#xff1a;如何管理rs和Pod&#xff1f; 2、Deployment资源清单文件编写技巧 3、Deployment使用案例&#xff1a;创建一个web站点 4、Deployment管理pod&#xff1a;扩…

排序规则utf8_general_ci的作用是什么?

排序规则 utf8_general_ci 是指针对使用 UTF-8 编码存储的数据进行排序和比较的一种规则。在数据库管理系统&#xff08;如MySQL&#xff09;中&#xff0c;排序规则决定了在执行查询时如何比较和排序文本数据。 具体来说&#xff0c;utf8_general_ci 中的几个部分含义如下&am…

科研绘图系列:R语言雨云图(Raincloud plot)

介绍 雨云图(Raincloud plot)是一种数据可视化工具,它结合了多种数据展示方式,旨在提供对数据集的全面了解。雨云图通常包括以下几个部分: 密度图(Density plot):表示数据的分布情况,密度图的曲线可以展示数据在不同数值区间的密度。箱线图(Box plot):显示数据的中…

模型剪枝入门

一、定义 1.定义 2. 案例1 3. 全局剪枝案例 4. 全局剪枝案例 5. 自定义剪枝 6. 特定网络剪枝 7. 多参数模块剪枝 8. torch.nn.utils.prune 解读 二、实现 定义 接口&#xff1a; import torch.nn.utils.prune as prune案例1 import torch.nn as nn import torch.nn.utils.…

createElement方法,

在JavaScript中&#xff0c; createElement 方法&#xff0c;这是JavaScript中DOM操作的一部分&#xff0c;用于创建一个新的HTML元素。 以下是 document.createElement 方法的基本用法&#xff1a; 创建新元素 let newElement document.createElement(div); // 创建一个…

全部由1组成的子矩形的数量

题目描述&#xff1a; 给定一个二维数组matrix&#xff0c;其中的值不是0就是1&#xff0c;返回全部由1组成的子矩阵的数量。 way&#xff1a; 假设我们遍历矩形的每一行&#xff0c;以当前遍历到的行作为地基&#xff0c;去看这一行的直方图&#xff08;直方图介绍 ->直方…

10.3.3 QGIS点类型注释(Annotation)的应用与二次开发实现

文章目录 前言注释(Annotation)图层QGis中的注释(Annotation)图层二次开发实现线段类型注释(Annotation)点类型Item 总结 前言 介绍注释(Annotation)图层在QGis中的使用以及二次开发的实现说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 注释(Annotation)…

【Unity实战100例】Unity声音可视化多种显示效果

目录 一、技术背景 二、界面搭建 三、 实现 UIAudioVisualizer 基类 四、实现 AudioSampler 类 五、实现 IAudioSample 接口 六、实现MusicAudioVisualizer 七、实现 MicrophoneAudioManager 类 八、实现 MicrophoneAudioVisualizer 类 九、源码下载 Unity声音可视化四…

firefly rk3288 解决刷入Linux固件后mac地址一样的问题

原理&#xff1a;使用cpuid生成mac地址 1、修改u-boot/net/eth_common.c里的eth_env_set_enetaddr函数为&#xff1a; int eth_env_set_enetaddr(const char *name, const uchar *enetaddr) {char buf[ARP_HLEN_ASCII 1];sprintf(buf, "%pM", enetaddr);return en…

代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网:55.右旋转字符串

代码随想录算法训练营 Day 9 代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网&#xff1a;55.右旋转字符串 目录 代码随想录算法训练营前言LeetCode151.翻转字符串里的单词卡码网&#xff1a;55.右旋转字符串 一、LeetCode151.翻转字符串里的单词1.题目链…

laravel为Model设置全局作用域

如果一个项目中存在这么一个sql条件在任何情况下或大多数情况都会被使用&#xff0c;同时很容易被开发者遗忘&#xff0c;那么就非常适用于今天要提到的这个功能&#xff0c;Eloquent\Model的全局作用域。 首先看一个示例&#xff0c;有个数据表&#xff0c;结构如下&#xff1…

运行sudo apt install net-tools时显示无法定位软件包

当你在 Ubuntu 或基于 Debian 的系统上运行 sudo apt install net-tools 并收到“无法定位软件包”的错误时&#xff0c;这通常意味着你的系统可能没有正确配置软件源&#xff0c;或者软件源中没有提供 net-tools 包。以下是一些可能的解决方案&#xff1a; 1. 更新软件源列表…

java设计模式:03-结构型模式-概览

结构型模式&#xff08;Structural Patterns&#xff09; 结构型模式&#xff08;Structural Patterns&#xff09;主要关注类和对象的组合方式&#xff0c;旨在通过不同的结构组合方式来建立新的功能。结构型模式可以帮助开发者确保即使对象组合方式改变&#xff0c;也能保持…