< 笔记 > Java SE

来源:互联网 发布:学乐器的软件 编辑:程序博客网 时间:2024/05/29 07:10

08 Java SE 网络编程

By Kevin Song

  • 08-01 网络模型概述
  • 08-02 TCP和UDP协议
  • 08-03 网络编程其他

08-01 网络模型概述

网络模型

  • OSI(Open System Interconnection)开放系统互联参考模型

    • 应用层
      • 终端应用
    • 表示层
      • 把计算机能识别的东西表示成人能识别的东西
    • 会话层
      • 在系统之间发起会话,会话请求
    • 传输层
      • 定义传输协议和端口号
        • TCP(传输控制协议)
          • 传输效率低
          • 可靠性强
          • 传输数据量大的数据
        • UDP(用户数据报协议)
          • 可靠性低
          • 传输数据量小的数据
      • 这一层数据叫:段
    • 网络层
      • IP地址的封装和解封装
      • 这一层数据叫:数据包
      • 这一层设备是:路由器
    • 数据链路层
      • MAC地址的封装和解封装
      • 这一层数据叫:帧
      • 这一层设备是:交换机
    • 物理层
      • 定义物理设备标准
      • 作用是传输比特流
      • 这一层数据叫:比特
  • TCP/IP参考模型

    • 应用层:数据段
    • 传输层:数据包
    • 网际互连层:数据帧
    • 网络接入层:比特

网络通讯要素

  • IP地址
    • 网络中设备的标识
    • 本地回环地址:127.0.0.1 主机名:localhost
  • 端口号
    • 用于标识进程的逻辑地址
    • 有效端口:0 - 65535
    • 系统保留端口:0 - 1024
  • 传输协议
    • 通讯的规则
    • 常见协议
      • TCP(传输控制协议)
        • 建立链接,形成传输数据的通道
        • 在连接中进行大数据量传输
        • 通过三次握手完成连接,所以可靠
          • Client:Server 帮个忙噻
          • Server:干什么噻
          • Client:那就谢谢了
        • 因为要连接,所以速度慢
        • 类似电话
      • UDP(用户数据报协议)
        • 数据和源目封装成数据包,不需要建立连接
        • 每个数据报文限制在64k内
        • 因为无连接,所以不可靠
        • 因为无连接,所以速速快
        • 类似对讲机

InetAddress类

作用:InetAddress类表示互联网协议(IP)地址

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

08-02 TCP和UDP协议

Socket

  • Socket就是为网络服务提供的一种机制
  • 通信的两段都有Socket
  • 网络通信其实就是Socket间的通信
  • 数据在两个Socket间通过IO传输

UDP协议

UDP协议发送端

创建UDP发送端思路
- 建立UDP的socket服务
- 将要发送的数据封装到数据包中
- 通过UDP的socket服务将数据包发送出去
- 关闭socket服务

public class UDPSendDemo {    public static void main(String[] args) {        //1.建立UDP的socket服务        DatagramSocket ds = new DatagramSocket();        //2.将要发送的数据封装到数据包中        String str = "UDP transmitting";            //用DatagramPacket将数据封装到该对象中        byte[] buf = str.getBytes();        DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.100"),10000);        //3.通过UDP的Socket服务将数据包发送出去        ds.send(dp);        //4.关闭socket服务        ds.close();    }}

UDP协议接收端

创建UDP接收端思路:

  • 建立UDP的socket服务,必须明确端口号
  • 将要接受的数据存储到数据包中
  • 用socket的receive方法接收数据,存储到数据包中
  • 通过数据包的方法解析数据包中的数据
  • 关闭socket服务
public class UDPReceiveDemo {    public static void main(String[] args) {        //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 UDPSendDemo {    public static void main(String[] args) {        //1.建立UDP的socket服务        DatagramSocket ds = new DatagramSocket(8888);        //2.将要发送的数据封装到数据包中        //String str = "UDP transmitting";        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        String line = null;        while((line=bufr.readLine())!=null) {            if("over".equals(line))                break;            byte[] buf = line.getBytes();            //用DatagramPacket将数据封装到该对象中            DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.100"),10000);            //3.通过UDP的Socket服务将数据包发送出去            ds.send(dp);        }        //4.关闭socket服务        ds.close();    }}
public class UDPReceiveDemo {    public static void main(String[] args) {        //1.建立UDP的socket服务        DatagramSocket ds = new DatagramSocket(10000);        while(true) { //持续接收数据            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);        }        //2.创建数据包        //5.关闭资源        //ds.close();}

多线程实现的聊天程序

public class ChatDemo {    /**     * @param args     * @throws IOException      */    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 Rece implements Runnable {    private DatagramSocket ds;    public Rece(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();                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) { }    }}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) {}    }}

TCP协议

概述

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

客户端

建立客户端思路
- 创建TCP客户端Socket服务
- 使用Socket对象
- 建议该对象已创建就明确目的地,要连接的主机
- 如果连接建立成功,说明数据传输通道已建立
- 通道就是Socket流,包含输入输出
- 通过Socket来获取输入输出对象
- 通过getOutputStream()和getInputStream()来获取输入输出字节流
- 使用输出流,发送到服务器
- 关闭资源

public class ClientDemo {    public static void main(String[] args) {        //1.创建客户端socket服务        Socket socket = new Socket("192.168.1.100", 10002);        //2.获取socket流中的输出流        OutputStream out = socket.getOutputStream();        //3.使用输出流将制定的数据写出去        out.write("TCP transmitting".getBytes());        //4.关闭资源        socket.close();    }}

服务端

建立服务端思路
- 创建TCP服务端Socket服务
- 使用ServerSocket对象
- 服务端必须对外提供一个端口,否则客户端无法连接
- 获取连接过来的客户端对象
- 通过客户端对象获取socket流读取客户端发来的数据
- 关闭资源(客户端,服务端资源都要关闭)

public class ServerDemo {    public static void main(String[] args) {        //1.创建服务端socket服务        ServerSocket ss = new ServerSocket(10002);        //2.获取连接过来的客户端对象        Socket s = ss.accept();        String ip = s.getInetAddress().getHoustAddress();        //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("server:"+text);        //4.关闭客户端,关闭服务端        s.close();        ss.close();    }}

客户端服务端交互

public class ClientDemo {    public static void main(String[] args) {        //1.创建客户端socket服务        Socket socket = new Socket("192.168.1.100", 10002);        //2.获取socket流中的输出流        OutputStream out = socket.getOutputStream();        //3.使用输出流将制定的数据写出去        out.write("TCP transmitting".getBytes());        //读取服务端返回的数据,使用socket读取流        InputStream in = socket.getInputsStream();        byte[] buf = new byte[1024];        int len = in.read(buf);        String text = new String(buf,0,len);        System.out.println(text);        //4.关闭资源        socket.close();    }}
public class ServerDemo {    public static void main(String[] args) {        //1.创建服务端socket服务        ServerSocket ss = new ServerSocket(10002);        //2.获取连接过来的客户端对象        Socket s = ss.accept();        String ip = s.getInetAddress().getHoustAddress();        //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.getOutpuStream();        out.write("Roger that".getBytes());        //4.关闭客户端,关闭服务端        s.close();        ss.close();    }}

文本转换

客户端思路

  • 创建socket客户端对象
  • 获取键盘录入
  • 将录入的信息发送给socket输出流
public class TransClient {    public static void main(String[] args) {        //1.创建socket客户端对象        Socket s = new Socket("192.168.1.100",10004);        //2.获取键盘输入        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));        //3.socket输出流        //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);            //读取服务器发回的一行大写数据            String upperStr = bufIn.readLine();            System.out.println(upperStr);        }        s.close();    }}

服务端思路

  • ServerSocket服务
  • 获取Socket对象
  • 源:socket,读取客户端发过来的需要转换的数据
  • 目的:显示在控制台上
  • 转换成大写发送给客户端
public class TransServer {    public static void main(String[] args) {        //1.ServerSocket服务        ServerSocket ss = new ServerSocket(10004);        //2.获取socket对象        Socket s = ss.accept();        //获取IP        String ip = s.getInetAddress().getHostAddress();        System.out.println(ip+"......connected");        //3.获取socket读取流并装饰        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));        //4.获取socket输出流并装饰        PrintWriter out = new PrintWriter(s.getOutputStream(),true);        String line = null;        while((line=bufIn.readLine())!=null){            System.out.println(line);            out.println(line.toUpperCase());            //out.print(line.toUpperCase()+"\r\n");            //out.flush();    }    s.close();    ss.close();}

上传文本文件

public class UploadClient {    public static void main(String[] args) {        Socket s = new Socket("192.168.1.100",10005);        BufferedReader bufr = new BufferedReader(new FileReader("client.txt"));        PrintWriter out = new PrintWriter(s.getOutputStream(),true);        String line = null;        while((line=bufr.readLine())!=null) {            out.println(line);        }        //告诉服务端,客户端写完了        s.shutdownOutput();        //out.println("over");        BufferedRedaer bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));        String str = bufIn.readLine();        System.out.println(str);        bufr.close();        s.close();    }}
public class UploadServer {    public static void main(String[] args) {        ServerSocket ss = new ServerSocket(10005);        Socket s = ss.accept();        System.out.println(s.getInetAddress().getHostAddress()+"...connected");        BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));        BufferedWriter bufw = new BufferedWriter(new FileWriter("server.txt"));        String line = null;        while((line=bufIn.readLine())!=null) {            if("over".equals(line))                break            bufw.write(line);            bufw.newLine();            bufw.flush();        }        PrintWriter out = new PrintWriter(s.getOutputStream(),true);        out.println("upload complete");        bufw.close();        s.close();        ss.close();    }}

上传图片

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();    }}
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 Socket s;    private 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");            if(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);            }            //获取socket输出流,把文件发送给客户端            OutputStream out = s.getOutputStream();            out.wirte("upload complete".getBytes());            fos.close();            s.close();        } catch (IOException e) {}    }}

08-03 网络编程其他

常见客户端和服务端

常见的客户端

  • 浏览器
    • Chrome,Edge,Firefox

常见的服务端

  • 服务器
    • Tomcat

自定义客户端和服务端

自定义服务端

  • 自定义服务端,使用已有的客户端IE,了解客户端给服务器端发了什么请求
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();    }}

服务端获取的信息如下:

请求行 请求方式
GET / HTTP/1.1 /myweb/1.html 请求的资源路径 http协议版本
请求消息头,属性名:属性值
**Accept: */*
Accept-Language: zh-cn, zu;q=0.5
Accept-Encoding:gzip, deflate
User-Agent: Mozilla/4.0
Host: 192.168.1.105:9090
Connection: Keep-Alive**
//空行(请求头和请求体之间有空行)
请求体
……

自定义客户端

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    }}

浏览器获取的信息如下:

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: 100
Date: Fri, 11 May 2012 07:51:39 GMT
Connection: close**
//空行
应答体

<html>    <head>        <title></title>    </head>    <body>        <h1>欢迎光临</h1>        <font size="5" color="red"> html网页 </font>    </body></html>
应答状态码 应答状态描述信息 200 OK 404 not found

URL&URL Connection

public class URLDemo {    public static void main(String[] args) throws MalformedURLException {        String str_url = "http://192.168.1.100:8080/myweb/1.html?name=lisi";        URL url = new URL(str_url);        /*        System.out.println(""+url.getProtocol());        System.out.println(""+url.getHost());        System.out.println(""+url.getPort());        System.out.println(""+url.getFile());        System.out.println(""+url.getPath());        System.out.println(""+url.getQuery());        */        //InputStream in = url.openStream();        //获取url对象的url连接器对象,将连接封装成了对象        //Java中内置的可以解析的具体协议的对象+socket        URLConnection conn = url.openConnection();        //System.out.println(conn);        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();    }}

常见网络架构

  • C/S (Client/Server)
    • 缺点
      • 客户端服务端都需要开发
      • 开发成本高,维护麻烦
    • 优点
      • 客户端在本地可以分担运算
  • B/S (Browser/Server)
    • 优点
      • 服务端需要开发,客户端不需要开发,直接用浏览器
      • 开发成本相对C/S低,维护简单
    • 缺点
      • 所有运算都在服务端完成