day04-2发送文件

多用户即时通讯系统04

4.编码实现03

4.6功能实现-发送文件功能实现

4.6.1思路分析

客户端(发送者):

  1. 先把文件a.jpg读取到客户端的字节数组
  2. 把文件对应的字节数组封装到message对象[包含文件内容,发送者,接收者]
  3. 将message对象发送到服务端

服务端:

  1. 接收到message对象
  2. 拆解message对象的getteruid,获取接收者用户的通信线程,得到socket
  3. 把message转发给指定用户

客户端(接收者):

  1. 在接收到包含有文件的message消息后,读取对应的文件字节数组,将该数组刷出到磁盘

4.6.2代码实现

1. 客户端:
1.修改MessageType接口

在该接口中拓展消息类型

String MESSAGE_FILE_MES = "8";//表示发送文件消息
2.修改Message类

扩展 和文件相关的成员和方法

//进行扩展 和文件相关的成员
private byte[] fileBytes;
private int fileLen = 0;
private String dest ;//将文件传输到哪里
private String src;//源文件路径

public byte[] getFileBytes() {
    return fileBytes;
}

public void setFileBytes(byte[] fileBytes) {
    this.fileBytes = fileBytes;
}

public int getFileLen() {
    return fileLen;
}

public void setFileLen(int fileLen) {
    this.fileLen = fileLen;
}

public String getDest() {
    return dest;
}

public void setDest(String dest) {
    this.dest = dest;
}

public String getSrc() {
    return src;
}

public void setSrc(String src) {
    this.src = src;
}
3.创建FileClientService

该类完成文件传输服务

package qqclient.service;

import qqcommon.Message;
import qqcommon.MessageType;

import java.io.*;

/**
 * @author 李
 * @version 1.0
 * 该类完成 文件传输服务
 */
public class FileClientService {
    /**
     * @param src      源文件
     * @param dest     把该文件传输到对方的哪个目录
     * @param senderId 发送用户的id
     * @param getterId 接收用户的id
     */
    public void sendFileToOne(String src, String dest, String senderId, String getterId) {
        //读取src文件--封装-->message对象
        Message message = new Message();
        message.setMesType(MessageType.MESSAGE_FILE_MES);//设置为文件类型
        message.setSender(senderId);
        message.setGetter(getterId);
        message.setSrc(src);
        message.setDest(dest);

        //需要将文件读取到程序中
        FileInputStream fileInputStream = null;
        byte[] fileBytes = new byte[(int) new File(src).length()];//创建一个和文件大小对应的字节数组

        try {
            fileInputStream = new FileInputStream(src);
            fileInputStream.read(fileBytes);//将src的文件读入到程序的字节数组
            //将文件对应的字节数组设置成message对象
            message.setFileBytes(fileBytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    //关闭流
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("
" + senderId + " 给 " + getterId + " 发送文件:" + src +
                " 到对方的电脑目录: " + dest);

        //发送
        try {
            //从管理线程的集合中,拿到发送者id的线程,
            // 在该线程对应的属性socket中得到输出流,将输出流转为对象输出流
            ObjectOutputStream oos =
                    new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(senderId).getSocket().getOutputStream());
            oos.writeObject(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
4.修改ClientConnectServerThread类

在在该类中增加接收message消息的类型,并进行相应的操作

else if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) {
    //接收到的是文件类型的消息
    //把服务器转发的message对象
    System.out.println("
" + message.getSender() + " 给 " + message.getGetter() +
            " 发送文件: " + message.getSrc() + " 到我的电脑的目录:" + message.getDest());
    //取出message文件的字节数组,通过文件输出流写出到磁盘
    FileOutputStream fileOutputStream =
            new FileOutputStream(message.getDest());
    fileOutputStream.write(message.getFileBytes());
    fileOutputStream.close();
    System.out.println("
保存文件成功~");
} 

image-20220923191626238

5.修改QQView

1.在该类中创建FileClientService对象

private FileClientService fileClientService = new FileClientService();//该对象用于文件传输

在该类中通过键盘,将用户输入传送到sendFileToOne方法中

image-20220923191656291

case "4":
    System.out.println("请输入你希望发送文件的用户(在线):");
    getterId = Utility.readString(50);
    System.out.println("请输入要发送文件的路径:(形式如:d:\xx.jpg)");
    String src = Utility.readString(100);
    System.out.println("请输入把文件发送到对方电脑下的路径:(形式如:d:\yy.jpg)");
    String dest = Utility.readString(100);
    fileClientService.sendFileToOne(src,dest,userId,getterId);
    break;
2.服务端
1.修改MessageType接口

在该接口中拓展消息类型

 String MESSAGE_FILE_MES = "8";//表示发送文件消息
2.修改Message类

扩展 和文件相关的成员和方法

//进行扩展 和文件相关的成员
private byte[] fileBytes;
private int fileLen = 0;
private String dest ;//将文件传输到哪里
private String src;//源文件路径

public byte[] getFileBytes() {
    return fileBytes;
}

public void setFileBytes(byte[] fileBytes) {
    this.fileBytes = fileBytes;
}

public int getFileLen() {
    return fileLen;
}

public void setFileLen(int fileLen) {
    this.fileLen = fileLen;
}

public String getDest() {
    return dest;
}

public void setDest(String dest) {
    this.dest = dest;
}

public String getSrc() {
    return src;
}

public void setSrc(String src) {
    this.src = src;
}
3.修改ServerConnectClientThread类

在该类的run方法中增加服务端接收文件并转发的业务

else if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) {
    //业务五:客户请求给某用户发送文件
    //根据接收的message对象的getter id 获取到对应的线程,将message对象进行转发
    //拿到线程
    ServerConnectClientThread serverConnectClientThread =
            ManageClientThreads.getServerConnectClientThread(message.getGetter());
    //获取socket,将socket输出流转为对象流
    ObjectOutputStream oos =
            new ObjectOutputStream(serverConnectClientThread.getSocket().getOutputStream());
    //转发
    oos.writeObject(message);
}

image-20220923192138448

运行:

1.运行服务端

image-20220923185336815

2.运行客户端,登录两个用户(100,200)

image-20220923185459644

3.用户100 尝试给用户200 发送文件

用户100:

image-20220923190747258

用户200:

image-20220923190838299

用户200的磁盘下成功接收到文件:

image-20220923190937399

4.服务端

image-20220923191021288

功能实现完毕

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » day04-2发送文件