< 笔记 > Java SE - 08 Java SE 网络编程

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>
应答状态码应答状态描述信息
200OK
404not 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低,维护简单
    • 缺点
      • 所有运算都在服务端完成
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值