zoukankan      html  css  js  c++  java
  • Python_socket

    TCP : 可靠传输,不安全,UDP: 安全传输,不可靠

    一台机器上有2^16-1=65535个端口(1-1024)保留自己开就1024往上

     socket (套接字):也可以理解为它是一个管道,用于描述IP地址和端口

    socket是一种特殊的文件:针对服务器端和客户端来 打开(建立链接),读(发送数据),写(接收数据)关闭的模式来实现信息的交换

    一、socket函数

     socket.socket(family,type[, protocol])   默认协议为TCP/IP

    # socket.slcketpair([family,type[,proto]]]):

    # socket.create_connection(address[,timeout[, source_address]])

    参数说明:

    1.family指定应用程序使用的通信协议的协议族

    family参数
    socket.AF_UNIX 只能单一的在Unix系统进行进程通信,一种本地的管道(socket)
    socket.AF_INET IPv4 为TCP/IP协议的默认值,服务器之间的网络通信
    socket.AF_INET6 IPv6

    2.type创建套接字的类型

    type参数
    socket.SOCK_STREAM  流式socket,用于TCP时选用
    socket.SOCK_DGRAM 数据报式socket,用于UDP时选用

    socket.SOCK_RAM

    原始套接字,普通的套接字无法处理ICMP  , IGMP 等网络报文,而SOCK_RAM可以;其次,SOCK_RAM也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCT套接字选项由用户构造IP头。

    socket.SOCK_RDM

    是一种可靠的UDP形式,即可保证交付数据但不保证顺序 ,SOCK_RAM用来提供对原始协议的低级访问,在需要某些特殊操作时使用,如发生ICMP报文,SOCK_RAM通常仅限于高级用户或管理员运行的程序使用.

    3.protocol指明所要接收的协议类型,通常设置为0,系统就会根据地址格式和套接类别自动选择一个合适的协议

    protocol参数

    socket.IPPROTO_TAW 

    相当于protocol=255,此时socket只能用来发送IP包,而不能接收任何的数据,发送的数据需要自己填充IP包头,并且自己计算校验和

    socket.IPPROTO_IP

    相当于protocol=0,此时用于接收任何的IP数据包,其中校验和和协议分析由系统完成

    二、socket内建方法

    服务器端套接字

    sk.bind()

    将套接字绑定地址,address地址的格式取决于地址簇,在AF_INET下,以(host.port )的形式表示地址

    sk.listen(backlog) 

    开始监听传入连接,backlog指定在拒绝连接之前,可以挂起的最大连接数量,等待排队的最多排几个,如:backlog等于5,表示内核已经接到了连接要求,但服务器还没有调用accept进行处理的连接个数,这个值不能无限大,因为要在内核中维护连接队列。

    sk.accept()

    接受TCP客户连接并返回(conn,address),阻塞式等待连接其到来,其中conn是新的套接字对象,可以用来接受和发送数据,address 是客户端的地址。
    客户端套接字
    s.connect() 主动初始化TCP服务器连接,一般address的格式为元组(hostname,port),如果连接出错,则返回socket.error错误
    s.connet_ex() 同上,不过,连接成功是返回0,连接失败是返回错误码,不会抛出异常
    公共用途套接字

    sk.recv(bufsize[,flag])

    接受套接字的数据。数据以字符串的形式返回,bufsize指定最多可接收的数据(一般为8192),flag提供有关消息的其他信息,通常可以忽略
    sk.recvform() 与recv()类似,多用于接受UDP数据,返回值为(data,address),其中data是包含接受数据的字符串,address是发送数据的套接字地址
    sk.send() 发送套接字数据,将string中的数据发送到连接的套接字,返回值是要发送的字节数量,该数据可能小于string的字节大小
    sk.sendall() 完整发送TCP数据,将string中的数据发送到连接的套接字,但返回之前会尝试一次性发送,就是不断的调用send,发送成功返回None,失败则抛出异常
    sk.sendto() 发送UDP数据,将数据发送到套接字,address的形式是(ipaddr,port)的元组,指定远程地址,返回值是发送的字节数
    sk.close() 关闭套接字
    sk.getpeername() 返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)
    sk.getsockname() 返回套接字自己的地址,通常是一个元组(ipaddr,port)
    sk.setsockopt() 设置给定套接字选项的值
    sk.getsockopt() 返回条件字选项的值
    sk.settimeout(timeout)  设置套接字操作的超时期,timeout是一个浮点数,单位为秒,值为None表示没有超时期,一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
    sk.gettimeout() 返回当前超时期的值,如果没有设置超时期,则返回为None
    sk.fileno() 返回套接字的文件描述符
    sk.setblocking(flag) 是否阻塞(默认为True),如果设置False或0(即非堵塞模式),那么accept和recv时一旦无数据,则报错
    sk.makefile() 创建一个与该套接字相关联的文件

    实例一:你说一句,我说一句

    import socket
    ip_port = ("127.0.0.1", 1313)
    
    sk = socket.socket()
    sk.bind(ip_port)       # 创建端口
    sk.listen(5)   # 监听多少个
    
    while True:
        print("等待消息。。")
        conn,addr = sk.accept()         # 生成地址和一个实例线程
        while True:
            try:              # 如果客户端端口,没有消息了,抓取异常,跳出循环
                client_data = conn.recv(1024)   # 接收消息
                print(str(client_data, "utf8"))  
            except Exception:
                print("over")
                break
    
            server_input = input(">>").strip()   # 发送消息
            conn.sendall(bytes(server_input,"utf8"))
        conn.close()
    服务器端
    import socket
    
    ip_port = ("127.0.0.1",1313)
    
    sk = socket.socket()      # 实例化
    sk.connect(ip_port)       # 连接端口
    while True:
        client_data = input(">>").strip()
        sk.sendall(bytes(client_data,"utf8"))   # 发送消息
        server_data = sk.recv(1024)            # 接收消息
        print(str(server_data,"utf8"))
    sk.close()
    客户端

    实例二:在Linux上Python3实现客户端发命令,服务器端把客户端命令实现,并发回客户端

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    import socket
    import subprocess
    ip_port = ('127.0.0.1',9999)
    sk = socket.socket()
    sk.bind(ip_port)
    sk.listen(5)
    while True:
        print('server waiting...')
        conn,addr = sk.accept()
        while True:
            client_data = conn.recv(1024)
            if not client_data:break            # 如果没有客户端发来的消息则退出
            print('recv cmd:',str(client_data,'utf8'))    # 打印客户端发来了的消息
            cmd = str(client_data, 'utf8').strip()
    
            cmd_call = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)     # 把客户发来的消息执行结果放在管道里
    
            cmd_result = cmd_call.stdout.read()              # 把 cmd 的执行结果读出来
            if len(cmd_result) == 0:          # 如果结果为 0
                cmd_result = b'cmd execution has no output...'
            ack_msg = bytes('CMD_RESULT_SIZE|%s' % len(cmd_result), 'utf8')       # 文件名和长度发回客户端
            conn.send(ack_msg)
            client_ack =  conn.recv(50)     # 向客户端确认消息 (收),用来解决粘包
            if client_ack.decode() == "yes":
                conn.send(cmd_result)     # 确认后,才向客户端发数据
        conn.close()
    服务器端
    #!usr/bin/python3
    # -*- coding:utf-8 -*-
    import socket
    
    ip_port = ('127.0.0.1',9999)
    sk = socket.socket()
    sk.connect(ip_port)
    
    while True:
        user_input = input('cmd:').strip()
        if len(user_input) == 0:continue
        if user_input =='q':break   # 按q可以退出
    
        sk.send(bytes(user_input,'utf8'))        # 发消息
    
        server_ack_msg = sk.recv(100)           # 每次接收服务器端发来的消息最大长度
        cmd_res_msg = str(server_ack_msg.decode()).split("|")          # 去掉 |  ,并转码
        print('server response:',cmd_res_msg)          # 打印 文件名,总长度
        if cmd_res_msg[0] =="CMD_RESULT_SIZE":        # 确定 文件名
            cmd_res_size = int(cmd_res_msg[1])          # 确定文件长度
        sk.send(b"yes")     # 发回消息确认,解决粘包
    
        res = ''               # 保存 文件内容
        received_size = 0
      #  (在服务器端和客户端中各有一个缓冲区,在一定的时间内客户端接收数据不够500,也会先进行收数据,其他的就下次再收)
        while received_size < cmd_res_size:         # 如果 文件内容,小于发来的长度
            data = sk.recv(500)                # 每次接收最大长度 为500
    
            received_size += len(data)         # 累加
            res += str(data.decode())
        else:
            print(str(res))
            print('---------------------')
    sk.close()
    客户端
    客户端:
    
    
    [root@localhost python_day2018_10_28]# python3 client_1.py 
    cmd:df
    server response: ['CMD_RESULT_SIZE', '521']
    Filesystem              1K-blocks    Used Available Use% Mounted on
    /dev/mapper/centos-root  18307072 2056032  16251040  12% /
    devtmpfs                   490096       0    490096   0% /dev
    tmpfs                      500664       0    500664   0% /dev/shm
    tmpfs                      500664    6956    493708   2% /run
    tmpfs                      500664       0    500664   0% /sys/fs/cgroup
    /dev/sda1                  508588  111880    396708  22% /boot
    tmpfs                      100136       0    100136   0% /run/user/0
    
    ---------------------
    cmd:
    
    
    服务器端:
    
    [root@localhost python_day2018_10_28]# python3 server.py 
    server waiting...
    recv cmd: df
    result
  • 相关阅读:
    Python 接口测试之结果集比较封装
    Python 接口测试之发送邮件封装
    Python 接口测试之接口请求方法封装
    Python 接口测试之获取接口数据封装
    Python 接口测试之接口关键字封装
    Python 接口测试之Excel表格数据操作方法封装
    [c++] 二级指针的原理
    [bug] java.text.ParseException: Unparseable date: "2020-01-01"
    [bug] IDEA编译时出现 Information:java: javacTask: 源发行版 1.8 需要目标发行版 1.8
    [bug] maven“1.5不支持diamond运算符,请使用source 7或更高版本以启用diamond运算符”
  • 原文地址:https://www.cnblogs.com/Vera-y/p/9930329.html
Copyright © 2011-2022 走看看