• day 29-1 socket


    socket是什么?

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    所以,我们无需深入理解 tcp/udp 协议,socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然就是遵循 tcp/udp 标准的。

    也有人将 socket 说成 ip+port,ip 是用来标识互联网中的一台主机的位置,而 port 是用来标识这台机器上的一个应用程序,ip 地址是配置到网卡上的,而 port 是应用程序开启的,ip 与 port 的绑定就标识了互联网中独一无二的一个应用程序
    而程序的pid是同一台机器上不同进程或者线程的标识

    套接字工作原理

     一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

    先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

    socket()模块

    基于 socket 实现简单套接字通信

    服务端

    import socket
    
    # 1.买手机
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2.绑定手机卡
    phone.bind(('127.0.0.1', 8080))  # 端口范围:0-65535,0-1024给操作系统使用
    
    # 3.开机
    phone.listen(5)
    
    # 4.等待连接
    print('Waiting...')
    conn, client_addr = phone.accept()
    
    # 5.收发消息
    data = conn.recv(1024)          # 1、单位:bytes  2、1024 代表接收最大 1024 个bytes
    print('客户端数据:', data)
    conn.send('hello'.encode('utf-8'))
    
    # 6.挂断
    conn.close()
    
    # 7.关机
    conn.close()

    客户端

    import socket
    
    # 1.买手机
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2.拨号
    phone.connect(('127.0.0.1', 8080))
    
    # 3.发、收消息
    phone.send('ni hao'.encode('utf-8'))
    res = phone.recv(1204)
    print(res)
    # 4.关闭
    phone.close()

    在简单套接字基础上加上通信循环

    服务端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    print('waiting...')
    conn,clent_addr = phone.accept()
    print(clent_addr)
    start = 1
    while start:        # 通信循环
        age = conn.recv(1024)
        if age == 'b':
            break
        print(age)
        conn.send(age.upper())
    conn.close()
    phone.close()

    客户端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8080))
    while True:
        mes = input('>>>').strip()
        if mes == 'b':
            break
        phone.send(mes.encode('utf-8'))
        info = phone.recv(1024)
        print(info)
    phone.close()

    BUG修改

    服务端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.bind(('127.0.0.1', 8081))
    phone.listen(5)
    print('waiting...')
    conn, clent_addr = phone.accept()
    print(clent_addr)
    start = 1
    while start:  # 通信循环
        try:
            age = conn.recv(1024)
            if not age: break
            print(age)
            conn.send(age.upper())
        except ConnectionResetError:
            break
    
    conn.close()
    phone.close()

    客户端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    phone.connect(('127.0.0.1', 8081))
    while True:
        mes = input('>>>').strip()
        if not mes: continue
        if mes == 'b':
            break
        phone.send(mes.encode('utf-8'))
        info = phone.recv(1024)
        print(info.decode('GBK'))
    phone.close()

    在简单套接字基础上加上通信循环

    服务端

    import socket
    import subprocess
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.bind(('127.0.0.1', 8081))
    phone.listen(5)
    print('waiting...')
    while True:  # 链接循环
        conn, clent_addr = phone.accept()
        print(clent_addr)
        start = 1
        while start:  # 通信循环
            try:
                age = conn.recv(1024)
                if not age: break
                print(age)
                info =subprocess.Popen(age.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout = info.stdout.read()
                stderr = info.stderr.read()
                conn.send(stdout+stderr)
            except ConnectionResetError:
                break
    
        conn.close()
    phone.close()

    客户端

    import socket
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    phone.connect(('127.0.0.1', 8081))
    while True:
        mes = input('>>>').strip()
        if not mes: continue
        if mes == 'b':
            break
        phone.send(mes.encode('utf-8'))
        info = phone.recv(1024)
        print(info.decode('GBK'))
    phone.close()

    在解决粘包问题——简单版

    服务端

    import socket
    import subprocess
    import struct
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    print('waiting...')
    while True:
        conn, addr = server.accept()
        print(addr)
        while True:
            ret = conn.recv(1024)
            print(ret)
            if not ret: break
            info = subprocess.Popen(ret.decode('utf-8'), shell=True,
                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout = info.stdout.read()
            stderr = info.stderr.read()
            len_std = len(stdout) + len(stderr)
            totle = struct.pack('i', len_std)
            conn.send(totle)
            conn.send(stdout)
            conn.send(stderr)
        conn.close()
    server.close()

    客户端

    import socket
    import struct
    
    center = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    center.connect(('127.0.0.1', 8080))
    while True:
        res = input('>>>').strip()
        if not res: continue
        center.send(res.encode('utf-8'))
        total = center.recv(4)
        total_size = struct.unpack('i', total)
        recv_size = 0
        recv_data = b''
        while recv_size < int(total_size[0]):
            ret = center.recv(1024)
            recv_data += ret
            recv_size += len(ret)
        print(recv_data.decode('GBK'))
    center.close()

    在解决粘包问题——最终版

    问题:1.报头是不仅仅只包含文本长度信息的,2.不应该把文本长度直接写入报文内。

    服务端

    import socket
    import subprocess
    import json
    import struct
    
    cmd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    cmd.bind(('127.0.0.1', 8090))
    cmd.listen(4)
    print('waiting...')
    while True:
        conn, addr = cmd.accept()
        print(addr)
        while 1:
            try:
                com = conn.recv(1024)
                if not com: break
                com_info = subprocess.Popen(com.decode('utf-8'), shell=True,
                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout = com_info.stdout.read()
                stderr = com_info.stderr.read()
                size_info = len(stdout) + len(stderr)
                header = {
                    'file_name': 'app.txt',
                    'hd5': '124482',
                    'size_data': size_info
                }
                header_str = json.dumps(header)
                header_bytes = header_str.encode('GBK')
    
                conn.send(struct.pack('i', len(header_bytes)))
                conn.send(header_bytes)
                conn.send(stdout)
                conn.send(stderr)
            except Exception:
                break
        conn.close()
    cmd.close()

    客户端

    import socket
    import struct
    import json
    
    cmd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    cmd.connect(('127.0.0.1', 8090))
    while 1:
        cmp = input('>>>').strip()
        if not cmp: continue
        cmd.send(cmp.encode('utf-8'))
        header = cmd.recv(4)
        header_size = struct.unpack('i', header)
        header_str = cmd.recv(header_size[0])
        header_json = json.loads(header_str)
        send_size = 0
        send_str = b''
        while send_size < int(header_json['size_data']):
            ret = cmd.recv(1024)
            send_str += ret
            send_size += len(ret)
        print(send_str.decode('GBK'))
    cmd.closs()
  • 相关阅读:
    用循环链表求解约瑟夫问题
    Nim游戏变种——取纽扣游戏
    POJ-2726-Holiday Hotel
    常用排序算法总结(二)
    常用排序算法总结(一)
    找出数组中出现次数最多的那个数——主元素问题
    C99新特性:变长数组(VLA)
    linux tftp配置 (Ubuntu18.04)
    Ubuntu 18.04安装Samba服务器及配置
    记录学习Linux遇到的问题
  • 原文地址:https://www.cnblogs.com/ysging/p/12120863.html
Copyright © 2020-2023  润新知