热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python学习笔记(七)

1.网络七层模型及主要协议2.TCP的“三次握手”和四次挥手三次握手Step1:首先客户端向服务器端发送一段TCP报文;Step2:服务器端接收到来自客户端的TCP报文之

Python 学习笔记(七)-

1.网络七层模型及主要协议

2.TCP的“三次握手”和四次挥手

三次握手

Step1:首先客户端向服务器端发送一段TCP报文;

Step 2:服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段,并返回一段TCP报文;

Step 3:客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段,并返回最后一段TCP报文。

此后客户端和服务器端进行正常的数据传输。

四次挥手

 

Step 1:首先客户端想要释放连接,向服务器端发送一段TCP报文;

Step 2:服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文;

Step 3:服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文;

Step 4:客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文。

服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。

3.socket

socket(简称 套接字)是进程间通信的一种方式,它与其它进程间通信的一个主要不同是:socket 可以实现不同机器间的进程通信。

下面是简单的Case,帮助理解。

 客户端

from socket import socket, AF_INET, SOCK_STREAM

##表示创建一个客户端的socket

client = socket(AF_INET, SOCK_STREAM) ##SOCK_STREAM --表示TCP; SOCK_DGRAM--表示UDP;

##定义一个连接的目标

con_address = ("IP地址",端口号)

##告诉客户端要连接的服务器的地址和端口号

client.connect(con_address)

##发送data

client.send("python学习笔记".encode("utf-8"))

##关闭
socket.close()

 服务端,创建socket服务器

from socket import socket, AF_INET, SOCK_STREAM
##创建一个socket对象
server = socket(AF_INET, SOCK_STREAM)

##绑定端口号
server.bind("",端口号) ##第一个参数为空字符串时,表示本机的IP

##开启监听状态
server.listen(5)  ###参数为整型,表示消息可堆积的数量。

while true:
  socket, addr_info = server.accept() ##阻塞的,表示没有连接的时候,一直等待。返回值为socket 和 addr_info。wait for an incoming connection. Return a new socket representing the connection, and the address of the client. For IP sockets ,the address info is a pair (hostaddr,port).
  
  ##打印下
  print(socket, addr_info)
  
  ##读取接受到的信息
  recv_data = socket.recv(512).decode("utf-8")  ##512是我们定义的bufsize.这个方法返回的是bytes。
  print("{}发送过来的消息是:{}" .format(addr_info[0] , recv_data))

  ##关闭
  socket.close()

4.客户端+服务器 交互通信(单信息交叉)

客户端

from socket import socket, AF_INET, SOCK_STREAM

##表示创建一个客户端的socket

client = socket(AF_INET, SOCK_STREAM) ##SOCK_STREAM --表示TCP; SOCK_DGRAM--表示UDP;

##定义一个连接的目标

con_address = ("IP地址",端口号)

##告诉客户端要连接的服务器的地址和端口号

client.connect(con_address)
while True:
  msg = input("客户端输入:")
  client.send(msg.encode("utf-8"))
  if msg == "byebye":
    break
  ##接受服务器端的msg
  recv_data = socket.recv(512).decode("utf-8")  ##512是我们定义的bufsize.这个方法返回的是bytes。
  print("服务器端发送过来的消息是:{}" .format(recv_data))
  if recv_data == "byebye":
    break
##关闭
socket.close()

服务端

from socket import socket, AF_INET, SOCK_STREAM
##创建一个socket对象
server = socket(AF_INET, SOCK_STREAM)

##绑定端口号
server.bind("",端口号) ##第一个参数为空字符串时,表示本机的IP

##开启监听状态
server.listen(5)  ###参数为整型,表示消息可堆积的数量。

while True:
  socket, addr_info = server.accept() ##阻塞的,
  while True: ###保证可以对多个客户端,不能因为一个客户端,关闭所有。
    ##读取接受到的信息
    recv_data = socket.recv(512).decode("utf-8")  
    print("客户端发送过来的消息是:{}" .format(recv_data))
    if recv_data == "byebye":  ##如果客户端说byebye,就退出
      break
    msg = input("服务器端输入:")
    socket.send(msg.encode("utf-8"))
    if msg == "byebye" : ##如果我们说了byebye,退出
      break  
  ##关闭
  socket.close()
  print(addr_info,"离开了!")

5.借助线程,一方可以发送多个消息

即客户端与服务端之间的通信不必要限制为一来一回,一问一答

服务端

##服务器端,创建socket服务器

from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
##创建一个socket对象
server = socket(AF_INET, SOCK_STREAM)

##绑定端口号
server.bind("",端口号)##第一个参数为空字符串时,表示本机的IP

##开启监听状态
server.listen(5)  ###参数为整型,表示消息可堆积的数量

##任务
def send_msg(socket)
  while True:
    msg = input("输入要发送的消息:")
    socket.send(msg.encode("utf-8"))

def recv_msg(socket)
  while Ture:##可以持续收消息
    data=socket.recv(512).decode("utf-8")
    if len(data)==0:
      break
    print("收到客户端的消息是",data)

while True:
  socket, addr_info = server.accept() ##阻塞的
  t_send = Thread(target=send_msg, args=(socket,))
  t_recv = Thread(target=recv_msg, args=(socket,))
  t_send.start()
  t_recv.start()

客户端

from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
##表示创建一个客户端的socket

client = socket(AF_INET, SOCK_STREAM) ##SOCK_STREAM --表示TCP; SOCK_DGRAM--表示UDP;

##定义一个连接的目标

con_address = ("IP地址",端口号)

##告诉客户端要连接的服务器的地址和端口号

client.connect(con_address)


##任务
def send_msg(socket)
  while True:
    msg = input("输入要发送的消息:")
    socket.send(msg.encode("utf-8"))

def recv_msg(socket)
  while Ture:##可以持续收消息
    data=socket.recv(512).decode("utf-8")
    if len(data)==0:
      break
    print("收到服务器端的消息是",data)


t_send = Thread(target=send_msg, args=(client,))
t_recv = Thread(target=recv_msg, args=(client,))
t_send.start()
t_recv.start()

 6.web客户端访问

不写专门的客户端,借助web进行访问,并且支持多个web同时访问(通过协程实现)。

web Server 的代码(服务端)

"""
cilent:浏览器客户端
浏览器发出请求(request),Server端返回响应(response)。
request 包含:request 行(里面有请求方法--get,协议--HTTP/1.1)、请求头【键值对】、请求体(POST请求时的数据)。
response 包含:response 行(里面有协议--HTTP/1.1,状态--例如200 ok)、响应头【键值对】、响应体(数据)。
"""


##服务器端,创建socket服务器
import gevent   ##导入协程的包
import gevent import monkey
##注意此时的socket 一定要来自gevent 的包,进行了继承和封装
##from socket import socket, AF_INET, SOCK_STREAM
from gevent import socket
from threading import Thread

monkey.patch_all()  

##创建一个socket对象
server = socket.socket()

##绑定端口号
server.bind("",端口号)---第一个参数为空字符串时,表示本机的IP

##开启监听状态
server.listen(5)  ###参数为整型,表示消息可堆积的数量

##处理客户端的访问
def handle_client(socket)
  recv_data = socket.recv(512).decode("utf-8")
  print(recv_data)

  ##每次访问返回的信息是
  
  msg ="欢迎来此访问!"
  ##格式化response,需要有响应行、响应头
  resp_line = "HTTP/1.1 200 OK
" ##
格式有换行要求
  resp_header = "Content-Type:text/html
charset=utf-8
Server:testServer
" 

  resp=  resp_line + resp_header +"
"+msg  ##拼凑完整的返回体。注意返回体结束结尾需是两个换行,添加一个

  socket.send(resp.encode("utf-8"))
  socket.colse() ##聊天结束

while True:
  socket, addr_info = server.accept()  
  print(addr_info,"请求访问!")
  gevent.spawn(handle_cilent,socket)

 7.socket 常用函数和方法的梳理

 

类型 函数或方法 解释

服务端套接字函数

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.TCP/IP协议(一)网络基础知识 网络七层协议

https://www.cnblogs.com/wanghuaijun/p/10092930.html

2.计算机各层网络协议 

https://www.cnblogs.com/weiliuyby/p/8030175.html

3.Python3之socket编程

https://www.cnblogs.com/zhangyingai/p/7097922.html

4.详解 TCP 连接的“ 三次握手 ”与“ 四次挥手 ”

https://baijiahao.baidu.com/s?id=1654225744653405133&wfr=spider&for=pc


推荐阅读
  • 利用 Python Socket 实现 ICMP 协议下的网络通信
    在计算机网络课程的2.1实验中,学生需要通过Python Socket编程实现一种基于ICMP协议的网络通信功能。与操作系统自带的Ping命令类似,该实验要求学生开发一个简化的、非标准的ICMP通信程序,以加深对ICMP协议及其在网络通信中的应用的理解。通过这一实验,学生将掌握如何使用Python Socket库来构建和解析ICMP数据包,并实现基本的网络探测功能。 ... [详细]
  • 本文介绍了如何使用Python的Paramiko库批量更新多台服务器的登录密码。通过示例代码展示了具体实现方法,确保了操作的高效性和安全性。Paramiko库提供了强大的SSH2协议支持,使得远程服务器管理变得更加便捷。此外,文章还详细说明了代码的各个部分,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • C#中实现高效UDP数据传输技术
    C#中实现高效UDP数据传输技术 ... [详细]
  • 本文介绍了 Python 中的基本数据类型,包括不可变数据类型(数字、字符串、元组)和可变数据类型(列表、字典、集合),并详细解释了每种数据类型的使用方法和常见操作。 ... [详细]
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • 机器学习算法:SVM(支持向量机)
    SVM算法(SupportVectorMachine,支持向量机)的核心思想有2点:1、如果数据线性可分,那么基于最大间隔的方式来确定超平面,以确保全局最优, ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 深入理解Linux网络编程:UDP协议实战解析
    深入理解Linux网络编程:UDP协议实战解析 ... [详细]
author-avatar
小猪jieao_229
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有