文章目录

  • TCP与UDP协议
    • TCP协议
      • ==三次握手==
      • ==四次挥手==
    • UDP协议
    • TCP与UDP的区别
  • 应用层
  • socket套接字
  • 代码优化
    • 循环通信
  • 半连接池
  • 粘包问题

TCP与UDP协议

  • 本质

    规定了数据传输所遵循的规则
    ps:数据传输能够遵循的协议有很多,TCP和UDP是较为常见的两个
    

TCP协议

TCP是一种面向广域网的通信协议,目的是在跨越多个网络通信时,为两个通信端点之间提供一条通信方式

三次握手

建立双向通道,中间的 FIN 和 ACK 能合并在一起
ps:洪水攻击(同时让大量的客户端朝服务端建立TCP连接的请求,容易出现状况)

第一次握手:客户端将标志位SYN设置为1,并且随机产生一个值seq=x,并且将该数据包发送给服务器,此刻客户端进入等待状态,等待服务器的确认
第二次握手:服务器接收到数据包之后,标志位是SYN=1,可以知道客户端请求连接,服务端如果同意创建连接,此刻SYN ACK都设置为1,并且ack=x+1,随机产生一个值seq=y,传递给客户端
第三次握手:客户端接收到确认之后,检查ack是否是x+1,ACK是否是1,如果都是正确的,会将标志位ACK设置为1,确认号ack设置为y+1,发送给服务端

四次挥手

断开双向通道
双方各自向对方发起建立连接的请求,再各自给对方回应,只不过,中间的 FIN 和 ACK 不一定能合并在一起

第一次挥手:客户端发送标识位FIN,用来关闭客户端到服务端的连接
第二次挥手:服务器接收到客户端发送的FIN之后,先发送ACK,ack,seq给客户端
第三次挥手:服务器发送FIN给客户端,用来关闭服务器和客户端的数据传送
第四次挥手:客户端接收到FIN之后,发送ACK,ack给服务端
注意:TCP链接是全双工的 ,全双工同时可以在2个方向上传输数据

类似于打电话的一个过程:

UDP协议

  • 本质

    基于UDP协议发送数据,没有任何的通道也没有任何的限制,提供面向交易的简单和不可靠的信息传输服务

  • 作用

    主要用于支持需要在计算机之间传输数据的网络应用

TCP与UDP的区别

1.UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同
2.TCP 是面向连接的传输控制协议,而UDP 提供了无连接的数据报服务;
3.TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;UDP 在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序;
4.UDP 具有较好的实时性,工作效率较 TCP 协议高;UDP 段结构比 TCP 的段结构简单

应用层

1.应用层的目的:
  
  应用层对应用程序的通信提供服务。

2.应用层重要协议:
  
  FTP、SMTP和POP3、HTTP、DNS。

3.应用层的功能:

① 文件传输。访问和管理。
② 电子邮件。
③ 虚拟终端。
④ 查询服务和远程作业登录。

socket套接字

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

基于文件类型的套接字家族套接字家族的名字:AF_UNIX
基于网络类型的套接字家族套接字家族的名字:AF_INET

理解图:

运行程序的时候 肯定是先确保服务端运行 之后才是客户端

服务端:

import socket
# 1.创建一个socket对象
server = socket.socket()  # 括号内什么都不写 默认就是基于网络的TCP套接字
# 2.绑定一个固定的地址(ip\port)
server.bind(('127.0.0.1', 8080))  # 127.0.0.1本地回环地址(只允许自己的机器访问)
# 3.半连接池(暂且忽略)
server.listen(5)
# 4.开业 等待接客
sock, address = server.accept()
print(sock, address)  # sock是双向通道 address是客户端地址
# 5.数据交互
sock.send(b'hello big baby~')  # 朝客户端发送数据
data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
print(data)
# 6.断开连接
sock.close()  # 断链接
server.close()  # 关机

客户端:

import socket
# 1.产生一个socket对象
client = socket.socket()
# 2.连接服务端(拼接服务端的ip和port)
client.connect(('127.0.0.1', 8080))
# 3.数据交互
data = client.recv(1024)  # 接收服务端发送的数据
print(data)
client.send(b'hello sweet server')  # 朝服务端发送数据
# 4.关闭
client.close()
  • 服务端套接字函数
    s.bind() 绑定(主机,端口号)到套接字
    s.listen() 开始TCP监听
    s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

  • 客户端套接字函数
    s.connect() 主动初始化TCP服务器连接
    s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

  • 公共用途的套接字函数
    s.recv() 接收TCP数据
    s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
    s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余

  • 空间时,数据不丢失,循环调用send直到发完)
    s.recvfrom() 接收UDP数据
    s.sendto() 发送UDP数据
    s.getpeername() 连接到当前套接字的远端的地址
    s.getsockname() 当前套接字的地址
    s.getsockopt() 返回指定套接字的参数
    s.setsockopt() 设置指定套接字的参数
    s.close() 关闭套接字

  • 面向锁的套接字方法
    s.setblocking() 设置套接字的阻塞与非阻塞模式
    s.settimeout() 设置阻塞套接字操作的超时时间
    s.gettimeout() 得到阻塞套接字操作的超时时间

  • 面向文件的套接字的函数
    s.fileno() 套接字的文件描述符
    s.makefile() 创建一个与该套接字相关的文件

代码优化

循环通信

  • 引言

    主要用来打破信息只能传输一次的问题

  • 方法

    1.先解决消息固定的问题
    解决办法:利用input获取用户输入
    2.再解决通信循环的问题
    解决方法:将双方用于数据交互的代码循环起来

    代码实现

    while True:data = sock.recv(1024)  # 听别人说话print(data.decode('utf8'))msg = input('请回复消息>>>:').strip()sock.send(msg.encode('utf8'))  # 回复别人说的话while True:msg = input('请输入你需要发送的消息>>>:').strip()client.send(msg.encode('utf8'))  # 给服务端发送消息data = client.recv(1024)  # 接收服务端回复的消息print(data.decode('utf8'))
    
  • 输入的消息不能为空(主要是针对客户端)

    解决方法:判断是否为空,为空则重新输入
    
  • 服务端能够持续提供服务

    需求:不会因为客户端断开连接而报错
    解决方法:异常捕获 一旦客户端断开连接 服务端结束通信循环 调到连接处等待
    

半连接池

1.什么是半连接池:

当服务器在响应了客户端的第一次请求后会进入等待状态,会等客户端发送的ack信息,这时候这个连接就称之为半连接

2.本质

半连接池其实就是一个容器,系统会自动将半连接放入这个容器中,可以避免半连接过多而保证资源耗光

3.产生半连接的两种情况:

客户端无法返回ACK信息
服务器来不及处理客户端的连接请求

粘包问题

问题:

我们知道tcp容易产生黏包的问题,而udp不会产生黏包的问题,但是会产生丢包的问题,tcp应用的场景很多所以黏包问题必须要解决。(传输信息字节大小和允许接收信息字节大小的问题)

1.TCP特性

流式协议:所有的数据类似于水流 连接在一起的
ps:数据量很小 并且时间间隔很多 那么就会自动组织到一起

2.recv

我们不知道即将要接收的数据量多大 如果知道的话不会产生也不会产生黏包
  • 解决方法一

    1.解决黏包问题第一种方法,我们知道黏包问题是由于tcp的优化算法将两个不太大的数据包合并了一起发送的,这种情况一般出现在连续使用几个send()出现的,所以我们如果知道要发送的数据有多大我们就可以设置接收的大小,这样就可以刚好能把所有的数据接收完。下面是具体的步骤细节见代码

这是远程执行cmd命令并返回结果的程序
server端代码
import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
while True:cmd = input('>>>')conn.send(bytes(cmd,encoding='utf-8'))num = conn.recv(1024).decode('utf-8')   #接收client端计算好的数据长度conn.send(bytes('ok',encoding='utf-8'))#发送一个确认防止发送num的时候跟后面的send内容合并了ret = conn.recv(num)print(ret.decode('gbk'))
conn.close()
sk.close()
client端代码
import socket
import struct
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:cmd = sk.recv(1024).decode('utf-8')ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)std_out = ret.stdout.read()std_err = ret.stderr.read()sk.send(bytes(str(len(std_err)+len(std_out)),encoding='utf-8'))#上面计算字符串的长度发送给server端在接收的时候刚好接收那么长的数据sk.recv(1024) #ok  这一步主要的目的是为了将num的发送跟后面的send分割开防止黏包现象sk.send(std_out)sk.send(std_err)
sk.close()

总结:但是有一个问题就是多了一次连接延时要接收一个没有用的数据 ok,如何不需要接收ok就能解决黏包现象呢?这就需要下面这种解决方案.

  • 解决方法二

    2.用struct模块解决黏包现象

server端代码#tcp黏包现象的解决 struct
import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
while True:cmd = input('>>>')conn.send(bytes(cmd,encoding='utf-8'))num = conn.recv(1024)   #接收数据num = struct.unpack('i',num)[0]#进行解包,解包的结果是一个元组类型取第一个数据ret = conn.recv(num)print(ret.decode('gbk'))
conn.close()
sk.close()
client端代码import socket
import struct
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:cmd = sk.recv(1024).decode('utf-8')ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)std_out = ret.stdout.read()std_err = ret.stderr.read()num = len(std_err) + len(std_out)num = struct.pack('i',num)  #利用struct模块将一个数据转换成bytes类型 i代表int型sk.send(num)sk.send(std_out)sk.send(std_err)
sk.close()

总结:
struct模块无论数据长度是多少 都可以帮你打包成固定长度
然后基于该固定长度 还可以反向解析出真实长度
struct模块针对数据量特别大的数字没有办法打包!!!

思路:

服务端

1.先将真实数据的长度制作成固定长度 4
2.先发送固定长度的报头
3.再发送真实数据

客户端

1.先接收固定长度的报头 4
2.再根据报头解压出真实长度
3.根据真实长度接收即可

TCP与UDP协议,socket套接字编程,通信相关操作相关推荐

  1. udp协议没有粘包问题、基于socketserver实现并发的socket(基于tcp、udp协议)、基于udp协议的套接字、操作系统原理以及进程知识

    基于udp协议的套接字通信服务端 from socket import *server=socket(AF_INET,SOCK_DGRAM) #数据报协议->udp server.bind((' ...

  2. 基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

    基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socketserver = socket.socket(socket.AF_INET,socket.S ...

  3. 基于UDP协议的套接字+socketserver模块

    基于UDP协议的套接字 user datagram protocal 数据报协议 无双向通道.自带报头.类似发短信.不会粘包 不可靠:数据发送时,丢就丢了 UDP socket: 服务端: impor ...

  4. 20181225 基于TCP/IP和基于UDP/IP的套接字编程

    一.TCP/IP的套接字编程 服务器端代码: import socket​server = socket.socket() # 默认是基于TCP# 基于TCP的对象serve=socket.socke ...

  5. day26-2 基于TCP协议的套接字编程

    目录 基于TCP协议的套接字编程 套接字 套接字工作流程 基于TCP协议的套接字编程(简单) 服务端 客户端 基于TCP协议的套接字编程(循环) 服务端 客户端1 客户端2 基于TCP协议的套接字编程 ...

  6. 自学Python 58 Socket套接字编程 (一)

    Python Socket套接字编程 (一) 文章目录 Python Socket套接字编程 (一) 一.库 Socket 内置函数和属性 二.Python中的socket通信逻辑   Socket又 ...

  7. TCP与UDP协议、socket套接字编程、通信相关操作(cs架构软件)、TCP黏包问题及解决思路

    OSI七层协议 传输层 1.PORT协议:前面讲过 2.TCP协议与UDP协议:规定了数据传输所遵循的规则(数据传输能够遵循的协议有很多,TCP和UDP是较为常见的两个) TCP协议 基于TCP传输数 ...

  8. 网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字

    socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程 ...

  9. TCP Socket套接字编程 附源码

    TCP 最主要的特点 TCP 是面向连接的运输层协议.应用程序在使用 TCP 协议之前,必须先建立 TCP 连接.在传送数据完毕后,必须释放已经建立的 TCP 连接 每一条 TCP 连接只能有两个端点 ...

最新文章

  1. [译] RabbitMQ tutorials (3) ---- 'Pub/Sub' (Javascript)
  2. 删除有序vector中的重复值c++
  3. mvc php session,PHP Session入门教程
  4. 专访 Swin Transformer 作者胡瀚:面向计算机视觉中的「开放问题」 原创
  5. ttl继承逻辑门的逻辑功能与参数测试 实验总结_LMS电声测试仪,LMS-V测试系统,精声电声...
  6. 为什么有那么多人选择“人工智能”,真的有那么好吗?
  7. 基础算法 —— 高精度计算 —— 高精度乘法
  8. Windows Firewall/Internet Connection Sharing (ICS) 无法启动解决办法
  9. 东大OJ-5到100000000之间的回文质数
  10. python实现将给定列表划分为(等长的/不等长)的元素和大致相等的两个子列表
  11. notepad++中文版下载
  12. python解一元三次方程_利用Python的sympy包求解一元三次方程示例
  13. 一种特殊的魔方阵解法
  14. 2021年饶州中学高考成绩查询,鄱阳饶州中学2019高考成绩喜报、一本二本上线人数情况...
  15. 怎么在contenteditable可编辑的div插入图片
  16. 娑罗双树,半枯半荣,娑罗花开,盛者必衰
  17. 冬天别忘晒太阳[整理]
  18. 微信中禁止网页下拉出现网页由XXX提供
  19. mysql 的一个错误 Error Code: 2013. Lost connection to MySQL server during...
  20. Robcup2D足球学习记录【2020.01.14】

热门文章

  1. pygame的基础知识详解(主窗口创建、图像绘制、时钟对象和事件响应等知识点),请惠存
  2. 英文记忆之拆分联想法
  3. 字符串中包含unicode编码内容转中文打印或输出到txt文件
  4. 嵌入式培训如何学?什么人适合转行嵌入式开发?
  5. Psoc Creator入门——EZI2C 通信
  6. html如何创建邮件链接,如何制作电子邮件链接html
  7. Qt-qmake install相关
  8. 连接到mysql提示错误:The server time zone value is unrecognized or represents more than one time zone
  9. 解决Error creating bean with name ‘redisConnectionFactory‘ defined in class path resource...问题
  10. vue 视频播放(使用vue-video-player)