zoukankan      html  css  js  c++  java
  • 2.socket编程

    套接字:进行网络通信的一种手段socket
    1.流式套接字(SOCK_STREAM):传输层基于tcp协议进行通信
    2.数据报套接字(SOCK_DGRAM):传输层基于udp协议进行通信
    3.原始套接字(SOCK_RAW):访问底层协议的套接字
    套接字编程:
    1.TCP服务端()
    0.导入socket模块
    from socket import *
    1.创建套接字
    socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0)
    功能:创建套接字
    参数:socket_family:选择地址族种类 AF_INET(UNIX)
    socket_type:套接字类型 SOCK_STREAM(流式套接字)
    SOCK_DGRAM(数据报套接字)
    proto:子协议类型默认为0
    返回值:返回创建的套接字
    2.绑定IP和端口号(上一步返回套接字对象名为sockfd)
    sockfd.bind()
    功能:绑定IP和端口
    参数:是一个元组,第一项是字符串形式的IP,第二项是端口号,示例("192.168.1.2",8888)
    返回值:无
    3.让套接字具有监听功能
    sockfd.listen(n)
    功能:是套接字变为监听套接字,同时创建监听队列
    参数:n 监听队列大小(n在linux下不起作用)
    返回值:无
    4.等待客户端连接
    sockfd.accept()
    功能:阻塞等待客户端连接
    参数:无
    返回值:1.返回一个客户端专属的新套接字用来和客户端通信
    2.返回连接的客户端地址
    示例:connfd,addr = sockfd.accept()
    5.消息的收发(用上一步返回的新套接字connfd)
    1.recv(buffer)
    功能:接收消息
    参数:一次接收消息的大小,单位:字节
    返回值:返回接收到的内容
    示例:connfd.recv(1024)
    2.send(data)
    功能:发送消息
    参数:发送的内容(发送byte格式的)
    返回值:发送了多少字节(整数)
    示例:connfd.send(b"你好,客户端--服务端发送");
    3.sendall()
    功能:同send
    返回值:发送成功返回none,失败产生异常

    注意:当没有接收端的时候,send操作会导致broken pipe

    6.关闭套接字
    close()
    功能:关闭套接字(所有套接字都要关闭)
    示例:sockfd.close()
    connfd.close()

    2.TCP客户端流程
    1.创建流式套接字
    2.发起连接请求
    connect()
    功能:发起连接
    参数:元组 (1.服务器ip,2.port)
    返回值:无
    3.收发消息
    4.关闭套接字

    3.示例
    #tcp测试服务端 my_tcp_server.py
    from socket import *
    # 创建连接
    sockfd = socket(AF_INET,SOCK_STREAM)
    #绑定ip和端口号
    sockfd.bind(("0.0.0.0",18888))
    #设置监听套接字
    sockfd.listen(10)
    while True:
    #等待连接
    print("waiting for connect...")
    connfd,addr = sockfd.accept()
    print("connect from",addr)
    #收发消息
    while True:
    cli_msg = connfd.recv(5)
    if not cli_msg:
    break
    print(cli_msg.decode())
    serv_msg = input("服务端消息>")
    connfd.send(serv_msg.encode())
    connfd.close()

    sockfd.close()
    =========================================
    #TCP测试客户端 my_tcp_clinet.py
    from socket import *

    sockfd = socket(AF_INET,SOCK_STREAM)
    sockfd.connect(("192.168.1.4",18888))
    while True:
    cli_msg = input("客户端消息>")
    if not cli_msg:
    break
    sockfd.send(cli_msg.encode())
    serv_msg = sockfd.recv(1024)
    print(serv_msg.decode())

    sockfd.close()

    4.UDP通信
    1.创建数据报套接字
    sockfd = socket(AF_INET,SOCK_DGRAM)
    2.绑定服务端地址
    ipaddr = ("192.168.1.4",18888)
    sockfd.bind(addr)
    3.收发消息
    1. data,addr = sockfd.recvfrom(buffersize)
    功能:接收数据报套接字消息
    参数:每次最多接收消息的大小 字节
    返回值:data: 接收到的消息
    addr:消息发送者的地址
    注意:一次接收一个数据包,如果数据包一次没有接收完则会丢失没接收的内容
    2. sockfd.sendto(data,addr)
    功能:发送消息
    参数: data 要发送的消息
    addr 发送给某个主机的地址
    返回值:发送消息的字节数
    4.关闭套接字
    sockfd.close()
    5.示例:
    #UDP测试服务端 udp_server.py
    from socket import *
    import sys
    from time import ctime
    #从命令行传入参数
    #python3 udp_server.py 192.168.1.4 18888
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])
    ADDR = (HOST,PORT)
    BUFFERSIZE = 1024

    #创建数据报套接字
    sockfd = socket(AF_INET,SOCK_DGRAM)
    #绑定地址
    sockfd.bind(ADDR)
    print("udp已启动...")
    #收发消息
    while True:
    data,addr = sockfd.recvfrom(BUFFERSIZE)
    print("recv from %s : %s" % (addr,data.decode()))
    sockfd.sendto(f"{ctime()} 接收到 {addr} 的消息".encode(),addr )

    sockfd.close()
    =============================================
    #udp测试客户端 udp_client.py
    from socket import *
    import sys
    from time import ctime
    #从命令行传入参数
    #python3 udp_client.py 192.168.1.4 18888
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])
    ADDR = (HOST,PORT)
    BUFFERSIZE = 1024
    sockfd = socket(AF_INET,SOCK_DGRAM)

    while True:
    msg = input("发往服务端数据>>")
    if not msg:
    break
    sockfd.sendto(msg.encode(),ADDR)
    data,addr = sockfd.recvfrom(BUFFERSIZE)
    print("从服务端收到:",data.decode())

    sockfd.close()

    套接字属性:
    1.创建套接字
    s = socket.socket() #示例创建流式套接字,使用默认参数
    2.属性:
    1. s.fileno()
    功能:获取套接字的描述符
    *描述符:每一个IO操作系统都会分配一个不同的整数与之对应,该整数即为此IO操作的描述符
    返回值:整数
    2. s.type (属性):套接字的类型
    3. s.getsockname()
    功能:获取套接字bind以后绑定的地址
    返回值:元组,("ip",port)
    4. conn.getpeername()
    功能:使用s.accept生成的conn套接字调用,获取该套接字对应客户端的地址
    返回值:元组,("ip",port)
    5. s.setsockopt(level,optname,value)
    功能:设置套接字选项
    参数: level: 要定义的选项类型
    常用的可选值: IPPROTO_TCP IPPROTP_IP SOL_SOCKET(这个最常用)
    optname:根据level确定的子选项
    value: 根据选项设置的值
    * 选项太多,应用时需要参考手册
    示例: s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    设置服务器程序结束之后,端口号可以立马被重用
    s.getsockopt(level,optname)
    功能:获取套接字选项
    参数:同setsockopt
    返回值:返回相应选项的值

    应用:
    1.udp应用之广播(要将套接字设置为允许接收广播)
    功能:将消息发送给局域网内所有终端,所以需要发送到.255地址来广播
    示例:
    #广播测试发送端 broadcast_send.py
    from socket import *
    from time import sleep
    # "192.168.1.255" 可以用 <broadcast> 代替
    dest = ("192.168.1.255",19999)
    s= socket(AF_INET,SOCK_DGRAM)
    s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
    print("发送端已运行...")
    while True:
    sleep(1)
    s.sendto("坚决拥护张大大".encode(),dest)
    data,addr = s.recvfrom(1024)
    print(f"从{addr}接收到:{data.decode()}")
    s.close()
    ===================================
    #广播测试接收端 broadcast_recv.py
    from socket import *
    HOST = ""
    PORT = 19999
    #create socket
    s = socket(AF_INET,SOCK_DGRAM)
    # set socket can receive broadcast
    s.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
    #绑定接收端的端口号
    s.bind((HOST,PORT))
    print("接收端已运行.....")
    while True:
    try:
    message,addr = s.recvfrom(4096)
    print(f"从{addr}获取信息:{message.decode()}")
    s.sendto(b"I am here",addr)
    except Exception as e:
    print(e)
    s.close()
    注意:
    广播风暴:在一个网络中大量发送广播会占用大量带宽

    2.TCP应用之 http传输
    1.http协议(超文本传输协议)
    1.客户端(浏览器)发起http请求
    2.传输层使用TCP协议建立连接,层层打包将请求内容发送给服务器
    3.web服务器解包后解析http请求,交给后端应用程序处理
    4.后端应用得到结果,通过web服务器回发给前端
    2.用途:网站中网页的传输和数据传输,也可用作基于http协议的编程传输数据
    3.特点:
    1.应用层协议,传输层用tcp连接,简单,灵活,连接使用方便
    2.几乎支持所有的数据类型
    3.是无状态的
    4.持续连接

    4.步骤
    请求(request)
    格式:
    请求行:确定具体的请求类型
    请求头:对请求内容的信息描述
    空行
    请求体:具体的请求参数
    详细:
    请求行:GET /index.html HTTP/1.1
    请求方法 请求资源 协议版本
    请求方法:
    GET 获取网络资源
    POST 提交一定的附加数据,得到返回结果
    HEAD 获取响应的头信息
    PUT 更新服务器资源
    DELETE 删除服务器资源
    TRACE 用于测试
    CONNECT 保留方法
    OPTIONS 请求获取服务器性能和信息
    *一般只用GET和POST
    请求头:很多内容
    请求体:
    get请求:get参数 示例:&a=1&b=2
    post请求:post内容
    响应(response)
    格式:
    响应行:反馈响应的情况
    响应头:对响应的具体描述
    空行
    响应体:具体返回给用户的内容
    详细:
    响应行:HTTP/1.1 200 OK
    协议版本 响应码 信息
    响应码:
    1xx:提示信息,表示请求已经接收,正在处理
    2xx:请求响应成功
    3xx:重定向,完成任务需要的其他操作
    4xx:客户端错误
    5xx:服务端错误
    示例:
    200 成功
    401 没有访问权限
    404 资源不存在
    500 服务器发生未知错误
    503 服务器暂时无法执行
    响应头:同请求头
    响应体:文件,图片....

    TCP应用
    1.http服务器
    1.接收http请求
    2.给出一定的响应
    2.示例
    #简单的http服务器示例 HttpServer.py
    #静态网页处理
    #采用循环模式,无法满足客户端长连接

    from socket import *
    HOST = "0.0.0.0"
    PORT = 15555

    #处理客户端请求
    def handleClient(conn):
    request = conn.recv(4096)
    requestHeadlers = request.splitlines()
    for line in requestHeadlers:
    print(line)
    try:
    f = open("django.html","r",encoding="utf8")
    except IOError:
    response = "HTTP/1.1 404 not found "
    response += " "
    response += "=====sorry,file not find"
    else:
    response = "HTTP/1.1 200 ok "
    response += " "
    print(response)
    for i in f:
    response += i
    finally:
    conn.send(response.encode())
    f.close()
    print("任务完成")
    #流程控制
    def main():
    s = socket()
    s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    s.bind((HOST,PORT))
    s.listen(10)
    while True:
    conn,addr = s.accept()
    handleClient(conn)
    if __name__ == "__main__":
    main()


    IO操作:在内存中存在数据交换的操作
    1.定义
    1.内存和磁盘交换: 文件读写 打印
    2.内存和网络交换: 上传,下载等
    2.程序分类
    1.IO密集型
    程序中执行大量的IO操作,而较少需要cpu运算:消耗cpu资源少,运行周期往往较长
    2.CPU密集型程序
    程序执行中需要大量的cpu运算,IO操作比较少:占用cpu多
    3.IO分类(阻塞:1.等待某种条件达成再继续运行 2.处理IO事件的耗时较长也会产生阻塞)
    1.阻塞IO:默认就是阻塞IO,效率最低的一种IO
    2.非阻塞IO:通过修改IO对象使其变为非阻塞状态(改变第一种阻塞形态)
    特点:通常用循环不断判断阻塞条件,需要消耗更多cpu,但是一定程度上提高了IO效率
    s.setblocking()
    功能:将套接字设置为非阻塞状态
    参数:bool 默认为True,设置为False则为非阻塞
    用法:用循环配合判断阻塞状态

    超时等待(检测):对原本阻塞的函数进行设置,使其不再始终阻塞,而是阻塞等待一定
    时间后自动返回,在规定时间中如果正常结束阻塞则继续执行,负责将产生timeout异常
    s.settimeout(sec)
    功能:设置套接字的超时检测
    参数:超时时间(秒)
    注意:套接字超时检测是用settimeout,还有其他的超时检测是由参数设定的,如select,join,wait等
    3.IO多路复用
    1.定义:同时监控多个IO事件,当哪个IO事件准备就绪就执行哪个IO事件,形成并发效果
    2.select模块(import select)
    1.方法
    1.select #支持win,linux,unix
    1.原型:r,w,x = select(rlist,wlist,xlist,[timeout])
    2.功能:监控IO事件,阻塞等待IO事件发生
    3.参数:
    1.rlist:列表 存放监控的等待处理的IO
    2.wlist:列表 存放我们希望主动处理的IO
    3.xlist:列表 存放如果发生异常需要处理的IO
    4.timeout:数字 超时检测 可选参数,默认一直阻塞
    4.返回值:
    1.r:返回列表 rlist中准备就绪的IO
    2.w:返回列表 wlist中准备就绪的IO
    3.x:返回列表 xlist中准备就绪的IO
    (乱七八糟,待用时再细看)2.poll #支持linux,unix
    1.步骤:
    1.创建poll对象:p=select.poll()
    2.加入关注IO:p.register(s)
    p.unregister(s) 从监控列表中删除
    3.使用poll函数监控:events = p.poll()
    功能:阻塞等待register的时间只要有任意准备就绪即返回
    返回值:列表 events = [(fileno,evnet),(),()]
    4.判断发生事件:s & POLLIN
    5.处理发生的IO事件
    2.poll 常用io事件(EVENTS)
    1.POLLIN:相当于rlist
    2.POLLOUT:相当于wlist
    3.POLLUP:断开连接
    4.POLLERR:相当于xlist
    5.POLLPRI:紧急处理
    6.POLLVAL:无效数据
    3.epoll #支持linux,unix
    1.特点
    1.效率上比poll和select稍微高一点
    2.只能用于linux,unix
    3.支持边缘触发,select和poll只支持水平触发
    3.注意点:
    1.在处理IO过程中,不应发生死循环(某个IO单独占有服务器)
    2.IO多路复用是单进程程序,是一个并发程序
    3.IO多路复用有较高的IO执行效率

    4.事件驱动IO
    5.异步IO

    本地套接字
    1.linux文件种类
    1. b 块设备文件
    2. c 字符设备文件
    3. d 文件夹
    4. - 普通文件
    5. l 连接文件
    6. s 套接字文件
    7. p 管道文件
    2.本地套接字
    1.意义:在linux/unix操作系统下,提供本地进程间通信的一种方式
    2.创建流程:
    1.创建套接字文件
    2.绑定套接字文件
    3.监听
    4.接收连接
    5.消息收发


    知识点
    1.发送接收缓冲区
    1.发送和接收消息均线放到缓冲区再进行处理
    2.recv接收消息,当一次接收不完的时候,下次会继续接收
    3.当recv阻塞时,如果客户端断开,则recv立即返回空字符串

    2.TCP粘包处理
    1.定义:TCP中数据以数据流的方式发送接收,每次发送的数据间没有边界,在接收时可能造成数据的粘连即为粘包
    2.处理:
    1.每次发送消息结束为止加标志
    2.发送的消息添加结构描述
    3.当连续发送时每次发送有一个短暂延迟 sleep(0.1)

    3.argv命令行传参
    import sys
    1.传入的参数都是字符串
    2.空格分隔各个参数
    3.sys.argv 自动收集命令行内容为一个列表,返回一个列表,第一个元素是命令本身
    4.如果要使用本身带空格的参数,可以把参数用""括起来

    4.TCP和UDP的区别
    1.TCP传输数据使用字节流的方式传输,UDP是数据包
    2.TCP会产生粘包现象,UDP不会
    3.TCP对网络条件要求高,UDP更适合实时传输
    4.TCP可以保证传输的可靠性,UDP则不保证
    5.TCP使用listen accept保证连接性,UDP不需要
    6.TCP收发消息使用recv send sendall,udp使用recvfrom sendto

    5.模块中的属性名字含义(dir(模块名)
    1.全部大写的名字:一般为变量,常量,标示量
    2.前后带__的名字:内置方法
    3.大驼峰的名字:模块里的类
    4.全部小写:模块中的方法或属性

    6.更专业的打印异常信息
    import traceback
    捕获后:
    trancback.print_exc()

    7.os.unlink("路径") or os.remove("路径")
    功能:删除某个文件
    参数:路径
    os.path.exists("路径")
    功能:判断一个文件是否存在
    参数:路径
    返回值:bool
  • 相关阅读:
    104. 二叉树的最大深度
    1120. 子树的最大平均值
    1121. 将数组分成几个递增序列
    1118. 一月有多少天
    1110. 删点成林
    102. 二叉树的层次遍历
    145. 二叉树的后序遍历
    94. 二叉树的中序遍历
    144. 二叉树的前序遍历
    剑指offer-0x04
  • 原文地址:https://www.cnblogs.com/huohu121/p/12319812.html
Copyright © 2011-2022 走看看