【大数据开发】Java语言基础——TCP编程、Stream流式操作day23

一、知识准备

在这里插入图片描述

二、TCP编程

1.TCP客户端步骤

package day23.tcp1;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;


public class TcpClient {
    public static void main(String[] args) throws IOException {
        //1.
        //这行代码执行成功,说明客户端创建成功
        //说明客户端和服务器端连接成功,实际上就是这个socket对象
        //Socket中既有字输入流,也有字节输出流
        Socket socket = new Socket(InetAddress.getByName("10.20.152.10"), 11111);

        //2.
        //向服务器端发送数据,也就是使用字节输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,你好".getBytes());

        //3.
        //接收数据
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[50];
        int length = inputStream.read(bytes);
        System.out.println(new String(bytes,0,length));

        //4.
        //关闭socket
        socket.close();
    }

}

2.TCP服务器端步骤

服务器端向和哪个客户通信,需要得到客户端的Socket对象

package day23.tcp1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
    public static void main(String[] args) throws IOException {
        //1.
        //创建ServerSocket对象的同时,监听端口
        ServerSocket serverSocket = new ServerSocket(11111);

        //2.
        //服务器端需要得到一个客户端是Socket对象,从而保证和客户端使用相同的通道(Socket流)
        Socket socket = serverSocket.accept();
        System.out.print(InetAddress.getByName("10.20.152.10")+ ":");
        //3.
        //接收客户端发送的数据
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[50];
        int length = inputStream.read(bytes);
        System.out.println(new String(bytes,0,length));

        //4.
        //给客户端发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("我已经收到信息!谢谢".getBytes());
        socket.close();
    }
}

3.运行结果:

在这里插入图片描述
在这里插入图片描述

4.总结

在这里插入图片描述

4.练习

(1)大小写转换
客户端

public class ChangeClient {
    /*
     实现一个大写转换服务器:客户端读取键盘输入的小写字符串,发送给服务器端
	                      服务器端读取客户端发送的小写字符串,转成大写,再发给客户端

	    客户端:
	    1.读取键盘输入的小写字符串
	    2.把小写字符串发送给服务器端
	    3.接收服务器端发送过来的大写字符串
     */
    public static void main(String[] args) throws IOException {
        System.out.println("客户端启动了......");
        //创建客户端对象
        Socket socket=new Socket(InetAddress.getByName("10.20.152.61"),17878);

        //创建读取键盘输入的小写字符串的字符缓冲读取流
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));

        //创建把小写字符串发送给服务器端的字符输出流
        OutputStream out = socket.getOutputStream();
        PrintWriter prinWriter=new PrintWriter(out,true);

        //创建接收服务器端发送过来的大写字符串的字符输入流
        InputStream in = socket.getInputStream();
        BufferedReader br=new BufferedReader(new InputStreamReader(in));

        //反复读取键盘输入的数据,发送给服务端
        String line=null;
        while ((line=bufferedReader.readLine())!=null)
        {
            if("over".equals(line))
                break;
            //把数据发送给服务端
            prinWriter.println(line);
            //读取服务器返回的大写数据
            System.out.println(br.readLine());
        }

        bufferedReader.close();
        socket.close();

    }
}

服务端

public class ChangeServer {

    /*
     实现一个大写转换服务器:客户端读取键盘输入的小写字符串,发送给服务器端
	                      服务器端读取客户端发送的小写字符串,转成大写,再发给客户端

	    服务端:
	    1.读取客户端发送的小写字符串
	    2:把大写字符串发送给客户端
     */
    public static void main(String[] args) throws IOException {

        System.out.println("服务端启动了。。。。");

        //创建服务端对象
        ServerSocket serverSocket=new ServerSocket(17878);

        //得到客户端对象
        Socket socket = serverSocket.accept();
        System.out.println(socket.getInetAddress().getHostAddress()+":");

        //读取客户端发送的小写字符串
        InputStream in = socket.getInputStream();
        BufferedReader br=new BufferedReader(new InputStreamReader(in));

        //把大写字符串发送给客户端
        OutputStream out = socket.getOutputStream();
        PrintWriter pw=new PrintWriter(out,true);

        //反复读取客户端发送过来的数据
        String line=null;
        while((line=br.readLine())!=null){
            pw.println(line.toUpperCase());
        }

        //socket.close();


    }
}

(2)文本文件的上传
客户端

public class UploadClient {
    //实现文本文件的上传:把文件从客户端上传到服务端,上传完成时,服务端返回"上传成功",客户端显示 “上传成功”
    /*
      1。客户端读取本地文件
      2:把读取的本地文件的内容发送到服务端
      3.读取服务端返回的 上传成功
     */
    public static void main(String[] args) throws IOException {

        //创建客户端对象
        Socket socket=new Socket(InetAddress.getByName("10.20.152.61"),18989);

        //创建读取本地文件的字符读取流
        BufferedReader bufferedReader=new BufferedReader(new FileReader("files\\temp.java"));

        //把读取的本地文件的内容发送到服务端,创建字符输出流
        OutputStream outputStream = socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream,true);

        //读取服务端返回的 上传成功,创建字符输入流
        InputStream inputStream = socket.getInputStream();
        BufferedReader br=new BufferedReader(new InputStreamReader(inputStream));

        //循环读取本地文件,发送到服务端
        String line=null;
        while((line=bufferedReader.readLine())!=null)
        {
            printWriter.println(line);
        }
        socket.shutdownOutput();//给服务端一个结束标记

        bufferedReader.close();

        //读取服务端返回的 上传成功
        String result = br.readLine();
        System.out.println(result);

        socket.close();

    }
}


服务端

public class UploadServer {
     //实现文本文件的上传:把文件从客户端上传到服务端,上传完成时,服务端返回"上传成功",客户端显示 “上传成功”
    /*
    1;接收客户端发送的数据
    2:把数据写到服务端的某个文件中
    3:给客户端发送 "上传成功"
     */
    public static void main(String[] args) throws IOException {

        //创建服务端对象
        ServerSocket serverSocket=new ServerSocket(18989);

        //得到客户端对象
        Socket socket = serverSocket.accept();
        System.out.println(socket.getInetAddress().getHostAddress()+":");

        //创建接收客户端发送的数据的字符读取流
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));

        //把数据写到服务端的某个文件中,创建文件输出流
        BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("files\\temp_copy.java"));

        //给客户端发送 "上传成功"
        OutputStream outputStream = socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream,true);

        //反复读取客户端发送的数据,写入到服务端文件
        String line=null;
        while((line=bufferedReader.readLine())!=null)//循环读取的是客户端,所以读不到null
        {
            bufferedWriter.write(line);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        bufferedWriter.close();

        printWriter.println("上传成功");//循环没结束,所以没能发送"上传成功"

        socket.close();
        serverSocket.close();
    }
}

注意这题客户端应当加入结束标记socket.shutdownOutput(),因为流的发送不可能发送null过去,服务端不能接收到null。
1.在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
2.通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
3.如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket

(3)图片文件上传
客户端

public class UploadPicClient {
    public static void main(String[] args) throws IOException {

        Socket socket=new Socket(InetAddress.getByName("10.20.152.61"),19999);

        //创建读取本地图片的字节输入流
        FileInputStream fileInputStream=new FileInputStream("images\\33.jpg");

        //创建向服务端发送数据的字节输出流
        OutputStream outputStream = socket.getOutputStream();

        //创建读取服务端返回数据的字节输入流
        InputStream inputStream = socket.getInputStream();

        //反复读取本地文件,发送到服务端
        byte[] arr=new byte[1024];
        int num=0;
        while((num=fileInputStream.read(arr))!=-1)
        {
            outputStream.write(arr,0,num);
        }
        socket.shutdownOutput();//写入结束标记
        fileInputStream.close();

        byte[] b=new byte[20];
        num = inputStream.read(b);
        System.out.println(new String(b,0,num));

        socket.close();

    }
}

服务端

public class UploadPicServer {

    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket=new ServerSocket(19999);

        Socket socket = serverSocket.accept();
        System.out.println(socket.getInetAddress().getHostAddress()+":");

        //创建读取客户端数据的输入流
        InputStream inputStream = socket.getInputStream();

        //创建写入到本地文件的字节输出流
        FileOutputStream fileOutputStream=new FileOutputStream("images\\33_copy.jpg");

        //创建发送数据字节输出流
        OutputStream outputStream = socket.getOutputStream();

        //反复读取客户端,写入到本地文件
        byte[] arr=new byte[1024];
        int num=0;
        while((num=inputStream.read(arr))!=-1)
        {
            fileOutputStream.write(arr,0,num);
        }

        fileOutputStream.close();

        outputStream.write("上传成功".getBytes());

        socket.close();
        serverSocket.close();


    }
}

(4)多线程上传图片
客户端

public class UploadPicClient {
    public static void main(String[] args) throws IOException {

        Socket socket=new Socket(InetAddress.getByName("10.20.152.61"),19999);

        //创建读取本地图片的字节输入流
        FileInputStream fileInputStream=new FileInputStream("images\\33.jpg");

        //创建向服务端发送数据的字节输出流
        OutputStream outputStream = socket.getOutputStream();

        //创建读取服务端返回数据的字节输入流
        InputStream inputStream = socket.getInputStream();

        //反复读取本地文件,发送到服务端
        byte[] arr=new byte[1024];
        int num=0;
        while((num=fileInputStream.read(arr))!=-1)
        {
            outputStream.write(arr,0,num);
        }
        socket.shutdownOutput();//写入结束标记
        fileInputStream.close();

        byte[] b=new byte[20];
        num = inputStream.read(b);
        System.out.println(new String(b,0,num));

        socket.close();

    }
}

服务端
服务端分为两个文件,多线程接收文件

public class UploadPicture implements Runnable {

    private Socket socket;
    UploadPicture(Socket socket)
    {
        this.socket=socket;
    }

    @Override
    public void run() {
           String ip = socket.getInetAddress().getHostAddress();
           System.out.println(ip+":");

           //上传的文件统一放在一个目录下
           File dir=new File("f:\\files");
           if(!dir.exists())
               dir.mkdir();

           int num=0;
           File file=new File(dir,ip+"("+num+")"+".jpg");

           while(file.exists()){
               file=new File(dir,ip+"("+(++num)+")"+".jpg");
           }

         try {
            InputStream inputStream = socket.getInputStream();//读取客户端数据的输入流

            FileOutputStream fileOutputStream=new FileOutputStream(file);

            OutputStream outputStream = socket.getOutputStream();

            byte[] arr=new byte[1024];
            int len=0;
            while((len=inputStream.read(arr))!=-1)
            {
                fileOutputStream.write(arr,0,len);
            }
            fileOutputStream.close();

            outputStream.write("上传成功".getBytes());

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

public class Program {

    public static void main(String[] args) throws IOException {
        //创建服务端对象
        ServerSocket serverSocket=new ServerSocket(19999);
        while(true) {

           Socket socket = serverSocket.accept();
           new Thread(new UploadPicture(socket)).start();
        }

    }
}

三、Stream类

集合的流式编程: jdk1.8 出现的,多数需要结合着lambda使用。目的是简化代码

  •  Collection
    
  •      Stream<E>  stream()
    
  •  数组
    
  •      Stream<T> stream(T[] array)
    
  • JDK8加入 了 java.util.stream包,实现了集合的流式操作,流式操作包括集合的过滤,排序,映射等功能。根据流的操作性,又可以分为串行流 和 并行流。
  • 根据操作返回的结果不同,流式操作又分为中间操作和最终操作。大大方便了我们对于集合的操作。
  • Stream 不是集合元素,也不是数据结构,它相当于一个高级版本的 Iterator,不可以重复遍历里面的数据,像水一样,流过了就一去不复返。它和普通的 Iterator 不同的是,它可以并行遍历,
  • 普通的 Iterator 只能是串行,在一个线程中执行。

1.最终操作

public class Demo1 {

    public static void main(String[] args) {

          ArrayList<Integer> list=new ArrayList<>();
          Collections.addAll(list,10,30,20,50,40);

          //获取流的方式,流中是集合中的数据,通过流来方便操作数据,集合中的数据本身是没有改变的
          Stream<Integer> stream = list.stream();//得到的是串行流
          Stream<Integer> integerStream = list.parallelStream();//得到的是并行流
          int[] arr={34,45,56};
          IntStream stream1 = Arrays.stream(arr);

          //对流的操作分为最终操作和中间操作
          //执行了最终操作,流就关闭了,执行的是中间操作,还会返回该流对象
        //最终操作
        //collect():将流中的数据收集到一起,对这些数据进行一些处理,返回一个新的集合
        List<Integer> lists = list.stream().collect(Collectors.toList());//把流中的数据存储到Collectors.toList()返回的集合对象中
        System.out.println(lists);

        Set<Integer> sets = list.stream().collect(Collectors.toSet());
        System.out.println(sets);

        //需要指定键生成的规则,值生成的规则
        Map<Integer, Integer> map = list.stream().collect(Collectors.toMap(e -> e / 10, e -> e));
        System.out.println(map);
        //reduce():将流的元素, 逐一带入到这个方法中,进行运算,最终的运算结果,得到的其实是一个Optional类型,需要使用get() 获取到里面的数据
        Integer integer = list.stream().reduce((e1, e2) -> e1 + e2).get();//reduce方法的返回值是Optional类型的,需要调用get方法得到结果值
        System.out.println(integer);

        //count():统计流中的元素数量。
        long count = list.stream().count();
        System.out.println(count);

        //forEach():遍历每个元素。
        list.stream().forEach(System.out::println);

        //min(): 找到最小值,需要使用get() 获取到里面的数据
        Integer integer1 = list.stream().min((e1, e2) -> e2 - e1).get();
        System.out.println(integer1);
        //max():找到最大值,需要使用get() 获取到里面的数据
        Integer integer2 = list.stream().max((e1, e2) -> e1 - e2).get();
        System.out.println(integer2);

        //allMatch:只有当流中所有的元素,都匹配指定的规则,才会返回true
        boolean b = list.stream().allMatch(e -> e > 5);
        System.out.println(b);
        // anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
        boolean b1 = list.stream().anyMatch(e -> e % 2 == 0);
        System.out.println(b1);
        //noneMatch:只有当流中的所有的元素,都不满足指定的规则,才会返回true
        boolean b2 = list.stream().noneMatch(e -> e > 60);
        System.out.println(b2);

        //findFirst:从流中获取一个元素(一般情况下,是获取的开头的元素),需要使用 get() 获取到里面的数据
        Integer integer3 = list.stream().findFirst().get();
        integer3 =list.parallelStream().findFirst().get();
        System.out.println(integer3);

        //findAny:从流中获取-一个元素(一般情况下,是获取的开头的元素)p,需要使用get() 获取到里面的数据
        Integer integer4 = list.stream().findAny().get();
        integer4=list.parallelStream().findAny().get();
        System.out.println(integer4);

        //在多线程的环境下,findAny 和findFirst返回的结果可能不一样。
      /*
        Stream<Integer> stream2 = list.stream();
        System.out.println(stream2.count());//执行完该最终操作,流会关闭
        stream2.forEach(System.out::println);//再次使用流时,会异常  java.lang.IllegalStateException

       */
    }
}

2.中间操作

public class Demo2 {

    public static void main(String[] args) {

         ArrayList<Integer> list=new ArrayList<>();
        Collections.addAll(list,10,20,30,30,60,15);
        //中间操作:可以连续操作,每一个操作的返回值都是一个Stream对象,可以继续进行其他的操作。直到最终操做
        //filter(): 对元素进行过滤
        //list.stream().filter(e->e>20).forEach(System.out::println);

        //distinct():去除重复的元素,去重的规则与HashSet相同。
        //list.stream().distinct().forEach(System.out::println);
        //sorted():对元素排序
        //list.stream().sorted().forEach(System.out::println);//流中的数据所属的类必须实现Comparable接口
        //list.stream().sorted((e1,e2) ->e2-e1).forEach(System.out::println);
        //limit():   截取流中指定数量的元素
        //list.stream().limit(3).forEach(System.out::println);
        //skip():   跳过流中的指定数量的元素
        //list.stream().skip(3).forEach(System.out::println);

        //list.stream().skip(4).limit(1).forEach(System.out::println);
        //map():对流中的数据进行映射,用新的数据替换旧的数据。
        list.stream().map(e->e==10?true:false).forEach(System.out::println);
        System.out.println(list);

        //flatmap(): 扁平化映射,常用于map直接映射完成后,流中的数据是一个个的容器,而我们需要对容器中的元素进行处
        String[] arr={"h,e,l,l,o","w,o,r,l,d"};
        Arrays.stream(arr).map(e->e.toCharArray()).forEach(e->System.out.println(Arrays.toString(e)));
        //map映射之前是几个数据,映射之后还是几个,flatMap 是合并成一个
        Arrays.stream(arr).map(e->e.split(",")).flatMap(e->Arrays.stream(e)).distinct().forEach(System.out::println);

        //mapToInt():将流中的数据替换成int类型
        String[] b={"234","567"};
        double asDouble = Arrays.stream(b).mapToInt(e -> Integer.parseInt(e)).average().getAsDouble();
        System.out.println(asDouble);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值