• Java 网络编程


    网络编程

    网络模型
     OSI参考模型
      //应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
     TCP/IP参考模型
      //应用层 传输层 网际层 网络接口层
    网络通讯要素
     IP地址
      //网络中设备的标识 本地回环地址 127.0.0.1 主机名 localhost
     端口号
      //标识进程的逻辑地址 有效端口 0~65535 其中0~1024系统使用或保留端口
     传输协议
      //通讯的规则 TCP UDP
    UDP
     将数据及源和目的 封装成数据包中 不需要建立连接
     每个数据包的大小限制在64K内
     因无连接 是不可靠协议
     不需要建立连接 速度快
    TCP
     建立连接 形成传输数据的通道
     在连接中进行大数据量传输
     通过三次握手完成连接 是可靠协议
     必须建立连接 效率会稍低

    InetAddress //IP地址
     getLocalHost //获取本地地址IP对象
     getHostAddress //IP地址字符串
     getHostName //IP主机名

    public class IPDemo {
    
        public static void main(String[] args) throws UnknownHostException {
    
            //获取本地主机ip地址对象。 
            InetAddress ip = InetAddress.getLocalHost();
            
            //获取其他主机的ip地址对象。
            ip = InetAddress.getByName("192.168.1.110");//InetAddress.getByName("my_think");
            
            System.out.println(ip.getHostAddress());
            System.out.println(ip.getHostName());
        }
    
    }

    Socket  

      Socket就是为网络服务提供的一种机制  

      通信的两端都有Socket  

      网络通信其实就是Socket间的通信  

      数据在两个Socket间通过IO传输

    UDP传输  

      DatagramSocket与DatagramPacket  

      建立发送端 接收端  建立数据包  调用Socket的发送接收方法  

      关闭Socket  

      发送端与接收端是两个独立的运行程序

    public class UDPSendDemo {
    
        public static void main(String[] args) throws IOException {
    
            System.out.println("发送端启动......");
            /*
             * 创建UDP传输的发送端。
             * 思路:
             * 1,建立udp的socket服务。
             * 2,将要发送的数据封装到数据包中。 
             * 3,通过udp的socket服务将数据包发送出去。
             * 4,关闭socket服务。
             */
            //1,udpsocket服务。使用DatagramSocket对象。
            DatagramSocket ds = new DatagramSocket(8888);
            
            //2,将要发送的数据封装到数据包中。
            String str = "udp传输演示:哥们来了!";
                //使用DatagramPacket将数据封装到的该对象包中。
            byte[] buf = str.getBytes();
            
            DatagramPacket dp = 
                    new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
            
            
            //3,通过udp的socket服务将数据包发送出去。使用send方法。
            ds.send(dp);
            
            //4,关闭资源。
            ds.close();
            
            
        }
    
    }
    public class UDPReceDemo {
    
        public static void main(String[] args) throws IOException {
    
            System.out.println("接收端启动......");
            /*
             * 建立UDP接收端的思路。
             * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
             * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
             * 3,使用socket服务的receive方法将接收的数据存储到数据包中。
             * 4,通过数据包的方法解析数据包中的数据。
             * 5,关闭资源 
             */
            
            //1,建立udp socket服务。
            DatagramSocket ds = new DatagramSocket(10000);
            
            
            //2,创建数据包。
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf,buf.length);
            
            //3,使用接收方法将数据存储到数据包中。
            ds.receive(dp);//阻塞式的。
            
            //4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
            String ip = dp.getAddress().getHostAddress();
            int port = dp.getPort();
            String text = new String(dp.getData(),0,dp.getLength());
            
            System.out.println(ip+":"+port+":"+text);
            
            //5,关闭资源。
            ds.close();
            
            
        }
        
    
    }

    升级版

    public class UDPSendDemo2 {
    
        public static void main(String[] args) throws IOException {
    
            System.out.println("发送端启动......");
            /*
             * 创建UDP传输的发送端。
             * 思路:
             * 1,建立udp的socket服务。
             * 2,将要发送的数据封装到数据包中。 
             * 3,通过udp的socket服务将数据包发送出去。
             * 4,关闭socket服务。
             */
            //1,udpsocket服务。使用DatagramSocket对象。
            DatagramSocket ds = new DatagramSocket(8888);
            
            
    //        String str = "udp传输演示:哥们来了!";
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            
            while((line=bufr.readLine())!=null){
                
                
                byte[] buf = line.getBytes();
                DatagramPacket dp = 
                        new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),10000);
                ds.send(dp);
                
                if("886".equals(line))
                    break;
            }
            
            //4,关闭资源。
            ds.close();
            
            
        }
    
    }
    public class UDPReceDemo2 {
    
        public static void main(String[] args) throws IOException {
    
            System.out.println("接收端启动......");
            /*
             * 建立UDP接收端的思路。
             * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
             * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
             * 3,使用socket服务的receive方法将接收的数据存储到数据包中。
             * 4,通过数据包的方法解析数据包中的数据。
             * 5,关闭资源 
             */
            
            //1,建立udp socket服务。
            DatagramSocket ds = new DatagramSocket(10000);
            
            while(true){
            
            //2,创建数据包。
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf,buf.length);
            
            //3,使用接收方法将数据存储到数据包中。
            ds.receive(dp);//阻塞式的。
            
            //4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
            String ip = dp.getAddress().getHostAddress();
            int port = dp.getPort();
            String text = new String(dp.getData(),0,dp.getLength());
            
            System.out.println(ip+":"+port+":"+text);
            
            
            }
            //5,关闭资源。
    //        ds.close();
            
            
        }
        
    }

    聊天室

    public class ChatDemo {
    
        public static void main(String[] args) throws IOException {
    
            
            DatagramSocket send = new DatagramSocket();
            
            DatagramSocket rece = new DatagramSocket(10001);
            new Thread(new Send(send)).start();
            new Thread(new Rece(rece)).start();
            
        }
    
    }
    public class Send implements Runnable {
    
        private DatagramSocket ds;
        
        public Send(DatagramSocket ds){
            this.ds = ds;
        }
        
        @Override
        public void run() {
            
            try {
                BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
                String line = null;
                
                while((line=bufr.readLine())!=null){
                    
                    
                    byte[] buf = line.getBytes();
                    DatagramPacket dp = 
                            new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001);
                    ds.send(dp);
                    
                    if("886".equals(line))
                        break;
                }
                
                ds.close();
            } catch (Exception e) {
            }
        }
    
    }
    public class Rece implements Runnable {
    
        private DatagramSocket ds;
    
        public Rece(DatagramSocket ds) {
            this.ds = ds;
        }
    
        @Override
        public void run() {
            try {
                while (true) {
    
                    // 2,创建数据包。
                    byte[] buf = new byte[1024];
                    DatagramPacket dp = new DatagramPacket(buf, buf.length);
    
                    // 3,使用接收方法将数据存储到数据包中。
                    ds.receive(dp);// 阻塞式的。
    
                    // 4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
                    String ip = dp.getAddress().getHostAddress();
                    int port = dp.getPort();
                    String text = new String(dp.getData(), 0, dp.getLength());
                    
                    System.out.println(ip + "::" + text);
                    if(text.equals("886")){
                        System.out.println(ip+"....退出聊天室");
                    }
    
                }
            } catch (Exception e) {
    
            }
    
        }
    
    }

    TCP传输
       Socket和ServerSocket
       建立客户端和服务器端
       建立连接后 通过Socket中的IO流进行数据传输

    public class ServerDemo {
    
        public static void main(String[] args) throws IOException {
    //        服务端接收客户端发送过来的数据,并打印在控制台上。 
            /*
             * 建立tcp服务端的思路:
             * 1,创建服务端socket服务。通过ServerSocket对象。
             * 2,服务端必须对外提供一个端口,否则客户端无法连接。
             * 3,获取连接过来的客户端对象。
             * 4,通过客户端对象获取socket流读取客户端发来的数据 
             *         并打印在控制台上。
             * 5,关闭资源。关客户端,关服务端。 
             */
            
            //1创建服务端对象。
            ServerSocket ss = new ServerSocket(10002);
            
            //2,获取连接过来的客户端对象。
            Socket s = ss.accept();//阻塞式.
            
            String ip = s.getInetAddress().getHostAddress();
            
            //3,通过socket对象获取输入流,要读取客户端发来的数据
            InputStream in = s.getInputStream();
            
            byte[] buf = new byte[1024];
            
            int len = in.read(buf);
            String text = new String(buf,0,len);
            System.out.println(ip+":"+text);
    
                    
            s.close();
            ss.close();
            
        }
    
    }
    public class ClientDemo {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            //客户端发数据到服务端
            /*
             * Tcp传输,客户端建立的过程。
             * 1,创建tcp客户端socket服务。使用的是Socket对象。
             *         建议该对象一创建就明确目的地。要连接的主机。 
             * 2,如果连接建立成功,说明数据传输通道已建立。
             *         该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
             *         想要输入或者输出流对象,可以找Socket来获取。 
             *         可以通过getOutputStream(),和getInputStream()来获取两个字节流。
             * 3,使用输出流,将数据写出。 
             * 4,关闭资源。 
             */
            
            
            //创建客户端socket服务。
            Socket socket = new Socket("192.168.1.100",10002);
            
            //获取socket流中的输出流。 
            OutputStream out = socket.getOutputStream();
            
            
            //使用输出流将指定的数据写出去。
            out.write("tcp演示:哥们又来了!".getBytes());
            
            //关闭资源。
            socket.close();
                    
        }
    
    }

    升级版

    public class ServerDemo2 {
    
        public static void main(String[] args) throws IOException {
    //        服务端接收客户端发送过来的数据,并打印在控制台上。 
            /*
             * 建立tcp服务端的思路:
             * 1,创建服务端socket服务。通过ServerSocket对象。
             * 2,服务端必须对外提供一个端口,否则客户端无法连接。
             * 3,获取连接过来的客户端对象。
             * 4,通过客户端对象获取socket流读取客户端发来的数据 
             *         并打印在控制台上。
             * 5,关闭资源。关客户端,关服务端。 
             */
            
            //1创建服务端对象。
            ServerSocket ss = new ServerSocket(10002);
            
            //2,获取连接过来的客户端对象。
            Socket s = ss.accept();
            
            String ip = s.getInetAddress().getHostAddress();
            
            //3,通过socket对象获取输入流,要读取客户端发来的数据
            InputStream in = s.getInputStream();
            
            byte[] buf = new byte[1024];
            
            int len = in.read(buf);
            String text = new String(buf,0,len);
            System.out.println(ip+":"+text);
                    
            //使用客户端socket对象的输出流给客户端返回数据
            OutputStream out = s.getOutputStream();
            out.write("收到".getBytes());
            
            s.close();
            ss.close();
            
        }
    
    }
    public class ClientDemo2 {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            //客户端发数据到服务端
            /*
             * Tcp传输,客户端建立的过程。
             * 1,创建tcp客户端socket服务。使用的是Socket对象。
             *         建议该对象一创建就明确目的地。要连接的主机。 
             * 2,如果连接建立成功,说明数据传输通道已建立。
             *         该通道就是socket流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。
             *         想要输入或者输出流对象,可以找Socket来获取。 
             *         可以通过getOutputStream(),和getInputStream()来获取两个字节流。
             * 3,使用输出流,将数据写出。 
             * 4,关闭资源。 
             */
            
            
            
            Socket socket = new Socket("192.168.1.100",10002);
            
            OutputStream out = socket.getOutputStream();    
            
            out.write("tcp演示:哥们又来了!".getBytes());
            
            //读取服务端返回的数据,使用socket读取流。 
            InputStream in = socket.getInputStream();
            byte[] buf = new byte[1024];
            
            int len = in.read(buf);
            
            String  text = new String(buf,0,len);
            
            System.out.println(text);
            
            //关闭资源。
            socket.close();
            
        }
    
    }

    两个练习Demo
    1 将客户端发送的小写字母转换为大写字母 输入over结束
    2 上传文本到服务端

    TCP上传图片 多线程

    public class UploadPicServer {
    
        public static void main(String[] args) throws IOException {
                
            //创建tcp的socket服务端。
            ServerSocket ss = new ServerSocket(10006);
            
            while(true){
                Socket s = ss.accept();            
                
                new Thread(new UploadTask(s)).start();        
                
            }
            //获取客户端。
            
            
    //        ss.close();
            
            
        }
    
    }
    public class UploadTask implements Runnable {
    
        private static final int SIZE = 1024*1024*2;
        private Socket s;
    
        public  UploadTask(Socket s) {
            this.s = s;
        }
    
        @Override
        public void run() {
    
            int count = 0;
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip + ".....connected");
            
            try{
    
            // 读取客户端发来的数据。
            InputStream in = s.getInputStream();
    
            // 将读取到数据存储到一个文件中。
            File dir = new File("c:\pic");
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dir, ip + ".jpg");
            //如果文件已经存在于服务端 
            while(file.exists()){
                file = new File(dir,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);
                
                if(file.length()>SIZE){
                    System.out.println(ip+"文件体积过大");
                    
                    fos.close();
                    s.close();
                    
                    
                    System.out.println(ip+"...."+file.delete());
                    
                    return ;
                }
            }
    
            // 获取socket输出流,将上传成功字样发给客户端。
            OutputStream out = s.getOutputStream();
            out.write("上传成功".getBytes());
    
            fos.close();
            s.close();
            }catch(IOException e){
                
            }
    
        }
    
    }
    public class UploadPicClient {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
    
            
            //1,创建客户端socket。
            Socket s = new Socket("192.168.1.100",10006);
            
            //2,读取客户端要上传的图片文件。
            FileInputStream fis = new FileInputStream("c:\0.bmp");
            
            //3,获取socket输出流,将读到图片数据发送给服务端。
            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 lenIn = in.read(buf);
            String text = new String(buf,0,lenIn);
            System.out.println(text);
            
            fis.close();
            s.close();    
            
        }
    
    }

    客户端服务端模型 最常见的客户端:  浏览器 :IE。 最常见的服务端:  服务器:Tomcat。

    为了了解其原理:

    自定义服务端, 使用已有的客户端IE,了解一下客户端给服务端发了什么请求?

    发送的请求是:

    GET / HTTP/1.1  请求行  请求方式  /myweb/1.html  请求的资源路径   http协议版本。
    请求消息头 . 属性名:属性值
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, 
    application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
    Accept: */*     
    Accept-Language: zh-cn,zu;q=0.5
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
    Host: 192.168.1.100:9090
    //Host: www.huyouni.com:9090
    Connection: Keep-Alive
    //空行
    //请求体

    服务端发回应答消息

    HTTP/1.1 200 OK   //应答行,http的协议版本   应答状态码   应答状态描述信息
    
    应答消息属性信息。 属性名:属性值
    Server: Apache-Coyote/1.1
    ETag: W/"199-1323480176984"
    Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
    Content-Type: text/html
    Content-Length: 199
    Date: Fri, 11 May 2012 07:51:39 GMT
    Connection: close
    //空行
    //应答体。
    <html>
        <head>
            <title>这是我的网页</title>
        </head>
    
        <body>
    
            <h1>欢迎光临</h1>
    
            <font size='5' color="red">这是一个tomcat服务器中的资源。是一个html网页。</font>
        </body>
    
    
    </html>

    Demo

    public class MyTomcat {
    
        public static void main(String[] args) throws IOException {
    
            ServerSocket ss = new ServerSocket(9090);
            
            Socket s = ss.accept();
            System.out.println(s.getInetAddress().getHostAddress()+".....connected");
            
            InputStream in = s.getInputStream();
            
            byte[] buf = new byte[1024];
            
            int len = in.read(buf);
            String text = new String(buf,0,len);
            System.out.println(text);
            
            
            //给客户端一个反馈信息。
            PrintWriter out = new PrintWriter(s.getOutputStream(),true);
            
            out.println("<font color='red' size='7'>欢迎光临</font>");
            
            s.close();
            ss.close();
        }
    
    }
    public class MyBrowser {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
    
            Socket s = new Socket("192.168.1.100",8080);
            
            //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
            PrintWriter out = new PrintWriter(s.getOutputStream(),true);
            out.println("GET /myweb/1.html HTTP/1.1");
            out.println("Accept: */*");
            out.println("Host: 192.168.1.100:8080");
            out.println("Connection: close");
            out.println();
            out.println();
            
            
            InputStream in = s.getInputStream();
            
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            
            String str =new String(buf,0,len);
            System.out.println(str);
            
            s.close();
            
            //http://192.168.1.100:8080/myweb/1.html
        }
    
    }
    public class URLDemo {
    
        public static void main(String[] args) throws IOException {
    
            String str_url = "http://192.168.1.100:8080/myweb/1.html";
            
            URL url = new URL(str_url);
            
    //        System.out.println("getProtocol:"+url.getProtocol());
    //        System.out.println("getHost:"+url.getHost());
    //        System.out.println("getPort:"+url.getPort());
    //        System.out.println("getFile:"+url.getFile());
    //        System.out.println("getPath:"+url.getPath());
    //        System.out.println("getQuery:"+url.getQuery());
            
    //        InputStream in = url.openStream();
            
            //获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
            URLConnection conn = url.openConnection();
            
    //        String value = conn.getHeaderField("Content-Type");
    //        System.out.println(value);
            
    //        System.out.println(conn);
            //sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html
            
            InputStream in = conn.getInputStream();
            
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            
            String text = new String(buf,0,len);
            
            System.out.println(text);
            
            in.close();
    
        }
    
    }

    网络结构

    1,C/S  client/server    

      特点:   该结构的软件,客户端和服务端都需要编写。   可发成本较高,维护较为麻烦。     好处:   客户端在本地可以分担一部分运算。

    2,B/S  browser/server  

      特点:   该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。   开发成本相对低,维护更为简单。  缺点:所有运算都要在服务端完成。

    一个简单浏览器的实现

    public class MyBrowseGUI extends javax.swing.JFrame {
        private JTextField url_text;
        private JButton goto_but;
        private JScrollPane jScrollPane1;
        private JTextArea page_content;
    
        /**
        * Auto-generated main method to display this JFrame
        */
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    MyBrowseGUI inst = new MyBrowseGUI();
                    inst.setLocationRelativeTo(null);
                    inst.setVisible(true);
                }
            });
        }
        
        public MyBrowseGUI() {
            super();
            initGUI();
        }
        
        private void initGUI() {
            try {
                setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                getContentPane().setLayout(null);
                {
                    url_text = new JTextField();
                    getContentPane().add(url_text);
                    url_text.setBounds(12, 36, 531, 44);
                    url_text.addKeyListener(new KeyAdapter() {
                        public void keyPressed(KeyEvent evt) {
                            url_textKeyPressed(evt);
                        }
                    });
                }
                {
                    goto_but = new JButton();
                    getContentPane().add(goto_but);
                    goto_but.setText("u8f6c u5230");
                    goto_but.setBounds(555, 36, 134, 44);
                    goto_but.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent evt) {
                            goto_butActionPerformed(evt);
                        }
                    });
                }
                {
                    jScrollPane1 = new JScrollPane();
                    getContentPane().add(jScrollPane1);
                    jScrollPane1.setBounds(12, 92, 676, 414);
                    {
                        page_content = new JTextArea();
                        jScrollPane1.setViewportView(page_content);
                    }
                }
                pack();
                this.setSize(708, 545);
            } catch (Exception e) {
                //add your error handling code here
                e.printStackTrace();
            }
        }
        
        private void goto_butActionPerformed(ActionEvent evt) {
            showPage();
        }
        
        private void url_textKeyPressed(KeyEvent evt) {
            if(evt.getKeyCode()==KeyEvent.VK_ENTER)
                showPage();
            
        }
    
        private void showPage() {
            try {
                
                String url_str = url_text.getText();
                URL url = new URL(url_str);
                
                InputStream in = url.openConnection().getInputStream();//url.openStream();
                
                page_content.setText("");
                
                byte[] buf = new byte[1024];
                int len = in.read(buf);
                String text = new String(buf,0,len,"utf-8");
                
                page_content.setText(text);
                
                in.close();
                
                
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    
    }
  • 相关阅读:
    1203 有穷自动机
    [转]HTTP协议详解
    JavaScript中的正则表达式
    [译]JavaScript insertAdjacentHTML
    [译]Autoprefixer:用最可行的方式处理浏览器前缀的CSS后处理器
    [译]JavaScript 错误和处理
    [译]CSS content
    [译]当你在浏览器输入url后发生了什么
    display的小故事
    移动web屏幕适配方案
  • 原文地址:https://www.cnblogs.com/huanyi0723/p/5003372.html
Copyright © 2020-2023  润新知