zoukankan      html  css  js  c++  java
  • python之day9(socket)

    今日重点socket网络编程:

    1,tcp/ip简介:

    2,socket简单应用模型:

    3,socket单用户模式扩展:

    4,socketserver实例:

    首先记录一个在day6时没有记录的知识点:

    百分比的应用:

    import sys
    import time
    
    def view_bar(num, total):
        rate = float(num) / float(total)
        rate_num = int(rate * 100)
        r = '
    %d%%' % (rate_num, )
        sys.stdout.write(r)
        sys.stdout.flush()
    
    
    if __name__ == '__main__':
        for i in range(0, 101):
            time.sleep(0.1)
            view_bar(i, 100)
    

    进入主要内容:

    一,tcp/ip

        osi7层结构以及具体作用。

        物理层:电缆,双绞线,无线电波

        链路层(网卡):ethernet通用协议---》找到唯一的mac地址

        网络层:IP 找到了子网中唯一的标识。

        传输层:tcp,udp,port 规定传输协议以及端口号。

        tcp/ip基本模型

    二,socket简单应用模型:

        socket的所在位置。

        整个的socket交流过程。

    socket要点提示:

    1.基于python3.5.2版本的socket只能收发字节(python2.7可以发送str)
    2.退出只在客户端退出就ok了
    3.s.accept()和s.recv()是阻塞的(基于链接正常)
    4.listen(n) n代表:能挂起的链接数,如果n=1,代表可以链接一个,挂起一个,第三个拒绝
    5.服务端出现端口冲突:修改监听端口号
    6.服户端:1.send #数据长度
                  4.recv #收到确认信息,开始下一步发送

              send

      客户端:2.recv #获取数据长度
                 3.send #发送确认信息

              recv #循环接收

    基础socket程序:

     1 import socket
     2 ip_port=('127.0.0.1',9999)
     3 #买手机
     4 s=socket.socket()
     5 #买手机卡
     6 s.bind(ip_port)
     7 #开机
     8 s.listen(5)
     9 #等待电话
    10 while True:
    11     conn,addr=s.accept()
    12     #收消息
    13     while True:
    14         try:
    15             recv_data=conn.recv(1024)
    16             if len(recv_data) == 0:break
    17             # print('--------------------',type(recv_data))
    18             #发消息
    19             send_data=recv_data.upper()
    20             print(send_data)
    21             conn.send(send_data)
    22         except Exception:
    23             break
    24     #挂电话t
    25     conn.close()
    server1
     1 #!/usr/bin/env  python
     2 # -*- coding: UTF-8 -*-
     3 # Author: Aaron Shen
     4 
     5 import socket
     6 ip_port=('127.0.0.1',9999)
     7 #买手机
     8 s=socket.socket()
     9 #拨号
    10 s.connect(ip_port)
    11 #发送消息
    12 while True:
    13     send_data=input(">>: ").strip()
    14     if send_data == "exit": break
    15     if len(send_data) == 0:continue
    16     s.send(bytes(send_data,encoding='utf8'))
    17 
    18 
    19     #收消息
    20     recv_data=s.recv(1024)
    21     print(str(recv_data,encoding='utf8'))
    22 #挂电话
    23 s.close()
    client1

    三,socket单用户模式扩展:

    关于执行系统命令,以及粘包问题解决思想:

    执行系统命令 用到subprocess 模块 .Popen方法 参数跟(系统命令,shell=True,stdout = subprocess.PIPE, stderr = subprocess.PIPE)

    粘包问题产生的原因:

    由于发送端的字节数超过了接收端一次性可接收的数量,到时一次无法将发送端的数据全部接收完,再继续执行命令是会继续进行发送,造成粘包。

    解决办法:

    首先就是要有一下循环的思想,只要没接收完就一直接收。因此我们要知道发送包data的具体大小。

    其次我们要先将data的大小发送给接收端。

    然后接收端回复Ok我收到了发送端要发送多大的包给我,我会根据这个包的大小进行循环接收,接收完就不再接收。

    最后发送端开始发送数据,接收端接收知道接收完成。

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Lire
     4 import socket
     5 import subprocess #导入执行命令模块
     6 ip_port=('127.0.0.1',9999) #定义元祖
     7 #买手机
     8 s=socket.socket()  #绑定协议,生成套接字
     9 s.bind(ip_port)    #绑定ip+协议+端口:用来唯一标识一个进程,ip_port必须是元组格式
    10 s.listen(5)        #定义最大可以挂起胡链接数
    11 #等待电话
    12 while True:  #用来重复接收新的链接
    13     conn,addr=s.accept()   #接收客户端胡链接请求,返回conn(相当于一个特定胡链接),addr是客户端ip+port
    14     #收消息
    15     while True: #用来基于一个链接重复收发消息
    16             try: #捕捉客户端异常关闭(ctrl+c)
    17                 recv_data=conn.recv(1024) #收消息,阻塞
    18                 if len(recv_data) == 0:break #客户端如果退出,服务端将收到空消息,退出
    19 
    20                 #发消息
    21                 p=subprocess.Popen(str(recv_data,encoding='utf8'),shell=True,stdout=subprocess.PIPE) #执行系统命令,windows平
    22                                                                                                       # 台命令的标准输出是gbk编码,需要转换
    23                 res=p.stdout.read()   #获取标准输出
    24                 if len(res) == 0:   #执行错误命令,标准输出为空,
    25                     send_data='cmd err'
    26                 else:
    27                     send_data=str(res,encoding='gbk')  #命令执行ok,字节gbk---->str---->字节utf-8
    28 
    29                 send_data=bytes(send_data,encoding='utf8')
    30 
    31 
    32                 #解决粘包问题
    33                 ready_tag='Ready|%s' %len(send_data)
    34                 conn.send(bytes(ready_tag,encoding='utf8')) #发送数据长度
    35                 feedback=conn.recv(1024)  #接收确认信息
    36                 feedback=str(feedback,encoding='utf8')
    37 
    38                 if feedback.startswith('Start'):
    39                     conn.send(send_data)  #发送命令的执行结果
    40             except Exception:
    41                 break
    42     #挂电话
    43     conn.close()
    进阶socket_server
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 import socket
     5 ip_port=('127.0.0.1',9999)
     6 #买手机
     7 s=socket.socket()
     8 #拨号
     9 s.connect(ip_port)  #链接服务端,如果服务已经存在一个好的连接,那么挂起
    10 
    11 while True:        #基于connect建立的连接来循环发送消息
    12     send_data=input(">>: ").strip()
    13     if send_data == 'exit':break
    14     if len(send_data) == 0:continue
    15     s.send(bytes(send_data,encoding='utf8'))
    16 
    17     #解决粘包问题
    18     ready_tag=s.recv(1024) #收取带数据长度的字节:Ready|9998
    19     ready_tag=str(ready_tag,encoding='utf8')
    20     if ready_tag.startswith('Ready'):#Ready|9998
    21         msg_size=int(ready_tag.split('|')[-1])  #获取待接收数据长度
    22     start_tag='Start'
    23     s.send(bytes(start_tag,encoding='utf8')) #发送确认信息
    24 
    25     #基于已经收到的待接收数据长度,循环接收数据
    26     recv_size=0
    27     recv_msg=b''
    28     while recv_size < msg_size:
    29         recv_data=s.recv(1024)
    30         recv_msg+=recv_data
    31         recv_size+=len(recv_data)
    32         print('MSG SIZE %s RECE SIZE %s' %(msg_size,recv_size))
    33 
    34     print(str(recv_msg,encoding='utf8'))
    35     #挂电话
    36 s.close()
    进阶socket_client

    四,socketserver实例:

      这部分是alex大拿老师讲的,基本上没听懂,呵呵,主要靠课下重新读代码,重新构思的。

      首先说一下socketserver与普通socket的区别:

      普通socket所有点链路(conn)都是单通道的,只能一个客户端占用。服务端也是一对一进行相应。如果还有别的客户端要访问就要排队等待,直到之前的客户端退出后才可以与服务端进行交互。

      

      socketserver 使用socketserver模块(2.7头字母要进行大写),继承了socketserver.BaseRequestHandler这个类,我们用的时候必须使用 handle这个函数。他的特点就是可以完成一对多的相应。

       基本程序构建:

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 
     6 #!/usr/bin/env python
     7 # -*- coding:utf-8 -*-
     8 #import SocketServer
     9 import socketserver
    10 
    11 class MyServer(socketserver.BaseRequestHandler):
    12     def handle(self):
    13         # print self.request,self.client_address,self.server
    14         self.request.sendall(bytes('欢迎致电 10086,请输入1xxx,0转人工服务.',encoding="utf-8"))
    15         while True:
    16             data = self.request.recv(1024)
    17             print("-->",len(data))
    18             if len(data) == 0:break
    19             print("[%s] says:%s" % (self.client_address,data.decode() ))
    20             self.request.sendall(data.upper())
    21 
    22 if __name__ == '__main__':
    23     server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
    24     server.serve_forever()
    socket_server
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 import socket
     6 ip_port=('192.168.11.58',8009)
     7 #买手机
     8 s=socket.socket()
     9 #拨号
    10 s.connect(ip_port)
    11 #发送消息
    12 welcome_msg = s.recv(1024)
    13 print("from server:",welcome_msg.decode())
    14 while True:
    15     send_data=input(">>: ").strip()
    16     if len(send_data) == 0:continue
    17     s.send(bytes(send_data,encoding='utf8'))
    18     #收消息
    19     recv_data=s.recv(1024)
    20     print(str(recv_data,encoding='utf8'))
    21     #挂电话
    22 s.close()
    socket_client

      通过socket 远程执行命令(通过客户端发送命令到服务端并执行)

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 
     6 #!/usr/bin/env python
     7 # -*- coding:utf-8 -*-
     8 #import SocketServer
     9 import socketserver
    10 import subprocess 
    11 class MyServer(socketserver.BaseRequestHandler):
    12     def handle(self):
    13         # print self.request,self.client_address,self.server
    14         self.request.sendall(bytes('欢迎致电 10086,请输入1xxx,0转人工服务.',encoding="utf-8"))
    15         while True:
    16             data = self.request.recv(1024)
    17             if len(data) == 0:break
    18             print("[%s] says:%s" % (self.client_address,data.decode() ))
    19             #self.request.sendall(data.upper())
    20             cmd = subprocess.Popen(data.decode(),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    21             cmd_res =cmd.stdout.read()
    22             if not cmd_res:
    23                cmd_res = cmd.stderr.read()
    24             if len(cmd_res) == 0: #cmd has not output 
    25                cmd_res = bytes("cmd has output",encoding="utf-8")
    26             self.request.send(cmd_res )
    27 
    28 
    29 if __name__ == '__main__':
    30     server = socketserver.ThreadingTCPServer(('0.0.0.0',8009),MyServer)
    31     server.serve_forever()
    com_server
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 import socket
     6 ip_port=('192.168.11.58',8009)
     7 #买手机
     8 s=socket.socket()
     9 #拨号
    10 s.connect(ip_port)
    11 #发送消息
    12 welcome_msg = s.recv(1024)
    13 print("from server:",welcome_msg.decode())
    14 while True:
    15     send_data=input(">>: ").strip()
    16     if len(send_data) == 0:continue
    17     s.send(bytes(send_data,encoding='utf8'))
    18     #收消息
    19     recv_data=s.recv(1024)
    20     print(str(recv_data,encoding='utf8'))
    21     #挂电话
    22 s.close()
    com_client

      通过socket进行ftp 上传操作(通过客户端发送指令,上传到服务器端)

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 
     6 #!/usr/bin/env python
     7 # -*- coding:utf-8 -*-
     8 #import SocketServer
     9 import socketserver,json
    10 class MyServer(socketserver.BaseRequestHandler):
    11     def handle(self):
    12         # print self.request,self.client_address,self.server
    13         self.request.sendall(bytes('欢迎致电 10086,请输入1xxx,0转人工服务.',encoding="utf-8"))
    14         while True:
    15             data = self.request.recv(1024)                  #接收要进行操作的基本信息,包括动作,文件路径以及文件名,文件大小
    16             if len(data) == 0:break
    17             print("data", data)
    18             print("[%s] says:%s" % (self.client_address,data.decode() ))
    19 
    20             task_data = json.loads( data.decode()  )        #接收到一个json格式的字典
    21             task_action = task_data.get("action")           #获取字典的中动作的值
    22             if hasattr(self, "task_%s"%task_action):        #反射到本程序的下面的函数,查看是否存在。如果存在
    23                func = getattr(self,"task_%s" %task_action)  #获取函数
    24                func(task_data)                                     #执行函数,同时参数就是那个字典
    25             else:
    26                print("task action is not supported",task_action)
    27 
    28     def task_put(self,*args,**kwargs):
    29         print("---put",args,kwargs)         
    30         filename = args[0].get('filename')          #文件名就等于task_data.get('filename')
    31         filesize = args[0].get('file_size')         #文件大小就等于task_data.get('file_size')
    32         server_response = {"status":200}            #准备工作都准备好后,给客户端发一个确认
    33         self.request.send(bytes( json.dumps(server_response), encoding='utf-8'  ))      #发送确认
    34         f = open(filename,'wb')                     #打开文件
    35         recv_size = 0                                #未开始接收,因此接收大小是 0
    36         while recv_size < filesize:                  #如果接收大小小于文件大小就是一直循环
    37             data = self.request.recv(4096)            #开始接收
    38             f.write(data)                               #写入文件
    39             recv_size += len(data)                      #增加大小
    40             print('filesize: %s  recvsize:%s' % (filesize,recv_size))           #展示进度
    41         print("file recv success")                      #循环结束,完成接收
    42         f.close()
    43 
    44 if __name__ == '__main__':
    45     server = socketserver.ThreadingTCPServer(('0.0.0.0',8009),MyServer)
    46     server.serve_forever()
    ftp_server
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 # Author:Alex Li
     4 
     5 import socket
     6 import os ,json
     7 ip_port=('192.168.11.150',8009)                     #要访问的服务端IP以及端口
     8 #买手机
     9 s=socket.socket()                                      #生成套接字s
    10 #拨号
    11 s.connect(ip_port)                                      #连接服务和端口
    12 #发送消息
    13 welcome_msg = s.recv(1024)                              #获取服务端相应
    14 print("from server:",welcome_msg.decode())             #打印获取的服务端欢迎语
    15 while True:                                             #循环交互
    16     send_data=input(">>: ").strip()
    17     if len(send_data) == 0:continue                     #如果发送为空就重新发送
    18 
    19     cmd_list = send_data.split()                        #将命令进行分割 [put  test.txt]
    20     if len(cmd_list) <2:continue                        #如果小于2个元素就重新输入,命令是不完整的
    21     task_type = cmd_list[0]                               #第一个是命令 put, 第二个是文件路径
    22     if task_type == 'put':                              #如果是 put
    23         abs_filepath = cmd_list[1]                       #第二个就是文件路径
    24         if os.path.isfile(abs_filepath):                   #如果文件存在
    25             file_size = os.stat(abs_filepath).st_size       #获取文件大小
    26             filename = abs_filepath.split("\")[-1]         #获取文件名
    27             print('file:%s size:%s' %(abs_filepath,file_size))
    28             msg_data = {"action":"put",
    29                         "filename":filename,
    30                         "file_size":file_size}             #写成字典包括动作,文件名,文件大小
    31 
    32             s.send(  bytes(json.dumps(msg_data),encoding="utf-8")  )        #将字典整合成json发送给服务端(明确要上传的信息)
    33             server_confirmation_msg = s.recv(1024)                           #接收服务端发送的确认信息。
    34             confirm_data = json.loads(server_confirmation_msg.decode())      #获取确认信息,服务端发来的信息也是json封装的字典
    35             if confirm_data['status'] ==200:                                #如果是200 确认成功
    36 
    37                 print("start sending file ",filename)
    38                 f = open(abs_filepath,'rb')                                 #二进制打开要上传的文件
    39                 for line in f:                                              #逐行循环
    40                     s.send(line)                                             #上传到服务端   
    41 
    42                 print("send file done ")
    43 
    44         else:
    45             print("33[31;1mfile [%s] is not exist33[0m" % abs_filepath)
    46             continue
    47     else:
    48         print("doesn't support task type",task_type)
    49         continue
    50     #s.send(bytes(send_data,encoding='utf8'))
    51     #收消息
    52     recv_data=s.recv(1024)
    53     print(str(recv_data,encoding='utf8'))
    54     #挂电话
    55 s.close()
    ftp_client
  • 相关阅读:
    [野狐行网游研究][二期][8.21更新]
    Movidius的深度学习入门
    Linux下深度学习常用工具的安装
    Intel AI Cloud 使用
    【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
    策略模式
    Java 8 中常用的函数式接口
    MySQL权限管理(五)
    kickstart无人值守安装
    pymysql模块使用
  • 原文地址:https://www.cnblogs.com/aaron-shen/p/5639562.html
Copyright © 2011-2022 走看看