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()

 

posted @ 2019-12-30 17:30  亦双弓  阅读(158)  评论(0)    收藏  举报