美文网首页
Java之Socket网络编程

Java之Socket网络编程

作者: 凌云struggle | 来源:发表于2019-08-21 20:48 被阅读0次

    Java网络编程

    • 网络编程:指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

    URL处理:http://www.baidu.com/search?code=Android&type=1

    • URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。
    • http/https :传输协议 TCP/IP协议
    • www.baidu.com :域名表示一台网络中的电脑
      (ipv4 ipv6 )IP地址:唯一标识一台网络中的计算机
                  32位:4个部分 每部分8个字节
    • DNS服务器:域名解析 将www.baidu.com的域名解析为对应的IP地址
    • search:对应的后天程序文件 php java jsp
    • ? 表示运行这个程序需要传递的参数
    • code=Android code是服务器端规定的字段
    • & 如果有多个参数使用&连接

    ps:查找自己的电脑IP:win+R进入DOS窗口输入ifconfig即可

    • 数据传输主要通过TCP/IP协议,以下是两种常见的协议:
      • TCP(安全):TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

      • UDP(不安全,但是快):UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

    Socket 编程

    相关概念

    • IP地址:唯一标识某一台电脑

    • 端口号:唯一标识电脑上的某一个进程(程序)80

    • Socket类:客户端 手机应用、浏览器等

    • ServerSocket:服务器端 存储、处理数据

    image.png

    使用方法:

    • 读取数据:客户端读取 服务器端读取
      BufferedReader->InputStreamReader->socket.getInputStream()
    • 读取终端
      BufferedReader->InputStreamReader->System.in
    • 输出:客户端输出 服务器端输出
      BufferedWriter->OutputStreamWriter->serverSocket.getOutputStream()
      PrintStream(socket.getOutputStream)

    1. 实现客户端和服务器端传递数据(注意端⼝号必须相同 先运⾏Server 再运⾏Client)

    客户端:(1)创建用于通信的Socket,指明IP地址与端口号。
            (2)使用BufferedReader用循环接收服务器端的数据。
            (3)使用PrintStream向服务器端发送数据,并告诉发送完成socket.shutdownOutput()。
    服务器端:(1)创建服务器端的ServerSocket,并指明端口。
              (2)用serverSocket.accept()获取连接客户端的socket。
              (3)用PrintStream向客户端发送数据,完成时使用serverSocket.shutdownOutput()
              (4)使用BufferedReader接收客户端发来的数据

    模拟客户端:

    //模拟客户端
    //10.129.49.204
    class Client{
        public static void main(String[] args) throws IOException {
            // 1.创建用于通信的Socket
            //  指明和谁通信:IP地址 端口号
            Socket socket = new Socket("10.129.25.52",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();
        }
    }
    
    

    模拟服务器端:

    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(clientSocket.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);
            }
        }
    }
    

    2. 手动输入内容发送,将输⼊的内容发送给客户端 可以⼀直发

    异常处理:如果出现异常,按从小到大关闭资源

    两种方式处理异常:

    • 方式1使用if判断语句
     Socket socket = null;
            try {
                socket = new Socket("10.129.49.204",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();
                }
            }
    
    • 方式2
     try( ServerSocket serverSocket = new ServerSocket(8888)) {
                // 监听客户端
                Socket socket = serverSocket.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("10.129.49.204",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();
                }
            }
    
        }
    }
    
    
    class MyServer{
        public static void main(String[] args){
            //创建ServerSocket  自动关闭
            try( ServerSocket serverSocket = new ServerSocket(8888)) {
                // 监听客户端
                Socket socket = serverSocket.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();
            }
    
        }
    }
    
    

    3. 实现客户端向服务器端上传图⽚(字节流)

    class Client{
        public static void main(String[] args) throws IOException {
            //链接服务器端  获取socket
            Socket socket = new Socket("10.129.49.204",8080);
    
            //创建服务器端对应的输入流 用于接受服务器端发来的数据
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
           System.out.println( bufferedReader.readLine());
    
           //向服务器端发送文件(图片)
            String path = "C:\\Users\\gyl\\Desktop\\1.jpg";
            //1. 将文件写入到内存
            FileInputStream fis = new FileInputStream(path);
    
            // 2 .创建字节流 outputStream
            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer)) != -1){
                bos.write(buffer,0,length);
            }
            socket.shutdownOutput();
    
    
        }
    }
    
    
    class Server{
        public static void main(String[] args) throws IOException {
            //创建服务器的serverSocket
            ServerSocket serverSocket = new ServerSocket(8080);
    
            //监听客户端连接
            //当有客户端来连接这个服务器  就可以得到对应的socket
            //当没有客户端来连接 服务器一直在这里等待
            Socket socket = serverSocket.accept();
    
            //创建客户端对应的输出流对象 用于向这个客户端发送数据
            PrintStream printStream = new PrintStream(socket.getOutputStream());
            printStream.println("连接成功  可以发送数据了");
    
            // 接收客户端传递过来的图片
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            //文件对应的输出流
            String path = "D:\\AndroidStudioProjects\\JavaCourse\\Java\\src\\main\\java\\day12\\media\\1.jpg";
            FileOutputStream fos = new FileOutputStream(path);
    
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = bis.read(buffer)) != -1){
                fos.write(buffer,0,length);
            }
        }
    }
    
    

    4.使⽤多线程实现对聊

    • 创建一个类实现Runnable接口,重写run方法
    • 创建一个类继承于Thread类,重写run方法
    /**
     * 客户端和服务器端可以随意的发送内容
     * 从终端输入
     *
     * 客户端:
     *          主线程:接收终端输入   将终端的输入发送给服务器端
     *          子线程:接收服务器端发送过来的数据
     * 服务器端:
     *          主线程:接收终端输入   将终端的输入发送给客户端
     *           子线程:接收客户端发送过来的数据
     */
    
    class Cilent{
        public static void main(String[] args) throws IOException {
            //链接服务器端 获取socket
            Socket socket = new Socket("10.129.49.204",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 {
                // 关闭输入输出流
                // 关闭对应的socket链接
                try {
                    if (br != null) {
                        br.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    

    5.实现群聊

    • 使用ArrayList 保存每一个连接到的客户端,并且通过循环依次将信息发送给每一个客户端。
    class Server{
        // 保存每一个链接过来的对象
        public static ArrayList<Socket> sockets = new ArrayList<>();
        public static void main(String[] args) throws IOException {
            ServerSocket ss = new ServerSocket(8888);
    
            //不停地等待客户端来连接
            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){
                    // 群发消息
                    // 遍历Server维护的数组
                    for (Socket socket:Server.sockets){
                        // 想socket对应的客户端发送信息
                        PrintStream s = new PrintStream(socket.getOutputStream());
                        s.println(line);
                    }
                }
            } catch (IOException e) {
                System.out.println("网络异常  请重新登录");
                System.exit(-1);
            }finally {
                // 关闭输入输出流
                // 关闭对应的socket链接
                try {
                    if (br != null) {
                        br.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    class Cilent{
        public static void main(String[] args) throws IOException {
            //链接服务器端 获取socket
            Socket socket = new Socket("10.129.49.204",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();
                }
            }
        }
    }
    
    

    心得体会

      关于客户端和服务器端的操作,刚开始对于输入输出有点绕,不过多写了几遍之后,就更清楚了 ,类似于模板。同时又将多线程的知识融入进来,对知识的理解也更加深刻了。

    相关文章

      网友评论

          本文标题:Java之Socket网络编程

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