python3 socket实操备忘

server端:

#!/usr/bin/env python3
# 网络编程:三要素:ip地址、端口(进程)、协议
# socket.socket(socket_family,socket_type,protocal=0)   
# socket_family 可以是 AF_UNIX(unix使用) 或 AF_INET(ipv4)、AF_INET6(ipv6)。socket_type 可以是 SOCK_STREAM(tcp协议) 或 SOCK_DGRAM(udp协议)。protocol 一般不填,默认值为 0。

import socket
import subprocess
import os
BaseDir = os.path.dirname(os.path.abspath(__file__))
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    # 创建通道:套接字
address = ("127.0.0.1",8000)
sk.bind(address)    # 设置服务器ip地址及端口:绑定(主机,端口号)到套接字,元组
sk.listen(2)    # 设置最大排队人数
while True:
    conn,addr = sk.accept()     # 等待连接。。。waiting....被动接受TCP客户的连接,(阻塞式)等待连接的到来
    try:
        data = conn.recv(1024)  # recv不允许接收空数据。当断开链接时,data = "",接收数据中。。。waiting
    except Exception as e:      # 获取数据失败-出错时,断开连接
        break
#    print(conn,addr)
    data = str(data,"utf-8")
#********** 聊天 **********
    if data == "chat":
        while True:
            try:
                data = conn.recv(1024)  # recv不允许接收空数据。当断开链接时,data = "",接收数据中。。。waiting
            except Exception as e:      # 获取数据失败-出错时,断开连接
                break
            if not data:
                conn.close()
                print("正常连接关闭!")
                break
            print("....",str(data,"utf-8"))
            inp = input(">>>")
            conn.send(bytes(inp,"utf-8"))
#********** 远程命令 **********
    elif data == "remote_control":   
        while True:
            try:
                data = conn.recv(1024)  # recv不允许接收空数据。当断开链接时,data = "",接收数据中。。。waiting
            except Exception as e:      # 获取数据失败-出错时,断开连接
                break
            if not data:
                conn.close()
                print("正常连接关闭!")
                break
#            print("....",str(data,"utf-8"))
# subprocess 执行str(data,"utf-8")这个命令。通过stdout = subprocess.PIPE把结果调回主进程。shell = True必填
            obj = subprocess.Popen(str(data,"utf-8"), shell = True, stdout = subprocess.PIPE)
            cmd_result = obj.stdout.read()  # 获取cmd在本机执行的结果,bytes()类型,系统编码
            print(type(cmd_result))   # 调试,确定类型为bytes()类型
            print(cmd_result)
            result_len = bytes(str(len(cmd_result)),"utf-8")    # 取得结果长度,并转成bytes类型
            conn.sendall(result_len)   # 把结果长度发送给客户端,连续发送2信息,linux出错。粘包现象!
            conn.recv(1024)     # 解决粘包现象,中间穿插一个等待。client发送随机内容
            conn.sendall(cmd_result)    # 把结果发送给客户端
#********** 上传文件 **********  
    elif data == "post_file":
        while True:   
            try:
                data = conn.recv(1024)  # recv不允许接收空数据。当断开链接时,data = "",接收数据中。。。waiting
            except Exception as e:      # 获取数据失败-出错时,断开连接
                break
            if not data:
                conn.close()
                print("正常连接关闭!")
                break               
            data = data.decode("utf-8")
 #           print(data)
            cmd, filename, filesize = data.split("|")
            abspath = os.path.join(BaseDir,"img",filename)  # 路径拼接
            filesize = int(filesize)    # 把接收到的filesize转成整形
#            print(abspath)
            if cmd == "post":
                with open(abspath,"ab") as f:
                    recv_data = 0
                    while recv_data != filesize:
                        data = conn.recv(1024)
                        f.write(data)
                        recv_data += len(data)
                print("上传成功!")
                
                      
sk.close()

client端:

#!/usr/bin/env python3
import socket
import re
import os
BaseDir = os.path.dirname(os.path.abspath(__file__))
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
address = ("127.0.0.1",8000)
for i in range(3):
    try:
        sk.connect(address)
    except Exception as e:
        i += 1
    else:
        break
inp = input(">>>")
if inp == "exit":
    sk.close()
else:
    sk.send(bytes(inp,"utf-8"))
if inp == "chat":   # 聊天
    while True:
        inp = input(">>>")
        if inp == "exit":
            break
        sk.send(bytes(inp,"utf-8"))
        data = sk.recv(1024)
        print(str(data,"utf-8"))
    else:
        sk.close()
elif inp == "remote_control":   # 远程命令
    while True:
        inp = input(">>>")
        if inp == "exit":
            break
        sk.send(bytes(inp,"utf-8"))
        data_len = sk.recv(1024)        # 取得文件长度,bytes()类型
        data_len = int(str(data_len,"utf-8"))   # 取得bytes()数据的长度。整形
#        print(data_len)   # 调式
        sk.send(b"111")
        data_recv = bytes() # 定义一个空的bytes类型
        while len(data_recv) != data_len:    # bytes()类型,长度比较
            data = sk.recv(1024)
            data_recv += data
        print(str(data_recv,"utf-8"))
    else:
        sk.close()
elif inp == "post_file":   # 上传文件
    while True:
        inp = input(">>>")  # 上传文件格式:post|文件路径
        if inp == "exit":
            break
#        elif re.findall(r"post/d*|/d*.*",inp):
        cmd, path = inp.split("|")  # 取得命令及相对路径
        cmd = cmd.strip()
        path = path.strip()
        abspath = os.path.join(BaseDir,path)    # 获得绝对路径
        filename = os.path.basename(abspath)    # 取得文件名
        filesize = os.stat(abspath).st_size     # 取得文件大小,其实是byte()类型的长度,整数
        fileinfo = "%s|%s|%s"%(cmd,filename,filesize) # 信息打包
        print(fileinfo)     # str类型
        sk.sendall(bytes(fileinfo,"utf-8"))    # 发送打包的信息
        import time     # linux下的粘包问题
        time.sleep(1)
        with open(abspath,"rb") as f:   # 以bytes()格式打开文件
            send_data = 0
            while send_data != filesize:
                data = f.read(1024)
                sk.sendall(data)
                send_data += len(data)

posted @ 2019-01-12 15:46  挖坑达人  阅读(15)  评论(0)    收藏  举报