在局域网下,不同主机之间可以使用socket进行通信。
首先,要获取服务端的ip地址:
1. linux系统:输入命令ifconfig
在这里插入图片描述

2. windows系统:win+R输入cmd进入命令行,输入ipconfig
在这里插入图片描述

在Windows与虚拟机ubuntu下进行了文件传输尝试:
(两种写法类似,都能成功进行文件传输,代码中的IP均为服务端的IP地址
写法一:
服务端server.py

# 服务端
# -*- coding=utf-8 -*-
import socket
import threading
import sys
import os
import struct


def deal_data(conn, addr):
    print('Accept new connection from {0}'.format(addr))
    while True:
        fileinfo_size = struct.calcsize('128sq')  # linux 和 windows 互传 128sl 改为 128sq  机器位数不一样,一个32位一个64位
        buf = conn.recv(fileinfo_size)
        print('收到的字节流:', buf, type(buf))
        if buf:
            print(buf, type(buf))
            filename, filesize = struct.unpack('128sq', buf)
            fn = filename.strip(str.encode('\00'))
            new_filename = os.path.join(str.encode('./'), str.encode('new_') + fn)
            print('file new name is {0}, filesize if {1}'.format(new_filename, filesize))
            recvd_size = 0  # 定义已接收文件的大小
            with open(new_filename, 'wb') as fp:
                print("start receiving...")
                while not recvd_size == filesize:
                    if filesize - recvd_size > 1024:
                        data = conn.recv(1024)
                        recvd_size += len(data)
                    else:
                        data = conn.recv(filesize - recvd_size)
                        recvd_size = filesize

                    fp.write(data)
            print("end receive...")
        conn.close()
        break


def socket_service():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 修改ip,此处ip必须为服务器端的ip ,linux做服务器输入ifconfig得到ip
        s.bind(('192.168.159.128', 5555))
        s.listen(10)
        
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print("Waiting...")
    while True:
        conn, addr = s.accept()
        t = threading.Thread(target=deal_data, args=(conn, addr))
        t.start()


if __name__ == '__main__':
    socket_service()

客户端client.py

# -*- coding=utf-8 -*-

import socket
import os
import sys
import struct


def socket_client():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 修改ip
        s.connect(('192.168.159.128', 5555))# 此处ip必须为服务器端的ip

    except socket.error as msg:
        print(msg)
        sys.exit(1)

    while True:
        filepath = '10.jpg' # 传输文件的路径
        if os.path.isfile(filepath):
            # 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
            fileinfo_size = struct.calcsize('128sq')
            # 定义文件头信息,包含文件名和文件大小
            fhead = struct.pack('128sq', bytes(os.path.basename(filepath).encode('utf-8')), os.stat(filepath).st_size)
            s.send(fhead)
            print('client filepath: {0}'.format(filepath))
            with open(filepath, 'rb') as fp:
                while True:
                    data = fp.read(1024)
                    if not data:
                        print('{0} file send over...'.format(filepath))
                        break
                    s.send(data)
        s.close()
        break


if __name__ == '__main__':
    socket_client()

运行结果:
1.先在linux端运行server.py,再在windows运行client.py,IP地址为linux的ip
linux: 传过来的文件保存在当前文件夹下,并在文件名前加前缀new_
在这里插入图片描述
windows:
在这里插入图片描述
2. windows作服务端,linux作客户端,ip地址均改为windows的ip
windows:
在这里插入图片描述
linux:
在这里插入图片描述

写法二:注意两个IP地址都为服务器端的IP!
服务端service.py

import socket
import os
import sys
import struct

def socket_service_image():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('192.168.159.128', 6000))
        s.listen(10)

    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print("Wait for Connection.....................")
    while True:
        sock, address = s.accept()  # addr是一个元组(ip,port)
        deal_image(sock, address)


def deal_image(sock, address):
    print("Accept connection from {0}".format(address))  # 查看发送端的ip和端口
    while True:
        fileinfo_size = struct.calcsize('128sq')  # 返回格式字符串fmt描述的结构的字节大小
        print('fileinfo_size is', fileinfo_size)
        buf = sock.recv(fileinfo_size)  # 接收图片名
        print('buf is ', buf)
        if buf:  # 如果接收到了数据就开始接下来的操作
            filename, filesize = struct.unpack('128sq', buf)  # 按照客户端打包的格式进行解包,得到图片的名字和图片大小
            print('filename :', filename.decode(), 'filesize :', filesize)
            # fn = filename.decode().strip('\x00')  # 其实,这里的filename已经是解码完毕去掉字节符号的样子了,我感觉这一步是多此一举
            fn = filename.strip(str.encode('\00'))
            print('fn is ', fn)
            new_filename = os.path.join(str.encode('./'), str.encode('new_') + fn)
            print(new_filename)

            # 在服务器端新建图片名(可以不用新建的,直接用原来的也行,只要客户端和服务器不是同一个系统或接收到的图片和原图片不在一个文件夹下)

            recvd_size = 0
            fp = open(new_filename, 'wb')  # 二进制打开文件

            while not recvd_size == filesize:  # 如果收到的直接总数不等于这个文件的直接总数,那么就继续接受数据
                if filesize - recvd_size > 1024:  # 这个最后一次如果数据比
                    data = sock.recv(1024)  # 每次从客户端接受1024个字节
                    recvd_size += len(data)  # 每次都记录好收到的字节数,然后叠加上去

                else:  # 这个最后一次数据如果比1024少的话那么这一次读完就OK了,而且这次结束后循环也就结束了
                    data = sock.recv(1024)
                    recvd_size = filesize
                    print('data is', data)  # 输出每一次收到的数据
                fp.write(data)  # 写入图片数据,因为每次都是读取到1024个字节,所以每一次读取都需要把得到的字节进行拼凑
            fp.close()

        sock.close()

        break


if __name__ == '__main__':
    socket_service_image()

客户端client.py

import socket
import os
import sys
import struct

def sock_client_image():
    while True:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect(('192.168.159.128', 6000))
        except socket.error as msg:
            print(msg)
            print(sys.exit(1))

        file_path = 'a.jpg'  # 输入当前目录下的图片名
        # pack按照图片格式、图片名字、图片大小

        fhead = struct.pack(b'128sq',  # 图片打包的格式为128sq
                            bytes(os.path.basename(file_path), encoding='utf-8'),  # 返回图片文件名,编码字节化
                            os.stat(file_path).st_size)  # 返回读取文件的相关属性,然后得到其中st_size的数据(记录文件大小)
        s.send(fhead)
        fp = open(file_path, 'rb')  # 打开要传输的图片

        while True:
            data = fp.read(1024)  # 读入图片数据,data是图片的数据字节流(由于图片字节很多,这里一次只读取1024个字节)
            if not data:  # 如果读到字节的数据没有了
                print('{0} send over...'.format(file_path))
                break
            s.send(data)  # 以二进制格式发送图片数据(每次发1024个字节)
        s.close()
        break  # 如果需要一直发送图片则需要在这里进行修改


if __name__ == '__main__':
    sock_client_image()

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐