day26 作业

TCP三次握手、四次挥手图

三次握手

  • 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_Send 状态。

  • 第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。

  • 第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。

  • 服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方已建立起了链接。

四次挥手

刚开始双方都处于 establised 状态,假如是客户端先发起关闭请求,则:

  • 第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
  • 第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
  • 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
  • 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态。服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。

简明理解三次握手

第一次握手:Client什么都不能确认;Server确认了对方发送正常

第二次握手:Client确认了:自己发送、接收正常,对方发送、接收正常;Server确认了:自 己接收正常,对方发送正常

第三次握手:Client确认了:自己发送、接收正常,对方发送、接收正常;Server确认了:自己发送、接收正常,对方发送接收正常

基于TCP开发一款远程CMD程序

客户端连接服务器后,可以向服务器发送命令
服务器收到命令后执行,无论执行是否成功,无论执行几遍,都将执行结果返回给客户端

注意: 执行系统指令使用subprocess模块完成.

利用 subprocess模块 实现

  • 创建popen类的实例化对象
    obj = Subprocess.Popen("pwd",shell=True,stdout=subprocess.PIPE)
  • shell 开启shell
  • stdout 重定向结果输出管道
    * PIPE 将结果转移到当前主进程
  • stdout.read() 获取命令执行的结果,指定结果后会将执行结果封装到指定的对象中,然后通过对象,read()获取执行命令的结果,如果不定义stdout会将结果进行标准输出
# 例子

[root@192.168.32.130 /python]$ cat python-subprocess.py
#coding=utf-8
import subprocess
popen = subprocess.Popen("pwd",shell=True,stdout=subprocess.PIPE)
print(popen.stdout.read().strip())
[root@192.168.32.130 /python]$ 
[root@192.168.32.130 /python]$ python3 python-subprocess.py
b'/python'
[root@192.168.32.130 /python]$ 
# 服务端编写
# coding=utf-8
import socket
import subprocess
sock = socket.socket()
# 重用ip和端口
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

sock.bind(('192.168.32.130', 8888))
sock.listen(5)

while True:
    print("等待客户端连接...")
    conn, addr = sock.accept()
    print(f"{addr}成功连接!")
    while True:
        cmd = conn.recv(1024)
        if cmd == "q":
            print("客户端退出连接!")
            break
        print(f"命令是 {cmd.decode('utf-8')}")
        # 利用subprocess模块进行系统调用
        data = subprocess.Popen(cmd.decode(),shell=True,
                                stdout=subprocess.PIPE,
                                stdin=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout = data.stdout.read()
        stderr = data.stderr.read()
        # 打包执行结果
        res = stdout + stderr
        # 发送执行结果
        conn.send(res)
    conn.close()
# 客户端编写

# coding=utf-8
import socket
sock = socket.socket()
sock.connect(('192.168.32.130', 8888))
while True:
    cmd = input("请输入你要执行的命令").strip()
    if not cmd:
        print("不能为空!")
        continue
    elif cmd == 'exit':
        break

    sock.send(cmd.encode('utf-8'))

    data = sock.recv(1024)
    print(data.decode('utf-8'))
sock.close()

终端打印结果

利用 os模块 实现

# 服务端

# coding=utf-8

import os
import socket

sock = socket.socket()
# 重置ip和端口
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
address = ("192.168.32.130",8888)

sock.bind(address)
sock.listen(5)

while True:
    print("等待客户端连接...")

    conn,addr = sock.accept()
    print(f"来自客户端地址{addr}连接成功!")
    while True:
        cmd = conn.recv(1024)
        if not cmd:
            print("客户端断开连接...")
            break
        print(f"客户端执行了命令:{cmd}")

        # 利用os模块的popen方法执行命令
        data = os.popen(cmd.decode("utf-8")).read()
        conn.send(data.encode("utf-8"))

    conn.close()


# coding=utf-8

import socket

sock = socket.socket()
address = ("192.168.32.130",8888)
sock.connect(address)

while True:
    cmd = input("请输入你要执行的命令>>>").strip()
    if not cmd:
        continue
    if cmd == "exit":
        break

    sock.send(cmd.encode("utf-8"))

    data = sock.recv(1024)
    print(data.decode("utf-8"))

sock.close()

posted @ 2019-10-17 16:20  GeminiMp  阅读(170)  评论(0)    收藏  举报