java学习笔记18------网络(客户端Socket类,URL类,服务器端SeverSocket类),lambda表达式

刚开始学习的Java的同学可以参考我的博客,我是Java小白,刚刚入行,写的东西也都是基础知识,不过今天看到我增了四个粉丝,虽然很少,但也很开心,哈哈哈。。继续坚持!!!!
第一部分:客户端
(一).#TCP/IP协议线的概念:传输控制协议TCP,网络地址协议IP。
分为四层:
##1.应用层常用协议:
http 超文本传输协议(访问网页)。
telnet远程登录协议
ssh远程登录(保证安全)
##2传输层常用协议:
打包数据,确定目的的应用程序。
TCP (保障数据的可靠有序)、UDP(不保证)
http 占用 80号端口
telnet 22号端口
##3.互联网层协议
IP协议
##4.网络访问层协议
###例子1:
控制命令黑窗口中输入:
连接: telnet 对方IP 端口号
发送请求:http协议
GET /index.html(路径) HTTP/1.1 或者GET /time(time)HTTP/1.1
Host: localhost
回车
回车
响应:HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 20
Date: Sat, 24 Nov 2018 01:37:25 GM
Nov 24 2018 09:37:25
上面的是响应头,主要是对内容的大概的概括;说明了内容的类型,编码格式,内容长度,日期等等。
(二)#Socket类
Socket类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
其实Socket 就是一个端点,用于通信的端点 ,底层:是TCP协议。
构造方法:Socket(String host,int port)// 创建一个流套接字并将其连接到指定主机上的指定端口号。
socket.getOutputStream(); // 发数据,即把数据写到流中发出去。
socket.getInputStream(); // 收数据
新建Socket对象 Socket socket = new Socket(“192.168.3.123”,80);的过程中实现了三次握手:
客户端-》服务器; 服务器-》客户端; 客户端-》服务器?????前面两次是询问是否可以连接,最后是传送数据。
关闭Socket用close();
代码实现如下:

public class DemoSocket {
    public static void main(String[] args) throws IOException {
        //创建Socket对象
        Socket socket = new Socket("192.168.3.123",80);
        //发送数据
        OutputStream out=socket.getOutputStream();
        out.write("GET /index.html HTTP/1.1\n".getBytes());
        out.write("Host: localhost\n".getBytes());
        out.write("\n".getBytes());
        out.write("\n".getBytes());
        //接收数据
        InputStream in=socket.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
        while(true){
            String line = reader.readLine();
            if(line==null){
                break;
            }
            System.out.println(line);
        }
        socket.close();
    }
}

(三).##URL类
URL统一资源定位符 ,它是指向互联网“资源”的指针。
参数:http://ip地址:端口/资源地址
创建对象:new URL(http://ip地址:端口/资源地址)
注:127.0.0.1是访问自己电脑的Ip地址,等价于localhost
HttpURLConnection conn= (HttpURLConnection) url.openConnection();//建立连接,发送get请求;
Conn.getInputStream();//拿到服务器返回的结果。
HttpURLConnection是支持 HTTP 特定功能的 URLConnection。
方法:openConnection()返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。
URL类与Socket类不同的地方在于URL类是没有头信息的,所以在下载网页图片的时候,可以选用URL类;
关闭时调用disconnect()方法;不是close()方法。
代码如下:

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

        //创建URL对象
        URL url=new URL("http://192.168.3.123:80/index.html");
        //建立连接
        HttpURLConnection connection=(HttpURLConnection) url.openConnection();
        //发送数据
        OutputStream out = connection.getOutputStream();
        out.write("GET /index.html HTTP/1.1\n".getBytes());
        out.write("Host: localhost\n".getBytes());
        out.write("\n".getBytes());
        out.write("\n".getBytes());
        //接收数据,可以用字节流读,也可以用字符流读
        InputStream in=connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
        while(true){
            String line = reader.readLine();
            if(line==null){
                break;
            }
            System.out.println(line);
        }
        connection.disconnect();
    }
    }

(四)小结:
#各种客户端
1.telnet 了解
浏览器 谷歌,火狐(编程一般用这两个)知道常用的浏览器;
2.Socket类
Socket是传输层的TCP;
(1).创建Scoket对象 new Scoket(“IP地址”,端口号);
(2).发数据 socket.getOutputStream();
(3).收数据socket.getInputstream();
3.URL类(比较重要)
(1).创建URL new URL(“http://IP地址:端口号/资源地址”);
(2).建立连接,发送get请求 HttpURLConnection connect=(HttpURLConnection)url.openConnection();
(3).拿到服务器返回的结果,即接收数据;connect.InputStreram();
第二部分:服务器端
(一)1.阻塞IO ( blocking IO ,简称BIO)
ServerSocket 服务器的端点;
New ServerSocket(端口号);//每个程序只能占用一个端口
自己的程序最好用四位以上的接口。
Server.accept();//等待客户端来连接
阻塞IO的特点:一个socket执行IO的读写操作时会阻塞其他的IO读写
一个线程内的IO的读写是串行的,解决方法:多线程。
代码如下:创建一个客户端Client,一个服务器端Server1

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 5000);
        OutputStream out = socket.getOutputStream();
        out.write("hello\n".getBytes());
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
        while (true) {
            int len = in.read(bytes);
            if (len == -1) {
                break;
            }
            String s = new String(bytes, 0, len,"UTF-8");
            System.out.print(s);
        }
        socket.close();
    }
}

public class Server1 {
    public static void main(String[] args) throws IOException {
        //创建服务器端口
        ServerSocket serverSocket = new ServerSocket(5000);
        while(true){
            //等待客户端响应
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Socket socket= null;
                    try {
                        socket = serverSocket.accept();
                        System.out.println("服务器连接中...");
                        //输出服务器端响应,并反馈给客户端
                        handle(socket);//抽取成了方法ctrl+art+M
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
}
private static void handle(Socket socket) throws IOException {
        InputStream in=socket.getInputStream();
        OutputStream out=socket.getOutputStream();
        byte[] bytes=new byte[1024*8];
        while(true){
            int len= in.read(bytes);
            if(len==-1){
                break;
            }
            String s=new String(bytes,0,len);
            System.out.print(s);
            out.write(("返回的响应"+s).getBytes("UTF-8"));
        }
        in.close();
        out.close();

    }
}

2.每次New一个线程太浪费资源,选用线程池。
(1)了解下手动创建线程池
手动创建线程池:TreadPoolExecutor
ExecutorService service=new ThreadPoolExector(corePoolSize,maximuPoolSize, keepAliveTime,timeUnit,BlockingQueue);
其中参数的意义:
corePoolSize:核心线程数。
maximuPoolSize:最大线程数,核心线程数+救急线程数<=最大现线程数。
keepAliveTime:保持时间,如果空暇线程的时间超过了这个时间,那就把线程收回。
timeUnit 时间的单位 ;timeUnit.SECONDS代表秒。
BlockingQueue:阻塞队列;分为有界的阻塞队列:例如ArrayBlockingQueue<>(10);
无界的阻塞队列:例如LinkedBlockingQueue<>();
(2)看newFixedThreadPool的源码理解下线程池是怎么创建的:
源码为:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
代码如下:

public class Server2 {
    public static void main(String[] args) throws IOException {
        //创建服务器端口
        ServerSocket serverSocket = new ServerSocket(6000);
        ExecutorService service = Executors.newFixedThreadPool(10);
        //手动创建线程池
        //ExecutorService service1 =new ThreadPoolExecutor(5,10,0L, 
               // TimeUnit.SECONDS,new ArrayBlockingQueue<>(10));
        while(true){
            //等待客户端响应
            //每次都new一个线程,浪费资源,所以采用线程池
            service.submit(new Runnable() {
                @Override
                public void run() {
                    Socket socket= null;
                    try {
                        socket = serverSocket.accept();
                        System.out.println("服务器连接中....");
                        //输出服务器端响应,并反馈给客户端
                        handle(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
    private static void handle(Socket socket) throws IOException {
        InputStream in=socket.getInputStream();
        OutputStream out=socket.getOutputStream();
        byte[] bytes=new byte[1024];
        while(true){
            int len= in.read(bytes);
            if(len==-1){
                break;
            }
            String s=new String(bytes,0,len);
            System.out.print(s);
            out.write(("响应返回"+s).getBytes("UTF-8"));
        }
        in.close();
        out.close();
    }
}

(二)、并发量再高怎么办?非阻塞IO(清楚其原理,面试用)
非阻塞IO:(NIO :nonBlocking IO,也称之为:new IO)
线程(多路)复用:一个线程可以同时处理多个IO操作。
例子:幼儿园10个小朋友上厕所
阻塞IO:一个老师挨着问有没有小朋友上厕所,有就带着去,下一个想去上厕所的小朋友就要等着上一个回来再让老师带着去;非常慢;
非阻塞IO:两个老师 ,第一个老师负责轮流询问小朋友有没有想上厕所的,第二个老师领他们一起去厕所。
非阻塞IO的一些应用:(1)Web服务器 tomcat 雄猫(BIO ,NIO);(2)Netty服务器 封装了NIO技术,并发能力很高。(3)Spark分布式计算框架。Redis 缓存服务器。
(三)、lambda表达式;
Lambda表达式简化代码;其结构形式如下:
参数部分 特殊符号 代码体
(形参) -> {执行的代码}
注意:(1)针对单方法的接口,才能使用lambda表达式。
(2)代码体就一条语句时,{}括号可以略, 且末尾不能加分号;
(3)参数类型可以省略;因为可以由上下文推出参数类型;
(4)如果代码体部分只有一条语句,那么它还能充当返回值。
(5)用途:List集合排序;
Map集合遍历元素map.ForEach(); (1.8API新增特性)
default void forEach(BiConsumer<? super K,? super V> action)等效于键值对找值
其中BiConsumer是一个接口;
代码如下:

(1)public class TestLambda1 {
    public static void main(String[] args) {
        //List集合排序
        ArrayList<Integer> list=new ArrayList();
        list.add(10);
        list.add(2);
        list.add(8);
        list.add(1);
        //调用Collections工具类的sort方法
//        默认从小到大排
//        Collections.sort(list);
//        System.out.println(list);

        //从大到小排序,就要重写排序方法
        Collections.sort(list, new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(list);

        //用lambda表达式改写
        Collections.sort(list,(o1,o2)->{ return o2-o1; });
        System.out.println(list);
    }
}
(2)public class TestLambda2 {
    public static void main(String[] args) {
        //Map集合遍历元素
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"星期一");
        map.put(2,"星期二");
        map.put(3,"星期三");
        map.put(4,"星期四");
        //遍历元素方法1:键找值
        Set<Integer> key=map.keySet();
        for(Integer k:key){
            String v= map.get(k);
            System.out.println("key:"+k+",value:"+v);
        }
        //遍历元素方法2:根据键值对找值
        Set<Map.Entry<Integer,String>> key1=map.entrySet();
        for(Map.Entry<Integer,String> kv:key1){
            Integer k1=kv.getKey();
            String  v1=kv.getValue();
            System.out.println("key:"+k1+",value:"+v1);
        }
        //遍历元素方法3:map.oreach方法(1.8API新增特性)
       // default void forEach(BiConsumer<? super K,? super V> action)等效于键值对找值
        //其中BiConsumer是一个接口,以下是写成正常接口内部类和lambda表达式的形式;
        map.forEach(new BiConsumer<Integer,String>(){
            @Override
            public void accept(Integer integer, String s) {
                System.out.println("key:"+integer+",value:"+s);
            }
        });

        map.forEach( (key2,value2)->{System.out.println("key:"+key2+",value:"+value2);
        });
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值