美文网首页
JAVA-网络编程1(基础知识详解)

JAVA-网络编程1(基础知识详解)

作者: 宁晓鸯 | 来源:发表于2019-08-21 23:23 被阅读0次

    心得体会

    • 今天学的东西挺有趣的,从简单的服务端与客户端模拟,到实现群聊,一步一步感觉demo实现的功能越来越多。同一段的代码,不厌其烦的反复敲,与其他代码组合起来,就实现了不同的功能^^
      --

    今日所学

    • 1.OSI与TCP/IP体系模型

    • 2.URL

    • 3.IP地址和端口

    • 4.TCP和UDP

    • 5.Socket

    • 6.服务器端和客户端(聊天小demo)

    具体操作

    1.OSI与TCP/IP体系模型

    image.png
    image.png

    2.URL

    URL的定义

    URL是统一资源定位符(Uniform Resource Locator,缩写为URL),又叫做网页地址,是互联网上标准的资源的地址(Address)。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

    URL的组成
    PVF1_B{`M{4SFAN`04DAUJG.png

    http://www.baidu.com/search?code=android

    http:——指定因特网服务的类型。最流行的类型是HTTP
    www.baidu.com——域名 表示一台网络中的电脑
    search——URL的这部分被称为层级文件路径
    code=android —— 查询字符串是一个非必须的字段,只要负责将一系列非层级格式的任意参数传给服务器。可同时传递多个参数,参数之间用“&"符号连接,每个参数名与值用 = 隔开
    & ——如果有多个参数使用&符号链接 例如: www.baidu.com?uid=777&qqq=666


    3.IP地址和端口号

    • 1、IP地址用于唯一标示网络中的一个通信实体。这个通信实体可以是一台主机,可以是一台打印机,或者是路由器的某一个端口。而在基于IP协议网络中传输的数据包,必须使用IP 地址来进行标示。IP地址就像写一封信,必须指定收件人的地址一样。每个被传输的数据包中都包括了一个源IP和目标IP。
    • 2、IP地址唯一标示了通信实体,但是一个通信实体可以有多个通信程序同时提供网络服务。这个时候就要通过端口来区分开具体的通信程序。一个通信实体上不能有两个通信程序,使用同一个端口号。
    • 3.IP地址和端口号,就像一个出差去外地入住酒店一样,IP地址表示了酒店在具体位置,而端口号则表示了这个人在酒店的房间号。

    4.TCP和UDP

    1、TCP是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。它能够提供两台计算机之间的可靠的数据流,HTTP、FTP、Telnet等应 用都需要这种可靠的通信通道。

    2、UDP是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传送目的地,至于能够达到目的地,达到目的地的时间以及内容的正确性都是不能保证的。

    既然有了保证可靠传输的TCP协议,为什么还要非可靠传输的UDP协议呢?原因有两个:

    • 1、可靠的传输是要付出代价的,对数据内容的正确性的检验必然会占用计算机处理时间和网络带宽。因此TCP的传输效率不如UDP高。
    • 2、许多应用中并不需要保证严格的传输可靠性,比如视频会议系统,并不要求视频音频数据绝对正确,只要能够连贯就可以了。所以在这些场景下,使用UDP更合适些。

    5.Socket

    Socket定义

    套接字(通讯双方C/S协商好的约定),网络上两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket。应用程序通过套接字向网络发出请求或者应答网络请求。

    image.png
    网络通信的要素
    • 网络请求就是通过Socket建立连接然后互相通信

    ①IP地址(主机的唯一标识)
    ②端口号(定位程序,标示不同的进程)
    ③传输协议(通讯的规则)[常见的协议:TCP、UDP]


    2.服务器端和客户端

    服务器端和客户端的定义与联系
    • 服务器端:

    服务端是为客户端服务的,服务的内容诸如向客户端提供资源,保存客户端数据。例如:手机的存储、数据处理

    • 客户端:

    客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务器端互相配合运行 例如:手机app 浏览器 桌面QQ

    客户端、服务器端模拟
    demo1—实现客户端和服务器端传递数据:( 注意端⼝号必须相同 先运⾏Server 再运⾏Client)
    • 服务器端
    • 1.新建一个Server类,并在类中写一个main方法
    • 2.创建服务器端的ServerSocket(直接创建一个ServerSocket对象,并写一个端口 ) (注意:端口的值不能太大,否则会出现异常!!!)
    • 3.获取连接的客户端的socket
    • 4.向客户端发送数据
    • 5.接收客户端发来的数据
    //模拟服务器端
    class Server{
        public static void main(String[] args)throws IOException{
            //1.创建服务器端的ServerSocket
            ServerSocket ss=new ServerSocket(8989);
    
            //2.获取连接的客户端的socket
            Socket clientSocket=ss.accept();
    
            //3.向客户端发送数据
            //BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(cilentSocket.getOutputStream()));
            PrintStream ps=new PrintStream(clientSocket.getOutputStream());
            ps.println("登录成功");
            clientSocket.shutdownOutput();
            //4.接收客户端发来的数据
            BufferedReader br=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String line=null;
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
        }
    }
    

    ps:

    • 1.在创建ServerSocket对象时会出现 异常,这时需要抛出异常或自己处理异常,上图代码采取的是系统自动抛出异常
    • 2.向客户端发送数据有两种方式,一种用BufferedWriter,一种用 **PrintStream**
    • 3.向客户端发送数据后需要关闭数据

    • 客户端:
    • 1.新建一个Client类
    • 2.创建用于通信的socket (指明和谁通信:ip地址 端口号)
    • 3.接收服务器端的数据
    • 4.读取服务器端发来的数据
    • 5.客户端向服务器端发送数据
    class Client{
        public static void main(String[] args) throws IOException {
            //1.创建用于通信的socket
            //指明和谁通信:ip地址 端口号
            Socket socket=new Socket("192.168.43.121",8989);
            //接收服务器端的数据
           BufferedReader br=new BufferedReader( new InputStreamReader(socket.getInputStream()));
            //读取服务器端发来的数据
           // socket.getOutputStream();
            String line =null;
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
            //客户端向服务器端发送数据
            PrintStream ps=new PrintStream(socket.getOutputStream());
            ps.println("你好啊!");
            socket.shutdownOutput();
        }
    }
    

    ps:

    • 1.在创建Socket对象时会出现 异常,这时需要抛出异常或自己处理异常,上图代码采取的是系统自动抛出异常
    • 2.向服务器端发送数据后需要关闭数据

    运行结果:


    13X5Q9@V9${O__R@$NZPKA5.png
    image.png
    demo2—实现服务器端⼿动输⼊,将输⼊的内容发送给客户端 ,可以⼀直发( 注意端⼝号必须相同 先运⾏Server 再运⾏Client)
    • 服务器端
    class MyServer{
        public static void main(String[] args){
            //创建ServerSocket
            try (ServerSocket ss = new ServerSocket(8888)){
                //监听客户端的连接
                Socket socket = ss.accept();
    
                //从终端接收数据
                BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
                //获取向客户端输出数据的输出流
                PrintStream ps = new PrintStream(socket.getOutputStream());
                String line = null;
    
                while ((line = keyin.readLine()) != null){
                    //发送给客户端
                    ps.println(line);
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    • 客户端:
    class Myclient{
        public static void main(String[] args){
            //连接服务器端的socket
            Socket socket = null;
            try{
                socket = new Socket("192.168.43.121",8888);
    
                //接收服务器端信息
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line = null;
                while ((line = br.readLine()) != null){
                    System.out.println(line);
                }
    
                //从键盘输入数据 发送给服务器端
            } catch (IOException e) {
                System.out.println("网络出错 请重新登录");
            } finally {
                //关闭连接
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    PS:

    • 1.创建的对象的时候有异常,此时应该捕获异常,并且最后还要用finally来关闭(finally是必须执行的,有清理资源等作用),finally有异常进行捕获
    • 2.**demo1与demo2最大的区别是demo2实现了从终端输入
      BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
      运行结果
      20190821_221949.gif
    demo3—实现客户端向服务器端上传图⽚
    • 服务器端
    class Server{
        public static void main(String[] args) throws IOException {
            //创建服务器端的ServerSoket
            ServerSocket ss = new ServerSocket(8080);
    
            //监听客户端连接
            //当有客户端来连接这个服务器 就可以得到对应的socket
            //当没有客户端来连接 服务器一直在这里等待
            Socket socket = ss.accept();
    
            //创建客户端对应的输出流 用于向这个客户端发送数据
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("连接成功 可以发数据了!");
    
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String path = "F:/JAVA/DAY12/Day1/src/main/java/Day12/java/media/1.jpg";
            FileOutputStream fos = new FileOutputStream(path);
    
            byte[] buf = new byte[1024];
            int len = -1;
            while((len = bis.read(buf)) != -1){
                fos.write(buf,0,len);
            }
        }
    }
    
    • 客户端:
    class Client{
        public static void main(String[] args) throws IOException {
            //连接服务器 获取socket
            Socket socket = new Socket("192.168.43.121",8080);
    
            //创建服务器端对应的输入流 用于接收服务器端发来的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(br.readLine());
    
            //向服务器端发送文件(图片)
            //1.将文件写入到内存里
            String path = "C:/Users/Administrator.000/Desktop/psd/4456d40b75f2f8b4";
            FileInputStream fis = new FileInputStream(path);
    
            //2.创建字节流 outputStream
            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
            byte[] buf = new byte[1024];
            int len = -1;
            while ((len = fis.read(buf)) != -1){
                bos.write(buf,0,len);
            }
            socket.shutdownOutput();
        }
    }
    
    7$Q(QXO8O`DV1A284FI5`Y4.png U5BV(){G)`CG_I4KV{_85MV.png
    PS:
    • 我选择图片时用png格式不能成功,如果用png格式不行,可以换一个格式看看

    demo4—使⽤多线程实现对聊

    为什么要用多线程实现?

    • 聊天的过程是双向,同时进行的
    class Client{
        public static void main(String[] args)throws IOException {
            Socket socket=new Socket("192.168.43.121",8888);
            //用一个子线程处理服务器端数据
            new Thread(new ClientThread(socket)).start();
    
            //主线程处理终端输入发送给服务器端
            BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
            PrintStream ps=new PrintStream(socket.getOutputStream());
            String line=null;
            while((line=keyin.readLine())!=null){
                ps.println(line);
            }
        }
    }
    
    /**
     * 创建一个子线程处理客户端接收服务器端数据
     */
    class ClientThread implements Runnable{
        private Socket socket;
        //保存操作socket
        public ClientThread(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            BufferedReader br=null;
            try {
                 br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //读取数据
                String line=null;
                while((line=br.readLine())!=null){
                    System.out.println(line);
                }
            }catch(IOException e){
                System.out.println("网络出错 请重新登录");
                System.exit(-1);
            }finally{
                try {
                    if (br != null) {
                        br.close();
                    }
                    if(socket!=null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                    }
             }
        }
    }
    class Server{
        public static void main(String[] args)throws IOException{
            ServerSocket ss=new ServerSocket(8888);
            //获取客户端的socket
            Socket socket= ss.accept();
    
            new ServerThread(socket).start();
    
            //从终端输入流对象
            BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
            //客户端的输出流对象
            PrintStream ps=new PrintStream(socket.getOutputStream());
    
            //读取终端的输入 将输入输出给客户端
            String line=null;
            while((line=keyin.readLine())!=null){
                ps.println(line);
            }
        }
    }
    /**
     * 服务器端创建一个子线程处理服务器端接受客户端的数据
     */
    class ServerThread extends Thread{
        private Socket socket;
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedReader br =null;
            try {
                 br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line=null;
                    while((line=br.readLine())!=null){
                        System.out.println(line);
                }
            }catch(IOException e){
                System.out.println("网络出错 请重新登录");
                System.exit(-1);
            }finally{
                try {
                    if (br != null) {
                        br.close();
                    }
                    if(socket!=null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    

    PS:

    • 1.上图的demo中创建子线程用了继承Thread的方法
      运行结果:


      ![`]E13M5$OXFI)N2MF2N368E.png
    image.png
    demo4—实现群聊
    • Client和ClientThread代码和对聊不变,主要在Server⾥添加数组和监听客户端连接


      2ZPYR{~)(5IS2J_AEAVR_QG.jpg
    class server{
        public static ArrayList<Socket> sockets=new ArrayList<>();
        public static void main(String[] args)throws IOException {
            ServerSocket ss=new ServerSocket(6666);
    
            //不停的等待用户端连接
            while(true) {
                Socket socket = ss.accept();
                //当有客户端连接过来了 就保存
                sockets.add(socket);
    
                //开启一个线程处理每个客户端的输入
                new ServerThread(socket).start();
            }
        }
    }
    /**
     * 服务器端创建一个子线程处理服务器端接受客户端的数据
     */
    class ServerThread extends Thread{
        private Socket socket;
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedReader br =null;
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line=null;
                while((line=br.readLine())!=null){
                    //群发消息
                    //遍历数组
                    for(Socket s:server.sockets){
                        PrintStream ps=new PrintStream(s.getOutputStream());
                        ps.println(line);
                    }
                }
            }catch(IOException e){
                System.out.println("网络出错 请重新登录");
                System.exit(-1);
            }finally{
                try {
                    if (br != null) {
                        br.close();
                    }
                    if(socket!=null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    class Client{
        public static void main(String[] args)throws IOException {
            Socket socket=new Socket("192.168.43.121",6666);
            //用一个子线程处理服务器端数据
            new Thread(new ClientThread(socket)).start();
    
            //主线程处理终端输入发送给服务器端
            BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
            PrintStream ps=new PrintStream(socket.getOutputStream());
            String line=null;
            while((line=keyin.readLine())!=null){
                ps.println(line);
            }
    
    
        }
    
    }
    
    /**
     * 创建一个子线程处理客户端接收服务器端数据
     */
    class ClientThread implements Runnable{
        private Socket socket;
        //保存操作socket
        public ClientThread(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            BufferedReader br=null;
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //读取数据
                String line=null;
                while((line=br.readLine())!=null){
                    System.out.println(line);
                }
            }catch(IOException e){
                System.out.println("网络出错 请重新登录");
                System.exit(-1);
            }finally{
                try {
                    if (br != null) {
                        br.close();
                    }
                    if(socket!=null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    20190821_231418.gif
    PS:
    • 所连接的所有客户端,端口号必须一致!!!

    相关文章

      网友评论

          本文标题:JAVA-网络编程1(基础知识详解)

          本文链接:https://www.haomeiwen.com/subject/pphisctx.html