TCP通信与UDP通信记录

news/2024/5/18 14:26:17 标签: python, tcp/ip, udp, websocket

文章目录

    • 1、TCP/IP协议
    • 2、Socket通信
    • 3、基本通信知识
    • 4、UDP网络收发数据
      • 1、发送数据测试
      • 2、接收数据测试
      • 3、循环收发测试
    • 5、TCP网络收发数据
      • 1、基本原理和过程
      • 2、数据收发示例-客户端
      • 2、数据收发示例-服务器

本人不是计算机相关专业的,也没学过,本文仅代表我个人观点,很多理论部分也有很大一部分是个人理解,写下本文一方面是重在记录学习过程,一方面是为了方便自己平时查询。

1、TCP/IP协议

下面内容来自百度百科: TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。

总结:这个是一个用于网络间进行信息传输的一种协议。

协议分层,就像之前的在单片机Linux中的SPI,IIC协议一样,TCP/IP协议也有很多层,但是要比SPI,IIC这样的复杂多了,分层如下所示,这里我觉得是看看就行,了解下基本的含义就可以了。
在这里插入图片描述
各层的作用说明:
在这里插入图片描述

注:图源 TCP/IP协议详解

那么这个协议是如何进行通信的呢,解释如下:

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

其中TCP的协议还有比较有名的三次握手和四次挥手,我在学习的时候看到了,这里顺便记录下:

三次握手的过程
在这里插入图片描述
这里有人不太理解为什么要主机发送两次信号才能确认握手,这和我们平时不太一样,平时直接确定帧头帧尾就认为通信上了,下面的流程图给出了解释:
在这里插入图片描述
下面是四次挥手的流程图
在这里插入图片描述
当然实际情况下的通信不会是按照我们这样的过程的,这样肯定不太合适,总不能像流程图一样喊话吧,我要挥手,我要握手,这样肯定不行啊,实际上的传输是通过标志物来进行的。

标志位如下所示:

  • SYN(synchronous) 建立联机
  • ACK(acknowledgement) 确认
  • PSH(push) 传输
  • FIN(finish) 结束
  • RST(reset) 重置
  • URG(urgent) 紧急

关于标志位部分的的变化,可以看这个大佬的文章,写的比较清楚:四次挥手

2、Socket通信

前面的所有内容都没有讲socket,怎么就开始出现socket这个东西了呢,看起来确实有点突兀,明明说的是TCP/IP协议,这个协议的分支里面也都没有socket的内容,就是不明白这个socket和TCP/IP协议的关系

怎么理解呢,我的理解就是他是TCP/IP协议的抽象层,意思就是在代码上的表现形式

它是一组接口。他把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。Socket一般也称套接字,是一个网络通信的套接字(接口)。然后说了这些其实还是不懂,因为连套接字是什么都不知道。。。

所以还是看下面怎么让他进行通信吧!

python中直接导入模块就可以创建了,命令如下所示:

import socket
socket.socket(address,type)

参数说明如下所示:

  • address:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
  • type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

因此我们现在就可以来创建TCP和UDP的socket了:

创建TCP的如下所示,中间部分省略,用来进行套接字的数据通信和一些功能配置使用的

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP的套接字

sock.close() # 最后关掉

创建UDP的如下所示

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建UDP的套接字

sock.close() # 最后关掉

3、基本通信知识

一个比较基本的通信示例:

下面我进行一个比较基础的实验,使用socket进行通信对话,对话内容是每秒发送和接收一段内容,那么前面我们提到了进行通信需要三元组,这里也是一样的,需要的不能缺失掉,这里的三元组是IP地址,然后端口号,还有协议了,这里我们不用太注重协议,重点关注IP地址还有端口号。

首先是获取IP地址,这里注意是获取主机的IP地址,比如这里我设置电脑为主机,同样也用电脑作为从机吧,反正可以同时开多个python程序。

获取IP地址的命令如下,打开cmd,输入

ipconfig

电脑会显示我们的ip地址(该命令在linux中为ipconfig
在这里插入图片描述
同时我们也可以看局域网下的一些其他设备,比如上面他说我们的网关(这里我用的手机热点)有一个IP地址,那想必就是手机的IP地址了,可以使用ping的命令来查看设备是否存在(这里也叫连通性测试),如下所示:
在这里插入图片描述
至于端口,端口的范围在(0-65535),端口一般就是通信的时候端口要对应下,其他的就是不要和一个比较常见的端口重合,比如80端口(局域网应该就没有这个问题),其他就没什么问题了,就是随便设置。

知名端口,一般就是一些公用的端口,范围0-1023,例如:

  • 80端口分配给HTTP服务
  • 21端口分配给FTP服务

一般我们临时建立的端口为动态端口,当我们的服务结束就意味着端口被释放了。

4、UDP网络收发数据

前面已经讲过了UDP和TCP套接字的使用流程,现在我们就先来试试效果,下面我用一张流程图先简要概括下UDP的通信过程:

在这里插入图片描述

1、发送数据测试

下面用一段代码来实验下,代码如下:

from socket import *

udp_socket = socket(AF_INET, SOCK_DGRAM) #创建套接字
dest_addr = ('192.168.218.133', 8080)  

send_data = input("请输入要发送的数据:") # 这里获取要发送的数据
udp_socket.sendto(send_data.encode('utf-8'), dest_addr) # 数据发送
udp_socket.close() # 最后关闭

这里我们是当作客户端,那么服务器呢,可以我们在本机上写一个,当然也可以直接就是用现成的,用现成的这里使用网络调试助手就行了,这里我还是推荐VOFA,真是不错的好工具!

VOFA的配置如下所示:
在这里插入图片描述
我们可以开始运行程序,我们输入要发送的数据如下所示:
在这里插入图片描述
可以在VOFA这一端看到我们发送的数据内容(上面的内容是之前实验的时候发送的):
在这里插入图片描述

2、接收数据测试

上面已经测试发送数据,这里接收数据也是一样的,代码如下:

from socket import *

udp_socket = socket(AF_INET, SOCK_DGRAM)
dest_addr = ('192.168.218.133', 8080)

send_data = input("请输入要发送的数据:")
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)


recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数
print(recv_data[0].decode('gbk')) # 接受的内容
print(recv_data[1]) # IP地址还有端口号

udp_socket.close()

3、循环收发测试

服务器这边创建一个套接字之后就绑定端口,之后不断进行轮询接收,接收内容非空就会回应数据了,一秒进行一次
在这里插入图片描述
**客户端这边也是,在创建套接字之后就连接端口,所以,一般来说服务器那边最好是先启动,这样方便客户端找到想要的内容,后面就是打印接收到的数据了,这里也是一秒一下
在这里插入图片描述
连接后如下所示:
在这里插入图片描述
这里注意下,就是上面的代码中有看到encode,decode,还有b’这样的字符,这其实是字符转码的意思,具体说明如下:

str->bytes:encode编码
bytes->str:decode解码

其中b’的作用和encode有点像,就是把字符转成二进制。

5、TCP网络收发数据

1、基本原理和过程

TCP和UDP相似,不过他比UDP在通信的过程上更加严格,这使得TCP更适合在一些传输过程要求更加更加严格的场合使用,TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据。

所以总结来看,TCP就是打电话,是一对一的,UDP是广播,不用管有没有打开收音机去听,都会一直发送数据。

同时,TCP还是一种可靠传输,因为他对传输的要求严格,体现在:

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

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

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

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

通信流程图如下所示:
在这里插入图片描述

2、数据收发示例-客户端

下面进行TCP数据发送的测试,这里首先测试本地程序模拟客户端的情况:

现将我们的VOFA设置为TCP服务端的模式
在这里插入图片描述
本地的代码如下所示:

from socket import *

tcp_client_socket = socket(AF_INET, SOCK_STREAM)

tcp_client_socket.connect(('192.168.218.133', 5555))
send_data = input("请输入要发送的数据:")

tcp_client_socket.send(send_data.encode("utf-8"))
recvData = tcp_client_socket.recv(1024)
print('接收到的数据为:', recvData.decode('utf-8'))


tcp_client_socket.close()

运行之后可以看到连接数量,同时我们发送过去还有返回的数据
在这里插入图片描述
可以看到程序这边打印返回的结果
在这里插入图片描述

2、数据收发示例-服务器

下面进行TCP数据发送的测试,这里测试本地程序模拟服务器的情况:

现将我们的VOFA设置为TCP客户端的模式
在这里插入图片描述
使用的测试代码如下所示

from socket import *

tcp_server_socket = socket(AF_INET, SOCK_STREAM)
address = ('192.168.218.133', 7788)
tcp_server_socket.bind(address)
tcp_server_socket.listen(128)

client_socket, clientAddr = tcp_server_socket.accept()
recv_data = client_socket.recv(1024)
print('接收到的数据为:', recv_data.decode('gbk'))
client_socket.send("thank you !".encode('gbk'))
client_socket.close()

可以看到打开客户端后,收到数据就结束了,因为我们那边也只运行了一次就关闭了
在这里插入图片描述
这边打印出我们接收到的数据,为默认的一个握手数据
在这里插入图片描述
好的,这次就介绍到这里,后面还将继续分享相关内容!


http://www.niftyadmin.cn/n/980107.html

相关文章

再来写一个随机数解决方案,对Random再来一次封装

本文提供对Random的封装&#xff0c;简化并扩展了其功能 获取随机数&#xff0c;确保同时调用不会重复 //new Random().Next(5);RandomTask.Next(5); 从一个列表中&#xff0c;随机获取其中某个值 List<string> lsTest new List<string>{"1","2&qu…

xxx was built without full bitcode 编译错误解决

"xxx was built without full bitcode" 编译错误解决 &#xff08;1466&#xff09; &#xff08;0&#xff09; 举报 收藏 iOS 打包上线 All object files and libraries for bitcode must be generated from...报错: 那么bitcode 是神马:Distribution Guide–Ap…

Python多线程记录

文章目录1、多线程的意义及理解2、python使用多线程3、多线程使用过程中的全局变量共享问题1、全局变量使用及问题2、使用同步的方法来解决问题最近需要用到多线程相关的内容&#xff0c;因此这里记录下 1、多线程的意义及理解 我们一般而言肯定是不希望我们强大的电脑一段时间…

1.16 Linux机器相互登录

Linux机器相互登录使用 ssh 192.168.133.132 可以直接连另一台主机&#xff0c;可以使用 w命令查看连接情况&#xff0c;但这样并不安全&#xff0c;也不方便&#xff0c;每次都需要输入密码所以就使用密钥访问登录&#xff0c;安全性也会提高&#xff0c;同时也会方便很多使用…

1133. Splitting A Linked List (25)(结构体)

Splitting A Linked List (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given a singly linked list, you are supposed to rearrange its elements so that all the negative values appear before all of the …

TCP/UDP记录-聊天器

文章目录1、UI设计2、功能设计3、通信设计4、最终效果本文是接着之前的文章写的后续&#xff0c;因此如果有什么看不太明白的可以先看下前面的文章&#xff1a;TCP通信与UDP通信记录 1、UI设计 前面记录了UDP和TCP进行通信的基本原理和方式&#xff0c;本文就继续来进行一些应…

Android UI线程

在开发Android应用时必须遵守单线程模型的原则&#xff1a; Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则&#xff1a;1. 不要阻塞UI线程2. 确保只在UI线程中访问Android UI工具包当一个程序第一次启动时&#xff0c;Andr…

EPLAN Electric P8 2.0即将到来,着实令人期待-转caodaping

在今年的4月份,2.0版本的EPLAN Electric P8 首次揭开其神秘面纱,见诸于世.它的展露,再次印证了EPLAN 软件平台朝着"更实用"这一方向发展,同时也证明"可靠性"这个长期的话题--符合新的机械指令(译注:指IEC 61346等标准近期做了大量更新,EPLAN 软件相关主数据…