美文网首页网络通信协议
黑马程序员-网络

黑马程序员-网络

作者: 狼孩 | 来源:发表于2015-05-24 19:00 被阅读158次

    -------android培训java培训期待与您交流!----------

    1. 概述

    网络编程的本质是两个设备之间的数据交换,在计算机网络中,设备主要指计算机。

    • 网络模型
      网络传输方式中所细致划分层次的一个传输模型。每个层次都有自己功能作用。
    OSI和TVPIP参考模型.png
     1. OSI参考模型
         * 主要有七层定义:两个设备间通讯先会进行封装信息包的动作然后传给要传输的设备,接受设备在进行拆包动作对信息解析和接受。
     2. TCP/IP参考模型
         * 是对OSI模型的一个简化,分为四层。网络编程主要对应的是传输层和网际层。
         * 传输层对应的协议:TCP和UDP。网际层为:IP协议。应用层为HTTP、FTP等等协议。
    
    • 网络通讯要素
      1. IP地址:网络设备标识。本机回环IP地址:127.0.0.1或者localhost,也是默认。用途:可以测试网卡等。
      2. 端口:网络设备上应用程序的标识,此标识称作端口(逻辑端口),范围是0-65535任选,其中0-1024为系统使用或者保留端口。
      3. 传输协议:定义通信规则,此规则称为协议。常见的协议有:国际通用协议为:TCP/IP,UDP。
    package com.sergio.Network;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    /**
     * IP对象使用示例
     * Created by Sergio on 2015-05-19.
     */
    public class IPDemo {
        public static void main(String[] args) {
            InetAddress i = null;
            InetAddress ia = null;
            try {
                i = InetAddress.getLocalHost();
                System.out.println(i.toString());
                System.out.println(i.getHostAddress());
                System.out.println(i.getHostName());
    
                //通过名称主机名来解析地址和名字。但是还是以ip地址为主
                ia = InetAddress.getByName("www.baidu.com");
                System.out.println(ia.getHostAddress());
                System.out.println(ia.getHostName());
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
    }
    
    2. UDP和TCP
    • UDP:
      1. 将数据及源和目的封装成数据包,不需要建立连接
      2. 每个数据报的大小限制在64k内,有个封包动作
      3. 因无连接,是不可靠协议
      4. 不需要建立连接,速度快
      5. 应用场景:聊天,视频,桌面共享等
    • TCP:
      1. 建立连接,形成传输数据的通道
      2. 在连接中进行大数据量传输
      3. 通过三次握手完成连接,是可靠协议
      4. 必须建立连接,效率会稍低
      5. 应用场景:下载等
    3. Socket
    • Socket是为网络服务提供的一种机制
    • 通信两端都有Socket
    • 网络通信就是Socket间的通信
    • 数据在两个Socket间通过IO传输
    4. UDP应用
    • 对应的对象:DatagramSocket与DatagramPacket
    • 发送数据的步骤:
      * 1. 建立udp socket服务
      * 2. 提供数据,并将数据封装到数据包中
      * 3. 通过socket服务的发送功能,将数据包发出去
      * 4。关闭资源
    package com.sergio.Network;
    
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    
    /**
     * UDP发送数据步骤:
     * 1. 建立udp socket服务
     * 2. 提供数据,并将数据封装到数据包中
     * 3. 通过socket服务的发送功能,将数据包发出去
     * 4。关闭资源
     * Created by Sergio on 2015-05-19.
     */
    public class UDPSendDataDemo {
        public static void main(String[] args) throws Exception {
            //socket服务建立
            DatagramSocket ds = new DatagramSocket();
            //提供数据
            byte[] data = "udp send".getBytes();
            //封装数据
            DatagramPacket dp =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.123"), 10000);
            //发送数据
            ds.send(dp);
            ds.close();
        }
    }
    
    • 接收数据的步骤:
      * 1. 定义UDP socket服务,通常会监听一个端口,用来接收该接受的应用程序
      * 2. 定义数据包,用来存储接收到是字节数据,因为数据包对象中有更多功能可以提取字节数据的不同信息,
      * 3. 通过socket服务的receive方法将接收到的数据存入一定以好数据包中,
      * 4. 通过数据包对象的特有功能,将这些不同的数据取出。
    package com.sergio.Network;
    
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.SocketException;
    
    /**
     * UDP接受数据步骤:
     * 1. 定义UDP socket服务,通常会监听一个端口,用来接收该接受的应用程序
     * 2. 定义数据包,用来存储接收到是字节数据,因为数据包对象中有更多功能可以提取字节数据的不同信息,
     * 3. 通过socket服务的receive方法将接收到的数据存入一定以好数据包中,
     * 4. 通过数据包对象的特有功能,将这些不同的数据取出。
     * Created by Sergio on 2015-05-19.
     */
    public class UDPReceiveDataDemo {
        public static void main(String[] args) throws Exception {
            //创建udp socket服务,指定端口来接受该有的应用程序信息
            DatagramSocket ds = new DatagramSocket(10000);
            while (true) {
                //定义数据包,用来存储接受到的数据包
                byte[] data = new byte[1024];
                DatagramPacket dp = new DatagramPacket(data, data.length);
                //通过服务的receive方法将受到数据存入数据包中
                ds.receive(dp);
                //通过数据包的方法提取数据信息
                String ip = dp.getAddress().getHostAddress();
                //获取应有长度的数据内容
                String data1 = new String(dp.getData(), 0, dp.getLength());
                int port = dp.getPort();
                System.out.println(data1 + ip + port);
            }
        }
    }
    
    • 练习聊天:
    package com.sergio.Network;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.*;
    
    /**
     * 聊天程序
     * Created by Sergio on 2015-05-19.
     */
    public class ChatDemo {
        public static void main(String[] args) throws Exception {
            //创建发送和接受对象
            DatagramSocket sendSocket = new DatagramSocket();
            DatagramSocket receiveSocket = new DatagramSocket(10002);
            //启动线程
            new Thread(new Send(sendSocket)).start();
            new Thread(new Receive(receiveSocket)).start();
        }
    }
    
    
    //发送数据端线程
    class Send implements Runnable {
        private DatagramSocket ds;
    
        public Send(DatagramSocket ds) {
            this.ds = ds;
        }
    
        @Override
        public void run() {
            try {
                //读取键盘录入并发送数据
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                String line = null;
                while ((line = br.readLine()) != null) {
                    if ("886".equals(line))
                        break;
    
                    byte[] buf = line.getBytes();
                    DatagramPacket dp =
                        new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.123"), 10002);
                    ds.send(dp);
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    
    //接受数据的线程
    class Receive implements Runnable {
        private DatagramSocket ds;
    
        public Receive(DatagramSocket ds) {
            this.ds = ds;
        }
    
        @Override
        public void run() {
            try {
                //循环解析数据
                while (true) {
                    byte[] buf = new byte[1024];
                    DatagramPacket dp = new DatagramPacket(buf, buf.length);
                    ds.receive(dp);
                    String ip = dp.getAddress().getHostAddress();
                    String data = new String(dp.getData(), 0, dp.getLength());
    
                    System.out.println(ip + "::" + data);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    5. TCP应用
    • 对应的对象为:Socket和ServerSocket
    • TCP分客户端和服务端。客户端对应的对象为Socket、服务端为:ServerSocket。
      步骤:
    • 一. 客户端:
    1. 创建Socket服务,并指定要连接的主机和端口。
    2. 获取Socket流的中的输出流,将数据写到该流中,通过网络发送给服务端。
    3. 关闭Scoket。
    • 二. 服务端:
    1. 建立服务端的Socket服务,ServerSocket();
    2. 获取连接过来的客户端对象,通过ServerSocket的accept方法连接,此方法是阻塞式的。
    3. 客户端如果发来数据,服务端需要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发来的数据。
    4. 关闭服务端(可选)。
    • 注意:服务端没有输入输出流,主要是利用客户端对象的输出输入流来读取数据信息。
    package com.sergio.Network;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    
    /**
     * 交互式客户端示例
     * Created by Sergio on 2015-05-20.
     */
    public class TCPClientDemo2 {
        public static void main(String[] args) throws IOException {
            //建立Socket服务,指定连接主机和端口号
            Socket s = new Socket("192.168.1.123", 10004);
            //获取Socket流中的输出流,并写入到该流中
            OutputStream out = s.getOutputStream();
            out.write("交互式信息发送".getBytes());
    
            //交互部分代码输入,读取数据
            InputStream in = s.getInputStream();
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            System.out.println(new String(buf, 0, len));
            s.close();
    
        }
    }
    
    package com.sergio.Network;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 交互式服务端示例
     * Created by Sergio on 2015-05-20.
     */
    public class TCPServerDemo2 {
        public static void main(String[] args) throws IOException {
            //创建ServerSocket服务,并监听10004端口
            ServerSocket ss = new ServerSocket(10004);
            //通过accept方法获取客户端对象
            Socket s = ss.accept();
            //打印客户端的ip地址
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip + "连接进来");
    
            //获取客户端的输入流,并读取数据
            InputStream is = s.getInputStream();
            byte[] buf = new byte[1024];
            int len = is.read(buf);
            System.out.println(new String(buf, 0, len));
    
            //与客户端交互部分,写入数据
            OutputStream out = s.getOutputStream();
            out.write("服务端受到信息".getBytes());
            s.close();
            ss.close();
        }
    }
    
    • 键盘录入数据服务端返回大写格式信息示例:
    package com.sergio.Network;
    
    import java.io.*;
    import java.net.Socket;
    
    /**
     * 将客户端发送给服务端的字符转成大写。注意读取键盘录入数据的结束标记换行和回车符。
     * Created by Sergio on 2015-05-20.
     */
    public class TransClientDemo {
        public static void main(String[] args) throws IOException {
            Socket s = new Socket("192.168.1.123", 10005);
            //定义读取键盘数据的流对象
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            //定义目的,将数据写入到socket输出流,发送给服务端
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            //对上一句替换语句//PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
            //定义一个socket读取流,读取服务端返回的大写信息
            BufferedReader brIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
    
            String line = null;
            while ((line = br.readLine()) != null) {
                if ("over".equals(line))
                    break;
                bw.write(line);
                //需要有个回车符结束标记
                bw.newLine();
                bw.flush();
                //对上面三句的替换//pw.print(line);
                //读取服务端返回的信息
                String str = brIn.readLine();
                System.out.println("server::" + str);
            }
            br.close();
            s.close();
        }
    }
    
    
    package com.sergio.Network;
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 将客户端发送给服务端的字符转成大写。注意读取键盘录入数据的结束标记换行和回车符。
     * Created by Sergio on 2015-05-20.
     */
    public class TransServerDemo {
        public static void main(String[] args) throws Exception {
            ServerSocket ss = new ServerSocket(10005);
            Socket s = ss.accept();
    
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip + "连接进来");
    
            //读取socket读取流中的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //目的socket输出流将大小数据写入到socket暑促胡柳,并发送给客户端
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            //PrintWriter pw = new PrintWriter(s.getOutputStream());
            String line = null;
            while ((line = br.readLine()) != null) {
                //pw.print(line.toUpperCase());
                bw.write(line.toUpperCase());
                bw.newLine();
                bw.flush();
            }
            s.close();
            ss.close();
        }
    }
    
    • 客户端登录服务器示例:
    package com.sergio.Network;
    
    import java.io.*;
    import java.net.Socket;
    
    /**
     * 上传图片示例,客户端
     * 步骤:1.服务端点,2.读取客户端已有的数据,3.通过Socket输出流将数据发给服务端,
     * 4.读取服务端发聩信息,5.关闭
     * Created by Sergio on 2015-05-22.
     */
    public class UploadPicClient {
        public static void main(String[] args) throws Exception {
            //用来判断上传图片的上传要求
            //为空
            if (args.length != 1) {
                System.out.println("请选择一个jpg格式的图片");
                return;
            }
            File file = new File(args[0]);
            if (file.exists() && file.isFile()) {
                System.out.println("该文件有问题");
                return;
            }
            if (!file.getName().endsWith(".jpg")) {
                System.out.println("图片格式错误");
            }
            if (file.length() > 1024 * 1024 * 5) {
                System.out.println("文件过大");
                return;
            }
    
            Socket s = new Socket("192.168.1.123", 10008);
            FileInputStream fis = new FileInputStream(file);
            OutputStream out = s.getOutputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            //告诉服务端数据已经传完
            s.shutdownOutput();
            
            //读取反馈的信息
            InputStream in = s.getInputStream();
            byte[] bufIn = new byte[1024];
            int num = in.read(bufIn);
            System.out.println(new String(bufIn, 0, num));
            fis.close();
            s.close();
        }
    }
    
    package com.sergio.Network;
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 上传图片示例,并发处理服务端
     * Created by Sergio on 2015-05-22.
     */
    public class UploadPicServer {
        public static void main(String[] args) throws Exception {
            ServerSocket ss = new ServerSocket(10008);
            while (true) {
                //获取客户端连接并监听地址和端口
                Socket s = ss.accept();
                //启动服务端并发处理的线程
                new Thread(new PicThread(s)).start();
            }
        }
    }
    
    
    //服务端上传图片线程
    class PicThread implements Runnable {
        private Socket s;
    
        PicThread(Socket s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            //用来重复上传图片计数
            int count = 1;
            String ip = s.getInetAddress().getHostAddress();
            try {
                System.out.println(ip + "连接进来了");
                InputStream in = s.getInputStream();
                //处理重复上传判断和处理
                File file = new File(ip + "(" + (count) + ")" + ".jpg");
                while (file.exists()) {
                    file = new File(ip + "(" + (count++) + ")" + ".jpg");
                }
                //读取图片
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buf = new byte[1024];
                int len = 0;
                while ((len = in.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
    
                //服务端回应客户端
                OutputStream out = s.getOutputStream();
                out.write("上传成功".getBytes());
                fos.close();
                s.close();
            } catch (Exception e) {
                throw new RuntimeException(ip + "上传失败");
            }
        }
    }
    
    URL和URLConnection
    • URL是对底层传输层功能封装的对象。
    • URLConnection相当于应用层对URL的功能封装,更简便。

    1.URL

    package com.sergio.Network;
    
    import java.net.MalformedURLException;
    import java.net.URL;
    
    /**
     * URL对象示例,对网址进行解析
     * Created by Sergio on 2015-05-24.
     */
    public class URLDemo {
        public static void main(String[] args) throws MalformedURLException {
            URL url = new URL("https://www.amazon.cn/clouddrive?sf=1&ref_=nav_Photos_Files");
            System.out.println("协议" + url.getProtocol());
            System.out.println("主机" + url.getHost());
            System.out.println("端口" + url.getPort());
            System.out.println("路径" + url.getPath());
            System.out.println("文件" + url.getFile());
            System.out.println("查询" + url.getQuery());
        }
    }
    

    2.URLConnection

    package com.sergio.Network;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    
    /**
     * URLConnection对象使用,对连接解析并获取网页内容。
     * Created by Sergio on 2015-05-24.
     */
    public class URLConnectionDemo {
        public static void main(String[] args) throws IOException {
            URL url = new URL("https://www.amazon.cn.");
            //应用层URLConnection对象封装,打开socket流
            URLConnection conn = url.openConnection();
            System.out.println(conn);
    
            InputStream in = conn.getInputStream();
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            //打印获取到的数据信息
            System.out.println(new String(buf, 0, len));
        }
    }
    

    相关文章

      网友评论

        本文标题:黑马程序员-网络

        本文链接:https://www.haomeiwen.com/subject/mrekqttx.html