7.网络编程

1.网络模型:
OSI(Open System Interconnection)(开放系统)参考模型
TCP/IP参考模型

网络参考模型

描述

封包拆包:
这里写图片描述

2.网络通讯要素L:
IP地址
端口号
传输协议

3.IP地址:
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1,用来访问本机测试网卡。
主机默认名:localhost

4.端口:
用于有效标识进程的逻辑地址,不同进程的标识不同。
有效端口:0~65535,其中0~1024系统使用或保留端口。

这里写图片描述

5.传输协议:
通讯的规则
常见协议:
TCP(传输控制协议):打电话,下载文件,QQ文件在线发送
UDP(数据报文协议):对讲机,QQ文件离线发送

这里写图片描述

6.IP对象:InetAddress

public class IPDemo {

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

        //获取本地主机ip的地址对象
        InetAddress ip = InetAddress.getLocalHost();


        //获取其他主机的ip地址对象
//      ip = InetAddress.getByName("coy");
//      ip = InetAddress.getByName("100.64.172.141");
        ip = InetAddress.getByName("www.baidu.com");


        //获取本地主机的ip地址和主机名
        System.out.println(ip.getHostAddress());
        System.out.println(ip.getHostName());
    }


/*
180.97.33.107
www.baidu.com
*/

7.域名解析:
DNS:域名解析器(互联网公共主机服务器)

这里写图片描述

配置本地域名解析列表:
C:\Windows\System32\drivers\etc

系统域名解析 先找的是 本地域名解析文件。
(可以把一些游戏广告网站域名在本地解析成本机回环地址127.0.0.1,不进行访问,过滤垃圾网站)

8.Socket :

1.Socket就通讯的两端,为网络服务提供的一种机制(两个港口)
2.通信的两端都有Socket
3.网络编程就是Socket编程
4.网络通信其实就是Socket间的通信
5.数据在两个Socket间通过IO传输

9.UDP协议

1.DatagramSocket,DatagramPacket
2.建立发送端,接收端
3.建立数据包
4.调用Socket的发生接收方法
5.关闭Socket
发送端和接收端是两个独立的运行程序。

发送端:

public class UDPSendDemo {

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

        /*
                创建UDP传输的发送端。
                思路:
                1.建立UDP的socket服务
                2.将要发送的数据封装到数据包中。
                3.通过UDP的socket服务将数据包发送出去。
                4.关闭socket服务。
         */
        System.out.println("发送端启动...");
        //1.UDPsocket服务。使用DatagramSocket对象
        DatagramSocket ds = new DatagramSocket();

        //2.将要发送的数据封装到数据包中。
        String str = "udp传输演示:哈哈";
        byte[] buf = str.getBytes();
        DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("coy"),10000);

        //3.通过UDP的socket服务将数据包发送出去。使用send方法。
        ds.send(dp);

        //4.关闭资源。
        ds.close();
    }

}

接收端:

public class UDPReceDemo {

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

        /*
                建立UDP接收端的思路
                1.建立UDP的socket服务
                2.创建数据包。用于存储接收到的数据。方便用数据包对象的方法解析这些数据。
                3.使用Socket服务的receive方法将接收的数据存储到数据包中。
                4.通过数据包的方法解析数据包中的数据。
                5.关闭资源。
         */
        System.out.println("接收端启动...");

        //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();


    }

}

10.TCP传输:

1.Socket,ServerSocket
2.建立客户端和服务端
3.建立连接后,通过Socket中的IO流进行数据的传输。
4.关闭socket

同样,客户端和服务端是两个独立的应用程序。

这里写图片描述

客户端:

public class TCPClientDemo {

    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("coy",10002);

        //获取socket流中的输出流
        OutputStream out = socket.getOutputStream();

        //使用输出流将指定的数据写出去
        out.write("哈哈".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();

    }

}

服务端:

public class TCPServerDemo {

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

        //服务端接收客户端发送过来的数据,并打印在控制台上。
        /*
                    建立TCP服务端的思路:
                1.创建服务端的socket服务。通过ServerSocket对象。
                    服务端必须对外提供一个端口,否者客户端无法连接。
                2.获取连接过来的客户端对象
                3.通过客户端对象获取socket流读取客户端发来的数据
                并打印在控制台上。
                4.关闭资源。关客户端,服务端。


         */

        //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 TransClient {

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

        /*
                思路:
                客户端:
                1.现有socket端点
                2.客户端的数据源:键盘
                3.客户端的目的:socket
                4.接收服务端的数据,源:socket
                5.将数据打印出来:目的:控制台
                6.在这些流中操作的数据都是文本数据。

                转换客户端:
                1.创建socket客户端对象
                2.获取键盘录入
                3.将录入的信息发送给socket输出流
                4.socket输入流读取服务端返回的大写数据
                5.将接收到的服务端数据打印到控制台
         */

        //1.创建socket客户端对象
        Socket s = new Socket("100.64.190.224",10001);

        //2.获取键盘录入
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

        //3.socket输出流
//      BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);  //自动刷新

        //4.socket输入流:读取服务端返回的大写数据
        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;

        while((line = bufr.readLine())!=null){
            if("over".equals(line))
                break;

            out.println(line);

            //4.读取服务端返回的一行大写数据
            String upperStr = bufIn.readLine();      
            System.out.println(upperStr);       
        }


         s.close();

    }

}



public class TransServer {

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

        /*
                转换服务端:

                分析:
                1.serversocket服务
                2.获取socket对象
                3.读取客户端发过来的需要转换的数据,源:socket
                4.目的:显示在控制台上
                5.将数据转成大写发给客户端。目的:socket

         */

        //1.
        ServerSocket ss = new ServerSocket(10001);      
        //2.
        Socket s = ss.accept();  //阻塞
        //3.获取socket读取流,并装饰
        BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));

        //获取ip:
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip+".......connected");

        //4.获取socket输出流,并装饰。将大写数据返回给客户端
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);  //自动刷新

        String line = null;
        while((line = bufr.readLine())!= null)
        {
            System.out.println("收到信息:" + line); 


            //将大写数据返回给客户端
            out.println(line.toUpperCase());
        }

        s.close();
        ss.close();



    }

}

示例:上传文本文件。

//客户端
public class TransClient {

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


        //1.创建socket客户端对象
        Socket s = new Socket("100.64.190.224",10001);
        System.out.println("成功连接服务器: 100.64.190.224    端口号:10001");
        //2.获取文件读取流。并装饰
        File file = new File("上传文件.txt");
        if(!file.exists()){
            System.out.println("文件不存在,无法上传!");
            s.close();
            System.exit(0);
        }
        BufferedReader bufr = new BufferedReader(new FileReader(file));
        System.out.println("正在上传文本文件"+file.getName());
        //3.socket输出流
//      BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);  //自动刷新

        //4.socket输入流:读取服务端返回的上传标志
        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;

        while((line = bufr.readLine())!=null){          

            out.println(line);

        }
        //告诉服务端:客户端写完了
            s.shutdownOutput();
        //4.读取服务端返回的上传成功标志
        System.out.println(bufIn.readLine());       

        bufr.close();
         s.close();

    }

}




//服务端
public class TransServer {

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



        //1.
        ServerSocket ss = new ServerSocket(10001);      
        //2.
        Socket s = ss.accept();  //阻塞
        //3.获取socket读取流,并装饰
        BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //获取ip:
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".......connected");


        //获取文件输入流,并装饰
        File file = new File("服务端接收文件.txt");
        BufferedWriter bufw = new BufferedWriter(new FileWriter(file));
            System.out.println("正在接收 "+ip+"发来的文本文件...");

        //4.获取socket输出流,并装饰。将上传标志返回给客户端
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);  //自动刷新

        String line = null;
        while((line = bufr.readLine())!= null)
        {           
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }
        //将上传标志返回给客户端
        System.out.println("接收成功!保存至"+file.getAbsolutePath());
        out.println("上传成功!");

        bufw.close();
        s.close();
        ss.close();



    }

}

示例:上传图片

public class TransClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
//客户端

        //1.创建socket客户端对象
        Socket s = new Socket("100.64.190.224",10001);
        System.out.println("成功连接服务器: 100.64.190.224    端口号:10001");

        //2.读取客户端要上传的图片。
        File file = new File("动画短片《某人的目光》新海诚.flv");     
        FileInputStream fis =  new FileInputStream(file);
        System.out.println("正在上传图片"+file.getName());

        //3.获取socket输出流,将读到的图片数据发送给服务端      
        OutputStream out = s.getOutputStream();  

        int len = 0;
        byte[] buf = new byte[1024];
        while((len = fis.read(buf))!=-1){                       
            out.write(buf,0,len);           
        }
        //告诉服务端:这边的数据发送完毕。让服务端停止读取
            s.shutdownOutput();

    //4.socket输入流:读取服务端返回的上传标志
        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));           
        System.out.println(bufIn.readLine());       

        fis.close();
         s.close();

    }

}


public class TransServer {

    public static void main(String[] args) throws IOException {
//服务端
        //1.创建tcp的socket服务端
        ServerSocket ss = new ServerSocket(10001);      

        //2.获取客户端
        Socket s = ss.accept();  //阻塞

        //3.读取客户端发来的数据
        InputStream ins = s.getInputStream();

            //获取ip:
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".......connected");

        System.out.println("正在接收 "+ip+"发来的文本文件...");

        //4.将读取到的数据存储到一个文件中
        File file = new File("服务端接收动画短片《某人的目光》新海诚.flv");
        FileOutputStream fos =new FileOutputStream(file);

        int len = 0;
        byte[] buf =new byte[1024];

        while((len = ins.read(buf))!= -1)
        {           
            fos.write(buf, 0, len);         
        }

        System.out.println("接收成功!保存至"+file.getAbsolutePath());

        //5.获取socket输出流。将上传标志返回给客户端
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
        out.println("上传成功!");

        fos.close();
        s.close();
        ss.close();



    }

}

11.服务端多线程:

public class TransClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
//客户端




            //1.创建socket客户端对象
            Socket s = new Socket("100.64.190.224",10001);
            System.out.println("成功连接服务器: 100.64.190.224    端口号:10001");
        //2.读取客户端要上传的图片。
        File file = new File("秒速五厘米(Av4433361,P1).flv");        
        FileInputStream fis =  new FileInputStream(file);
        System.out.println("正在上传:"+file.getName());

        //3.获取socket输出流,将读到的图片数据发送给服务端      
        OutputStream out = s.getOutputStream();  

        int len = 0;
        byte[] buf = new byte[1024];
        while((len = fis.read(buf))!=-1){                       
            out.write(buf,0,len);           
        }
        //告诉服务端:这边的数据发送完毕。让服务端停止读取
            s.shutdownOutput();

    //4.socket输入流:读取服务端返回的上传标志
        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));           
        System.out.println(bufIn.readLine());       

        fis.close();
        s.close();



    }

}




public class TransServer {

    public static void main(String[] args) throws IOException {
//服务端多线程
        //1.创建tcp的socket服务端
        ServerSocket ss = new ServerSocket(10001);      


        while(true){

        //2.获取客户端
        Socket s = ss.accept();  //阻塞   

        new Thread(new Task(s)).start();

            }

    }

}



public class Task implements Runnable {
    private Socket s;
    public Task(Socket s){
        this.s = s;
    }
    @Override
    public void run() {
        int count = 0;


        try{        

        //3.读取客户端发来的数据
                InputStream ins = s.getInputStream();

                    //获取ip:
                String ip = s.getInetAddress().getHostAddress();
                System.out.println(ip+".......connected");

                //4.将读取到的数据存储到一个文件中
                File file = new File(ip+".jpg");
                while(file.exists()){
                    file = new File(ip+"("+(++count)+")"+".jpg");
                }

                FileOutputStream fos =new FileOutputStream(file);

                int len = 0;
                byte[] buf =new byte[1024];

                while((len = ins.read(buf))!= -1)
                {           
                    fos.write(buf, 0, len);         
                }

                System.out.println(file.getName()+"接收成功!");

                //5.获取socket输出流。将上传标志返回给客户端
                PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
                out.println(file.getName()+"上传成功!");

                fos.close();
                s.close();
        }catch(IOException e){

        }

    }

}

12.常见客户端和服务端

最常见的客户端:
    浏览器:IE
最常见的服务端:
    web服务器:Tomcat

ip 网际层规则
TCP/UDP 传输层规则
http:// 应用层规则

这里写图片描述

13.客户端和服务端(浏览器)原理:

1.自定义服务端
使用已有的客户端IE,了解一下客户端给服务端发了说明请求。

public class IEServer {

    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();

    }

}

服务端接收到 客户端的请求显示:
请求行(请求方式(GET,POST)/请求的资源路径(这里没有请求资源)   http协议版本/1.01.1)
GET / HTTP/1.1 

请求消息头:属性名:属性值 (就是一些规则,告诉服务端,客户端能处理解析的内容,语言,)
Accept: text/html, application/xhtml+xml, image/jxr, */*   //支持的解析内容  
Accept-Language: zh-CN   //支持的语言
Accept-Encoding: gzip, deflate  //支持的解压缩方式(服务端将数据压缩发送过来)
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko//浏览器版本信息(QQ空间ie版本过低提示)
Host: 100.64.190.224:9090//客户端的主机(因为ip是不变的,但是主机名是可修改的,为了确定哪一个主机)
//Host: www.houyouni.com:9090  
Connection: Keep-Alive  //保持存活,close保持关闭

请求头和请求体之间必须有个空行
//请求体:自定义的信息。

客户端发出请求后得到的反馈:
这里写图片描述

2.模拟一个浏览器获取信息:
浏览器请求过程:
这里写图片描述

public class IEClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        Socket s = new Socket("100.64.190.224",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: 100.64.190.224:8080");
        out.println("Connection:close");
        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的协议版本 应答状态码 应答状态描述信息   200:成功  404:找不到页面
HTTP/1.1 200 OK   

//应答消息头(属性信息): 属性名:属性值(因为自定义的浏览器没有http解析器,所以应答行和消息头也打印出来了。可以用URL类的openStream()方法直接获得该URL连接的读入流InputStream。然后直接读入消息体。)
Accept-Ranges: bytes    
ETag: W/"42-1509883856548"
Last-Modified: Sun, 05 Nov 2017 12:10:56 GMT  //最后一次修改的事件
Content-Type: text/html  //数据类型
Content-Length: 42  //字节数
Date: Sun, 05 Nov 2017 12:14:16 GMT
Connection: close   //连接关闭
//空行
//应答消息体
<font color='red' size='7'>欢迎光临</font>

14.URL解析

1.获取url的信息。
String str_url = "http://100.64.190.224:8080/myweb/1.html?name=lisi";
URL url = new URL(str_url);

syso("Protocol:"url.getProtocol()); //协议
syso("getHost:"url.getHost());  //主机ip
syso("getPort:"url.getPort());  //端口
syso("getFile:"url.getFile());  //文件信息(路径+参数信息)
syso("getPath:"url.getPath());  //路经
syso("getQuery:"url.getQuery());  //参数信息

2.
InputStream openStream() 
          打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。 
    此方法是下面方法的缩写: 
       openConnection().getInputStream()

//只打印消息体:
InputStream in = url.openStream();
//原理:
//URLConnection conn = url.openConnection();
//InputStream in = conn.getInputStream();

    获得url连接器对象,解析具体的协议,可获取连接器对象的socket输入输出流:
    //获取url对象的url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket
    //URLConnection conn = url.openConnection();
    //syso(conn);
    //sun.net.www.protocol.http.HttpURLConnection:http://100.64.190.224:8080/myweb/1.htm
l?name=lisi
    //conn.getHeaderField("Content-Type");  // text/html

byte[] buf = new byte[1024];
int len = in.read(buf);

String text = new String(buf,0,len);

syso(text);

in.close();

URL解析代替Socket连接服务端:

public class IEClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        String str_url = "http://100.64.190.224:8080/myweb/1.html";
        URL url = new URL(str_url);

        URLConnection conn = url.openConnection();



        //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。

        PrintWriter out  = new PrintWriter(conn.getOutputStream(),true);
        out.println("GET /myweb/1.html HTTP/1.1");
        out.println("Accept: */*");
        out.println("Host: 100.64.190.224:8080");
        out.println("Connection:close");
        out.println();

        InputStream in = conn.getInputStream();

        byte[] buf = new byte[1024];
        int len = in.read(buf);

        String str = new String(buf,0,len);
        System.out.println(str);

        in.close();

    }

}

15.常见网络结构:

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


2.B/S: browser/server(javaweb)
    优点:
        该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。
        开发成本相对低,维护更为简单。
    缺点:所有运算都在服务器端完成。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章