python学习笔记-Day9 (TCP/IP协议、socket)

TCP/IP协议

TCP/IP四层协议

 

TCP/IP概念

tcp/ip协议是主机接入互联网以及接入互联网的两台主机通信的标准。

 

数据帧概念

数据帧
  |-- 包头
  |     |--源地址
  |     |--目标地址
  |     |--数据类型
  |
  |-- 数据

 

socket在四层协议中的位置

 

socket协议的交互流程

 

socket初试

# 依照上socket流程图,实现一个功能,客户端输入什么,就把输入的转为大写

# soceet server

import socket
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 绑定ip,端口
s.bind(ip_port)

# 启动监听
s.listen(5)  # 挂起连接数,  允许最多处理5个请求
while True:
    # 等待连接
    conn, addr = s.accept()  # accept方法等待客户端连接,直到有客户端连接后,会返回连接线(conn)、连接地址(addr)

    while True:
        # 至此,当客户端连接时,conn即为连接客户端的连接线
        # 所以,当客户端主动断开连接时,conn就不存在了,也会抛出异常
        # 在这里定义一个异常跟踪
        try:
            # 接收消息
            recv_data=conn.recv(1024)  # 接收conn连接线路,并指定缓存该线路的1024
            print('接收消息类型:%s' % type(recv_data))

            # 发送消息
            send_data=recv_data.upper()  # 将接收消息转换为大写
            print("发送消息内容:%s" % send_data)
            conn.send(send_data)  # 使用conn线路,发送消息
        except Exception:  # 如果客户端主动断开,则server退出该循环等待下一条连接
            break

    # 结束进程
    conn.close() # 中断线路
# socket client

import socket
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 向服务端建立连接
s.connect(ip_port)

while True:
    # 发送消息
    send_data=input('>>: ').strip()
    if len(send_data) == 0:continue  # 如果发送消息为空,不去执行以下发送
    s.send(bytes(send_data,encoding='utf8'))
    if send_data == 'exit': break  # 如果输入exit,则退出

    # 接收消息
    recv_data = s.recv(1024) #
    print(str(recv_data,encoding='utf8'))

# 结束连接
s.close()

到目前为止,实现了以下功能:

1. client请求数据,server返回处理完数据

2. client断开,server不受影响

 

socket模拟ssh连接

# socket server

import socket
import subprocess
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 绑定ip,端口
s.bind(ip_port)

# 启动监听
s.listen(5)  # 挂起连接数,  允许最多处理5个请求
while True:
    # 等待连接
    conn, addr = s.accept()  # accept方法等待客户端连接,直到有客户端连接后,会返回连接线(conn)、连接地址(addr)

    while True:
        # 至此,当客户端连接时,conn即为连接客户端的连接线
        # 所以,当客户端主动断开连接时,conn就不存在了,也会抛出异常
        # 在这里定义一个异常跟踪
        try:
            # 接收消息
            recv_data=conn.recv(1024)  # 接收conn连接线路,并指定缓存该线路的1024
            print('接收消息类型:%s' % type(recv_data))

            # 发送消息
            # 将接收的字节转换为str,传入subprocess.popen执行该命令,并定义stdout
            p=subprocess.Popen(str(recv_data,encoding='utf8'),shell=True,stdout=subprocess.PIPE)
            # 读取stdout,res目前为gbk编码的bytes格式
            res = p.stdout.read()
            if len(res) == 0:
                send_data='cmd err'
            else:
                # 将res(gbk编码的bytes格式) 按照gbk解码为字符串
                send_data=str(res,encoding='gbk')
            # 将字符串(gbk格式)按照utf8编码转为bytes,发送给客户端
            conn.send(bytes(send_data,encoding='utf8'))
        except Exception:  # 如果客户端主动断开,则server正常退出
            break

    # 结束进程
    conn.close() # 中断线路
# socket client
# client无改变

import socket
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 向服务端建立连接
s.connect(ip_port)

while True:
    # 发送消息
    send_data=input('>>: ').strip()
    if len(send_data) == 0:continue  # 如果发送消息为空,不去执行以下发送
    s.send(bytes(send_data,encoding='utf8'))
    if send_data == 'exit': break  # 如果输入exit,则退出

    # 接收消息
    recv_data = s.recv(1024) #
    print(str(recv_data,encoding='utf8'))

# 结束连接
s.close()

 

socket粘包问题解决

# socket server
# 粘包问题解决,就是在真正接收文件时,客户端与服务端确认文件大小,
# 这样确定好大小后,只传输这么多大小的文件,即解决了粘包问题

import socket
import subprocess
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 绑定ip,端口
s.bind(ip_port)

# 启动监听
s.listen(5)  # 挂起连接数,  允许最多处理5个请求
while True:
    # 等待连接
    conn, addr = s.accept()  # accept方法等待客户端连接,直到有客户端连接后,会返回连接线(conn)、连接地址(addr)

    while True:
        # 至此,当客户端连接时,conn即为连接客户端的连接线
        # 所以,当客户端主动断开连接时,conn就不存在了,也会抛出异常
        # 在这里定义一个异常跟踪
        try:
            # 接收消息
            recv_data=conn.recv(1024)  # 接收conn连接线路,并指定缓存该线路的1024
            print('接收消息类型:%s' % type(recv_data))

            # 发送消息
            # 将接收的字节转换为str,传入subprocess.popen执行该命令,并定义stdout
            p=subprocess.Popen(str(recv_data,encoding='utf8'),shell=True,stdout=subprocess.PIPE)
            # 读取stdout,res目前为gbk编码的bytes格式
            res = p.stdout.read()
            if len(res) == 0:
                send_data='cmd err'
            else:
                # 将res(gbk编码的bytes格式) 按照gbk解码为字符串
                send_data=str(res,encoding='gbk')

            # 将字符串按utf8编码转换为bytes
            send_data = bytes(send_data, encoding='utf8')

            # 发送真正客户端数据之前,告诉客户端我发送的数据的字节长度,
            # 让客户端知道接收到哪里结束
            read_tag = 'Ready|%s' % len(send_data)  # 取出数据长度
            conn.send(bytes(read_tag,encoding='utf8'))  # 将取出长度发给客户端
            feedback = conn.recv(1024)  # 客户端接收长度后,确认返回值
            feedback=str(feedback,encoding='utf8')  # 将客户端返回的确认值,转为str

            # 发送真正客户端请求数据
            if feedback.startswith('Start'):  # 如果返回确认,则开始发送客户端所需要的数据
                conn.send(send_data)   # 将字符串(gbk格式)按照utf8编码转为bytes,发送给客户端

        except Exception:  # 如果客户端主动断开,则server正常退出
            break

    # 结束进程
    conn.close() # 中断线路
# socket client 
# 同server

import socket
ip_port=('127.0.0.1',9999)

# 封装协议(对象)
s = socket.socket()

# 向服务端建立连接
s.connect(ip_port)

while True:
    # 发送消息
    send_data=input('>>: ').strip()
    if send_data == 'exit': break  # 如果输入exit,则退出
    if len(send_data) == 0:continue  # 如果发送消息为空,不去执行以下发送
    s.send(bytes(send_data,encoding='utf8'))

    # 在接收server返回数据前,server返回本次传输数据的长度
    ready_tag=s.recv(1024)  # 使用1024字节记录本次数据长度
    ready_tag=str(ready_tag,encoding='utf8')  # 将bytes字符串
    if ready_tag.startswith('Ready'):  # 如果server端返回Ready 即为准备好,可以发送数据包
        msg_size=int(ready_tag.split('|')[1])  # 取出server要发送回的数据长度
        start_tag='Start'  
        s.send(bytes(start_tag,encoding='utf8')) # 返回给server 开始传输信息

    # 接收消息
    recv_size=0
    recv_msg=b''
    while recv_size < msg_size:
        recv_data = s.recv(1024) #
        recv_msg+=recv_data
        recv_size+=len(recv_data)
        print('MSG SIZE %s RECE SIZE %s' % (msg_size,recv_size))

    print(str(recv_msg,encoding='utf8'))
# 结束连接
s.close()

 

支持多连接的socket server

# socket server
# 同样是一个转换大写的server
import socketserver class MyServer(socketserver.BaseRequestHandler): # 类继承socketserver.BaseRequestHandler def handle(self): self.request.sendall(bytes('欢迎致电10086,请输入1xxx,0转人工服务。',encoding='utf8')) while True: data = self.request.recv(1024) print("[%s] says:%s" % (self.client_address,data.decode())) self.request.sendall(data.upper()) if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer) server.serve_forever() # 主要是继承并修改了socketserver.BaseRequestHandler类的handle方法 # 请直接阅读socketserver.BaseRequestHandler类,很简单的
# socket server
# 模拟ssh

import socketserver
import subprocess
class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        # print self.request,self.client_address,self.server
        self.request.sendall(bytes('欢迎致电 10086,请输入1xxx,0转人工服务.',encoding="utf-8"))
        while True:
            data = self.request.recv(1024)
            if len(data) == 0:break
            print("[%s] says:%s" % (self.client_address,data.decode() ))
            #self.request.sendall(data.upper())
            cmd = subprocess.Popen(data.decode(),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            cmd_res =cmd.stdout.read()
            if not cmd_res:
               cmd_res = cmd.stderr.read()
            if len(cmd_res) == 0: #cmd has not output
               cmd_res = bytes("cmd has output",encoding="utf-8")
            self.request.send(cmd_res )


if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('0.0.0.0', 8009), MyServer)
    server.serve_forever()
# socket client

import socket
ip_port=('127.0.0.1',8009)

# 封装协议(对象)
s = socket.socket()

# 向服务端建立连接
s.connect(ip_port)

# 接收欢迎信息
welcome_msg = s.recv(1024)
print("from server:",welcome_msg.decode())

while True:
    # 发送消息
    send_data=input('>>: ').strip()
    if send_data == 'exit': break  # 如果输入exit,则退出
    if len(send_data) == 0:continue  # 如果发送消息为空,不去执行以下发送
    s.send(bytes(send_data,encoding='utf8'))

    # 接收消息
    recv_data=s.recv(1024)
    print(type(recv_data))
    print(str(recv_data,encoding='gbk'))
# 结束连接
s.close()

 

posted @ 2016-07-06 22:43  Cool_King  阅读(1838)  评论(0编辑  收藏  举报