笔记:网络编程,多线程传输文件,文件名字和内容不用不同流封装来传

网络编程:

网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用。

网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的

1.InetAddress

此类表示互联网协议 (IP) 地址。

IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议;

  • UDP 和 TCP 协议都是在它的基础上构建的。

IP 地址的体系结构是由 RFC 790:Assigned Numbers、 RFC 1918:Address Allocation for Private Internets、RFC 2365:Administratively Scoped IP Multicast 和 RFC 2373:IP Version 6 Addressing Architecture 定义的。

InetAddress 的实例包含 IP 地址,还可能包含相应的主机名(取决于它是否用主机名构造或者是否已执行反向主机名解析)

1.InetAddress.getLocalHost():返回本地主机。

2.localHost.getHostName():获取此 IP 地址的主机名。

  • 如果此 InetAddress 是用主机名创建的,则记忆并返回主机名;

  • 否则,将执行反向名称查找并基于系统配置的名称查找服务返回结果。

3.localHost.getHostAddress():返回 IP 地址字符串(以文本表现形式)

4.InetAddress.getByName(“www.baidu.com”):在给定主机名的情况下确定主机的 IP 地址。

  • 主机名可以是机器名(如 “java.sun.com”),
  • 也可以是其 IP 地址的文本表示形式。
  • 如果提供字面值 IP 地址,则仅检查地址格式的有效性。

5.getHostAddress():返回 IP 地址字符串(以文本表现形式)。

InetAddress localHost = InetAddress.getLocalHost();
System.out.println("Host Name:" + localHost.getHostName());
System.out.println("Host Address(IP):" + localHost.getHostAddress());

InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println("baidu ip:" + baidu.getHostAddress());

1.url

  • URL url = new URL(“http://www.runoob.com/html/html-tutorial.html”);

  • 根据 String 表示形式创建 URL 对象。

2.url.openConnection():

返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。**

3.connection.getInputStream():

返回从此打开的连接读取的输入流。 在读取返回的输入流时,如果在数据可供读取之前达到读入超时时间,则会抛出 SocketTimeoutException。

URL url = new URL("http://www.runoob.com/html/html-tutorial.html");

/*获取此 URL 的协议名称*/
System.out.println("Protocol:" + url.getProtocol());
/*获取此 URL 的主机名(如果适用)*/
System.out.println("Host:" + url.getHost());
/*获取此 URL 的端口号*/
System.out.println("Port:" + url.getPort());
/*获取此 URL 的路径部分。*/
System.out.println("Path:" + url.getPath());

// 建立网络连接
URLConnection connection = url.openConnection();
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

Socket

1.ServerSocket服务端

  • new ServerSocket(9000):创建绑定到特定端口的服务器套接字。端口 0 在所有空闲端口上创建套接字。传入连接指示(对连接的请求)的最大队列长度被设置为 50。如果队列满时收到连接指示,则拒绝该连接。如果应用程序已指定服务器套接字工厂,则调用该工厂的 createSocketImpl 方法来创建实际套接字实现。否则创建“普通”套接字。
  • accept():侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞,如果接收到客户端请求则建立连接
  • socket.getInputStream():返回此套接字的输入流。
try (ServerSocket ss = new ServerSocket(9000)) {
    System.out.println("Server Started......");
    // 此方法会等待客堵塞。户端请求,如果接收到客户端请求则建立连接
    Socket socket = ss.accept();
    /*得到上传流*/
    BufferedReader serverReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // 得到上传的文件名,随后要以这个文件名去写文件
    String uploadFileName = serverReader.readLine();
    // 写出的目标文件
    File destFile = new File("d:\\ftp\\" + uploadFileName);

    System.out.println(uploadFileName);

    char[] cbuf = new char[1024];
    int len = -1;
    while((len = serverReader.read(cbuf)) != -1){
        //写本地文件
        FileUtils.writeStringToFile(destFile, new String(cbuf,0,len), "UTF-8", true);
    }

} catch (IOException e) {
    e.printStackTrace();
}

2.socket客户端

  • new Socket(“localhost”,9000):创建一个流套接字并将其连接到指定主机上的指定端口号。如果指定的主机为 null,则等效于指定与 InetAddress.getByName(null) 相同的地址。换句话话,等效于指定回送接口的地址。如果应用程序已指定服务器套接字工厂,则调用该工厂的 createSocketImpl 方法来创建实际套接字实现。否则创建“普通”套接字。
  • FileUtils.readFileToString(file, “UTF-8”):Reads the contents of a file into a String. The file is always closed.将文件转换为字符串;
  • socket.getOutputStream():返回此套接字的输出流。
 		try (Socket socket = new Socket("localhost",9000)){
            // 获得要上传的文件名
            File file = new File("D:\\练习\\second.txt");
            String fileName = file.getName();

            // 1. 先把要上传的文件名发送到服务器端
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            printWriter.write(fileName + "\n");
            printWriter.flush();

            // 2. 发送文件数据到服务器端
            String data = FileUtils.readFileToString(file, "UTF-8");
            printWriter.write(data);
            printWriter.flush();


        } catch (Exception e) {
            e.printStackTrace();
        }

多线程ftp传输文件

多个文件的一起传输主要用到:

  • 文件路径的创建与文件的选择过滤
  • 文件名字和内容要用不同的流来传输,巧妙运用字符流的readLine();
  • 文件名字用字符流接收传输,内容用字节流传输;
  • 线程的sleep;

1.客户端上传文件:

  • dir.listFiles():

    • 返回:返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录
    • 参数:filter - 文件名过滤器
    		/*箭头函数表示文件过滤器*/
    		/*(dir, name) -> {return name.endsWith("jpg");}*/		
    		File[] files = fileDir.listFiles((dir, name) -> {
                return name.endsWith("jpg");
            });
    
package ftp.ftpReviews;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * @author lz先生
 * @Date: 2020/3/20/020
 */
public class ClientUpload {

    public static void main(String[] args) {
        /*1.先找文件夹*/
        File fileDir = new File("D:\\练习");
        /*文件过滤器*/
        File[] files = fileDir.listFiles((dir, name) -> {
            return name.endsWith("jpg");
        });

        /*2.遍历上传文件,每个文件一个开启socket连接*/
        for (File file : files) {
            try (Socket socket = new Socket("127.0.0.1", 8888);){
                System.out.println("客户端上传文件:" + file.getName());
                /*先将文件名字写在第一行*/
                PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
                /*换行一定写*/
                printWriter.println(file.getName() + "\n");
                printWriter.flush();

                /*字节流写文件内容*/
                FileInputStream fileInputStream = new FileInputStream(file);
                byte[] bytes = new byte[1024 * 1024];
                int len = -1;
                while((len = fileInputStream.read(bytes)) != -1){
                    socket.getOutputStream().write(bytes, 0 , len);
                }
                socket.getOutputStream().flush();

                /*线程暂停一会*/
                Thread.sleep(1000);

            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

2.服务器接收文件

package ftp.ftpReviews;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;

/**
 * @author lz先生
 * @Date: 2020/3/20/020
 */
public class ServerAccept {
    public static void main(String[] args) {

        try {
            /*1.要传到的位置*/
            File fileDir = new File("D:\\练习\\copy");
            if (!fileDir.exists()) {
                /*目录不存在创建*/
                FileUtils.forceMkdir(fileDir);
                //fileDir.mkdirs();
            }
            /*2.启动服务器*/
            ServerSocket ss = new ServerSocket(8888);
            System.out.println("服务器启动了...");

            /*3.新建线程传输文件*/
            while (true) {
                new Thread(new FileUploadThread(ss.accept(),fileDir)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

3.传输文件线程

package ftp.ftpReviews;
import java.io.*;
import java.net.Socket;

/**
 * @author lz先生
 * @Date: 2020/3/20/020
 */
public class FileUploadThread implements Runnable {

    private Socket socket;
    private File fileDir;

    public FileUploadThread(Socket socket, File fileDir) {
        this.socket = socket;
        this.fileDir = fileDir;
    }

    @Override
    public void run() {
        FileOutputStream fileOutputStream = null;
        try {
            /*1.获得输入流*/
            InputStream inputStream = socket.getInputStream();
            /*2.字符流读取第一行文件名字*/
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String fileName = reader.readLine();
            System.out.println(fileName + ":开始上传");
            /*3.生成文件字节输出流*/
            File file = new File(fileDir, fileName);
            fileOutputStream = new FileOutputStream(file);
            /*4.读写文件*/
            byte[] bytes = new byte[1024 * 1000];
            int len = -1;
            while (!socket.isInputShutdown() && (len = inputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes, 0, len);
            }
            System.out.println(fileName + ":接收完毕");
        } catch (Exception e) {
        }finally {
            try {
                fileOutputStream.flush();
                fileOutputStream.close();

                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值