Python网络编程day-2[socket(udp),粘包,简单文件传输]

UDP模式的socket:

  自带迸发连接。

  因为是udp连接所以不可靠

服务端:
import socket
ip = ('127.0.0.1',5333)

server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

server.bind(ip)

while True:
    msg,addr = server.recvfrom(1024)
    print('recv:',msg,addr)

    server.sendto('This is udp scoket server'.encode('utf-8'),addr)


客户端:
import socket

ip = ('127.0.0.1',5333)

client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    msg = input('>>>: ').strip()
    if not msg:continue
    client.sendto(msg.encode('utf-8'),ip)

    server_msg,addr = client.recvfrom(1024)
    print(server_msg.decode('utf-8'),addr)

粘包问题:

  比如我们在写一个简单的ssh  socket程序时,在远程的计算机执行命令返回结果 过长的命令时,会有粘包现象(命令结果一次传输不完,输入下条命令显示的是上一条命令未传输完的结果。)

  造成粘包的问题,是因为命令在执行完结果是保存在 cache中的。

服务端:
import time
import socket
import subprocess

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("",9998))
sock.listen(1)

while True:

    conn,addr = sock.accept() #等待、阻塞
    print("got a new customer",conn,addr)

    while True:

        data = conn.recv(1024) #等待 bytes
        print("received",data)
        if not data: #客户端断开了
            print("conn %s is lost" % str(addr) )
            conn.close() #清除了跟这个断开的链接的实例对象
            break
        #conn.send(data.upper() )
        cmd = subprocess.Popen(data.decode("utf-8"),
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        stdout = cmd.stdout.read()
        stderr = cmd.stderr.read()
        cmd_res = stdout + stderr
        if not cmd_res:
            cmd_res = b'cmd has not output'
        msg_header = str(len(cmd_res)).zfill(10)          #定义 消息头  长度为 10 不足10 使用 数字零填充
        conn.send( bytes(msg_header,encoding='utf-8') )   #发送数据头
        #conn.recv(1)            #给用户发送完信息了等待用户返回 信息接收完的消息
        #time.sleep(0.5)    #这种方式是直接 暂停程序  0.5秒 等待 cache 刷新
        conn.sendall(cmd_res) #不能发空消息


sock.close() #关闭端口和服务

简单的文件传输:

服务端:
import socket
import os,json

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("",9999))
sock.listen(1)

def pack_msg_header(header,header_size):    #文件信息字典处理函数   接收字典和字典指定大小参数
    bytes_header = bytes(json.dumps(header) ,encoding="utf-8")     #转换文件信息字典为 bytes

    if len(bytes_header ) < header_size :#需要补充0       # 计算下变成字节的字典长度   并与指定的字典大小做比较,如果字典小于指定数值
        header['fill'].zfill( header_size - len(bytes_header) )   #向 字典中的 fill 元素 补充对应的零
        bytes_header = bytes(json.dumps(header), encoding="utf-8")  #重新 转换 更改后的字典
    return bytes_header   #返回更改后的字典

while True:

    conn,addr = sock.accept() #等待、阻塞
    print("got a new customer",conn,addr)

    while True:
        raw_cmd = conn.recv(1024) # get test.log      #接收用户输入的指令
        cmd,filename = raw_cmd.decode("utf-8").split()   #切分用户输入的指令 并赋值cmd 和 filename
        if cmd == "get":    #如果cmd 为 get
            msg_header = {"fill": ''}   #创建字典,并初始创建一个fill元素用于控制头文件大小
            if os.path.isfile(filename):      #判断文件是否存在

                msg_header["size"] =  os.path.getsize(filename)     #获取文件大小并添加到字典中
                msg_header["filename"] =  filename            #获取文件名并添加到字典中
                msg_header["ctime"] =  os.stat(filename).st_ctime
                bytes_header = pack_msg_header(msg_header,300)     #调用函数并接收返回值

                conn.send(bytes_header)   #发送给客户端  头部信息

                f = open(filename,"rb")   #以字节模式打开 客户端请求的文件
                for line in f:     #循环取出文件内容并发送
                    conn.send(line)

                else:       #如果文件发送完毕 则  打印信息
                    print("file send done....")
                f.close()     #操作文件完毕关闭文件
            else:      # <============================:如果文件判断不存在则发送相应的信息给客户端
                msg_header['error'] = "file %s on server does not exist " % filename
                bytes_header = pack_msg_header(msg_header, 300)
                conn.send(bytes_header)


sock.close() #关闭端口和服务

客户端:
import socket
import json ,os

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #数据流
sock.connect(('192.168.16.131',9999))

while True:
    cmd = input(">>>:").strip()
    if not cmd : continue
    sock.send(cmd.encode("utf-8"))
    msg_header = sock.recv(300) #接收信息头

    header = json.loads(msg_header.decode("utf-8"))  #反序列化取出文件的字典形式信息
    if header.get("error"):
        print(header.get("error"))
    else:
        filename = header['filename']    #提取字典的值
        file_size = header['size']
        f = open(filename,"wb")
        received_size = 0

        while received_size < file_size :        #切片传输 一次接收8192 字节
            if file_size - received_size < 8192:#last time    #最后一次传输不足 8192 则计算剩余的大小接收 
                data = sock.recv(file_size - received_size)
            else:
                data = sock.recv(8192)

            received_size += len(data)    #已接收的文件大小 自增
            f.write(data)   #写入文件
            #print("recv",received_size,file_size)   #显示 文件的接收过程 因为调用屏幕显示 会减慢传输速度
        else:
            print("file receive done....",filename,file_size)   #传输完毕打印完成
            f.close()   #关闭文件


sock.close()

 

posted @ 2017-07-11 21:53  neuropathy_ldsly  阅读(1018)  评论(0)    收藏  举报