java入门(网络编程)

网络编程

软件架构

  1. C/S : 客户端/服务器架构 , 例如:QQ,迅雷,微信,腾讯视频,爱奇艺其…
  2. B/S: 浏览器/服务器架构,例如:所有借助浏览器的应用都属于B/S, 淘宝网站,京东网站,公司门户网站…

网络通信协议

网络通信协议:就是网络数据传输的一种规范,规则。

  1. TCP:面向连接,只有建立了逻辑上连接(三次握手),才能够进行通信,传输数据安全可靠。例如:下载文件,网页浏览

  2. UDP:面向无连接。 传输不安全,但是数据传输效率快。 例如:视频会议…

网络通信3要素

  1. 协议:数据传输的规范
  2. IP地址: 找到网络设备,比如某台电脑
  3. 端口号:找到某台设备中运行的进程,端口号定义范围[0,65535],[0,1023]系统服务使用,如果要自己定义端口号,需要1024以上的端口号。同一台设备中,不同的进程,端口号一定是不一致。
    在这里插入图片描述

TCP编程

1:服务端和客户端的介绍

服务端:ServerSocket

客户端:Socket

在这里插入图片描述

2:客户端Socket类

客户端Socket类创建对象,可以连接指定地址,指定端口号的服务端。

  1. 构造方法

    public Socket(String host , int port) 
    host:服务端地址
    port:服务端程序的端口号
    

    协议不用管,底层封装好了

  2. 成员方法

    public OutputStream getOutputStream() 获取一个网络输出流,用来写数据到服务端
    public InpuptStream getInputStream()获取一个网络的输入流,用来读取服务端回传的数据
    public void close() 关闭客户端和服务端连接
    public void shutdownOutput() 关闭输出流,socket连接不会关闭。一般是在写出数据完毕之后,调用。
    
3:服务端ServerSocket

服务端ServerSocket类,用来接收客户端的连接,提供服务。

  1. 构造方法

    public ServerSocket(int port)
    port: 就是当前服务端程序的端口号,供客户端连接使用
    
  2. 成员方法

    public Socket accept() 当调用这个方法时,会进入阻塞状态,等待客户端连接。返回一个Socket对象,用来和客户端的Socket对象进行交互。
    

    服务端返回的Socket对象使用和客户端Socket对象使用,一样的。

4:实现简单的客户端和服务端通信

开发原理图,

注意:开发好服务端和客户端后,先开启服务端程序。

在这里插入图片描述

客户端代码实现

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

        //1.建立Socket对象指定服务端ip和端口
        Socket socket = new Socket("127.0.0.1", 8888);
        //2.获取网络输出流,进行发送数据给务端端
        OutputStream netOut = socket.getOutputStream();
        netOut.write("你好呀!吃饭了啊【来自客户端的问候】".getBytes());
        //3.调用shutDownOutputStream,告诉服务端传输完毕
        socket.shutdownOutput();
        //4.获取网络输入流用来读取服务端回传的数据
        InputStream netIn = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len;
        while ((len = netIn.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }
        //5.关闭服务
        socket.close();

    }
}

服务端代码实现

/*
服务端
 */
public class Server {
    public static void main(String[] args) throws IOException {
        //1.创建ServerSocket对象,绑定一个端口 8888
        ServerSocket serverSocket = new ServerSocket(8888);
        //2.调用accept方法接受客户端的连接【阻塞效果】
        System.out.println("等待客户端连接.....");
        Socket socket = serverSocket.accept();
        System.out.println("已经有一个客户端连接....");
        //得到一个用于服务客户端的Socket对象
        //3.获取网络输入流:读取客户端发送过来数据
        InputStream netIn = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len;
        while ((len = netIn.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }

        //4.获取网络输出流:响应数据到客户端
        OutputStream netOut = socket.getOutputStream();
        netOut.write("你也好呀!!我吃过了【响应自服务户端】".getBytes());

        //5.调用shutDownOutputStream,告诉客户端传输完毕
        socket.shutdownOutput();

        //6.关闭资源
        socket.close();
        serverSocket.close();//真实开发中,不会关

    }
}

文件上传案例

文件上传原理分析图:
在这里插入图片描述

客户端开发

读取本地文件到内存,使用网络输出流写出到网络中【服务端接收】

1)先把Socket对象创建,绑定服务端第的地址和端口
2)获取网络输出流,准备输出数据
3)创建本地的输入流,将文件读取到内存
4)边读数据,边写出到网络
5)写完后告诉服务端,数据传输完毕
6)接收服务端的结果响应
7)结束

代码实现:

public class Client {
    public static void main(String[] args) throws IOException {
        //1)先把Socket对象创建,绑定服务端第的地址和端口
        Socket socket = new Socket("127.0.0.1", 8888);
        //2)获取网络输出流,准备输出数据
        OutputStream netOut = socket.getOutputStream();
        //3)创建本地的输入流,将文件读取到内存
        FileInputStream localIn = new FileInputStream("client/美女.jpg");
        //4)边读数据,边写出到网络
        byte[] bytes = new byte[1024];
        int len;
        while ((len = localIn.read(bytes)) != -1) {
            //边读取本地数据,边写出到网络中
            netOut.write(bytes, 0, len);
        }
        //5)写完后告诉服务端,数据传输完毕
        socket.shutdownOutput();
        //6)接收服务端的结果响应
        InputStream netIn = socket.getInputStream();
        while ((len = netIn.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }
        //7)结束
        localIn.close();
        socket.close();//可以将网络流同时关闭

    }
}
服务端程序开发

服务端通过网络的输入流获取客户端的数据,并将数据写到硬盘

1)先创建Server Socket对象,绑定端口号 8888
2)接受客户端的连接,获取对应的Socket对象
3)获取网络输入流,读取客户端上传的数据
4)创建本地的输出流,将读取的数据写出到文件中
5)边读,边写
6)获取网络输出流,告诉客户端上传成功
7)告诉客户端数据发送完毕
8)关闭资源

代码实现

public class Server {
    public static void main(String[] args) throws IOException {
        //1)先创建Server Socket对象,绑定端口号 8888
        ServerSocket serverSocket = new ServerSocket(8888);
        //2)接受客户端的连接,获取对应的Socket对象
        System.out.println("等待客户端连接...");
        Socket socket = serverSocket.accept();
        System.out.println("客户端连接成功!!");
        //3)获取网络输入流,读取客户端上传的数据
        InputStream netIn = socket.getInputStream();
        //4)创建本地的输出流,将读取的数据写出到文件中
        FileOutputStream localOut = new FileOutputStream("server/beauty.jpg");
        //5)边读,边写
        byte[] bytes = new byte[1024];
        int len;
        while ((len = netIn.read(bytes)) != -1) {
            localOut.write(bytes, 0, len);
        }
        //6)获取网络输出流,告诉客户端上传成功
        OutputStream netOut = socket.getOutputStream();
        netOut.write("恭喜您!文件上传成功!".getBytes());
        //7)告诉客户端数据发送完毕
        socket.shutdownOutput();
        //8)关闭资源
        localOut.close();
        socket.close();//只能关闭网络流
        serverSocket.close();
    }
}

服务端开发优化1

改造为可以循环接受客户端连接,并文件不会覆盖的代码

/*
优化:
1.能让服务循环服务
2.上传的文件不能覆盖
 */

public class Server {
    public static void main(String[] args) throws IOException {
        //1)先创建Server Socket对象,绑定端口号 8888
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            //2)接受客户端的连接,获取对应的Socket对象
            System.out.println("等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端连接成功!!");
            //3)获取网络输入流,读取客户端上传的数据
            InputStream netIn = socket.getInputStream();
            //4)创建本地的输出流,将读取的数据写出到文件中
            long time = System.currentTimeMillis();
            FileOutputStream localOut = new FileOutputStream("server/beauty" + time + ".jpg");
            //5)边读,边写
            byte[] bytes = new byte[1024];
            int len;
            while ((len = netIn.read(bytes)) != -1) {
                localOut.write(bytes, 0, len);
            }
            //6)获取网络输出流,告诉客户端上传成功
            OutputStream netOut = socket.getOutputStream();
            netOut.write("恭喜您!文件上传成功!".getBytes());
            //7)告诉客户端数据发送完毕
            socket.shutdownOutput();
            //8)关闭资源
            localOut.close();
            socket.close();//只能关闭网络流
        }

        //serverSocket.close();

    }
}

服务端开发优化2

借助多线程实现

/*
优化:
线程优化,能够让多个客户端并发上传数据
 */

public class Server {
    public static void main(String[] args) throws IOException {
        //1)先创建Server Socket对象,绑定端口号 8888
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            //2)接受客户端的连接,获取对应的Socket对象
            System.out.println("等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端连接成功!!");

            //每获取一个socket连接都会开启一个线程用来服务
            new Thread(() -> {
                try {
                    //3)获取网络输入流,读取客户端上传的数据
                    InputStream netIn = socket.getInputStream();
                    //4)创建本地的输出流,将读取的数据写出到文件中
                    long time = System.currentTimeMillis();
                    FileOutputStream localOut = new FileOutputStream("server/beauty" + time + ".jpg");
                    //5)边读,边写
                    byte[] bytes = new byte[1024];
                    int len;
                    while ((len = netIn.read(bytes)) != -1) {
                        localOut.write(bytes, 0, len);
                    }
                    //6)获取网络输出流,告诉客户端上传成功
                    OutputStream netOut = socket.getOutputStream();
                    netOut.write("恭喜您!文件上传成功!".getBytes());
                    //7)告诉客户端数据发送完毕
                    socket.shutdownOutput();
                    //8)关闭资源
                    localOut.close();
                    socket.close();//只能关闭网络流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

        }

        //serverSocket.close();

    }
}

BS服务端开发

原理分析:

在这里插入图片描述

服务器端开发
  1. 准备数据,资料中由一个web文件夹拷贝到根目录
  2. 开发服务端(文件上传的案例类似)

注意:

  1. 获取浏览器访问时,需要解析浏览器所要的资源

    会收到浏览器访问的数据:  http协议数据
    GET /web/index.html HTTP/1.1
    ....
    ....
    传过来的第一行数据中存在,
    1:请求的方式:GET (POST PUT..2:浏览器需要的资源:web/index.html
    3:协议的版本:HTTP/1.1
    
  2. 将浏览器所需的资源,通过网络输出流输出到网络中,写出数据时,先写协议,浏览器才能够认识。

    netOut.write("HTTP/1.1 200 OK\r\n".getBytes());
    netOut.write("Content-Type:text/html\r\n".getBytes());
    netOut.write("\r\n".getBytes()); //第三行空行
    
  3. 访问自己的服务器:http://127.0.0.1:7788/web/index.html,如果要访问同桌的服务器,直接更换IP地址

代码实现

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8899);
        while (true) {
            //等待浏览器访问
            System.out.println("等待浏览器访问....");
            Socket socket = serverSocket.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {

                    try {
                        //获取浏览器想要的资源
                        String path = getPath(socket);
                        if (path == null || path.equals("favicon.ico")) {
                            System.out.println("没有文件....");
                            socket.close();
                            //continue; while循环中
                            return;
                        }

                        //获取网络输出流将资源传输给浏览器
                        OutputStream netOut = socket.getOutputStream();
                        //获取本地的输入流,将资源读取到内存中
                        FileInputStream localIn = new FileInputStream(path);
                        //写协议
                        netOut.write("HTTP/1.1 200 OK\r\n".getBytes());
                        netOut.write("Content-Type:text/html\r\n".getBytes());
                        netOut.write("\r\n".getBytes()); //第三行空行
                        //边读边写
                        int len;
                        byte[] bytes = new byte[1024];
                        while ((len = localIn.read(bytes)) != -1) {
                            netOut.write(bytes, 0, len);
                        }
                        socket.shutdownOutput();
                        socket.close();

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }).start();
        }

    }

    public static String getPath(Socket socket) throws IOException {
        //获取网络输入流,用来接收浏览器发送过来的数据
        InputStream netIn = socket.getInputStream();
        //把输入流转化成字符流
        InputStreamReader isr = new InputStreamReader(netIn);
        //把上面的字符流包装成高效流
        BufferedReader br = new BufferedReader(isr);

        //读取http协议的第一行数据:GET /web/index.html HTTP/1.1
        String firstLine = br.readLine();
        if (firstLine == null) {
            return null;
        }
        String path = firstLine.split(" ")[1].substring(1); //web/index.html}
        return path;

    }
    
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值