• Socket网络编程


    网络编程基础知识

    1. InetAddress:用于标识网络上的硬件资源
    2. URL:统一资源定位符 通过URL可以直接读取或写入网络上的数据
    3. Sockets:使用TCP协议实现网络通信的Socket相关的类。
    4. Datagram:使用UDP协议,讲数据保存在数据包中,通过网络进行通信。

    网络中相关的API的应用

    InetAddress类

    • InetAddress类用于表示网络上的硬件资源,表示互联网协议(IP)地址。
      需要注意的是,InetAddress没有构造方法,但是有很多静态方法
    public class Main {
    
        public static void main(String[] args) throws UnknownHostException {
            //获取本机InetAddress实例
            InetAddress address =InetAddress.getLocalHost();
            System.out.println("计算机名称 "+ address.getHostName());
            System.out.println("计算机地址 "+ address.getHostAddress());
            byte[] bytes = address.getAddress();//获取字节数组形式的IP
            System.out.println("获取字节数组形式的IP: " + Arrays.toString(bytes));
            System.out.println(address);//直接输出address对象
    
            //根据主机名称获取InetAddress实例
    //        InetAddress address2 = InetAddress.getByName("DESKTOP-JT605LG");
            //根据主机IP地址获取InetAddress实例
            InetAddress address2 = InetAddress.getByName("172.22.43.6");
            System.out.println("计算机名称 "+ address.getHostName());
            System.out.println("计算机地址 "+ address.getHostAddress());
    
        }
    
    }
    

    java中的URL的应用

    1. URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址
    2. URL由两部分组成:协议名称和资源名称,中间用冒号隔开。
    3. 在java.net包中,提供了URL类来表示URL。

      • 实例
    import java.net.MalformedURLException;
    
    import java.net.URL;
    
    /*
        URL常用方法
     */
    public class Main {
    
        public static void main(String[] args) {
    
            try {
                //创建一个URL实例
                URL imooc = new URL("http://www.imooc.com");
                //?后面表示参数,#后面表示锚点
                URL shen = new URL(imooc,"/index.html?username=tom#test");
                System.out.println("协议: "+shen.getProtocol());
                System.out.println("主机: "+shen.getHost());
                //如果为指定端口号,则使用人的端口号,此时getPort方法返回值为-1
                System.out.println("端口: "+shen.getPort());
                System.out.println("文件路径: "+shen.getPath());
                System.out.println("文件名称: "+shen.getFile());
                System.out.println("相对路径: "+shen.getRef());
                System.out.println("查询字符串: "+shen.getQuery());
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    
    • 使用URL读取页面内容
    public class Main {
    
        public static void main(String[] args) {
            try {
                //创建一个URL实例
                URL url = new URL("http://www.baidu.com");
                //通过URL的openStream方法获取URL对象所表示资源的字节输入流
                InputStream is = url.openStream();
                //将字节输入流转化为字符输入流
                InputStreamReader isr =new InputStreamReader(is,"UTF-8");
                //为字符输入流添加缓冲,增加读取效率
                BufferedReader dr = new BufferedReader(isr);
                String data = dr.readLine();//读取数据
                while(data!=null){//循环读取数据
                    System.out.println(data);//输出数据
                    data = dr.readLine();//在此读取数据
                }
                dr.close();
                isr.close();
                is.close();
    
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    通过Socket实现TCP编程

    TCP协议是面向连接、可靠的,有序的、以字节流的方式发送数据,基于TCP协议实现网络通信的类
    - 客户端的Socket类
    - 服务器端的ServerSocket类
    这里写图片描述

    Socket通信实现步骤

    1. 创建serverSocket和Socket
    2. 打开连接到Socket的输入输出流
    3. 按照协议对Socket进行读写操作
    4. 关闭输入输出流、关闭Socket

    服务器端

    1. 创建ServerSocket对象,绑定侦听端口
    2. 通过accept()方法监听客户端请求
    3. 连接建立后,通过输入流读取客户端发送的请求信息
    4. 通过输出流向客户端发送相应信息
    5. 关闭相应资源

    客户端

    1. 创建Socket对象,指明需要连接的服务器的地址和端口
    2. 连接建立后,通过输出流向服务器端发送请求信息
    3. 通过输入流获取服务器响应的信息
    4. 关闭相关资源

    综合训练

    单线程通信

    • 服务器端
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server  {
    
        public static void main(String[] args) {
            try {
                //创建ServerSocket
                ServerSocket serverSocket = new ServerSocket(8636);
                //侦听
                System.out.println("***服务器即将启动,等待客户端连接***");
                Socket socket = serverSocket.accept();
                //获取一个输入流,并读取客户端信息
                InputStream is = socket.getInputStream();//字节输入流
                InputStreamReader isr = new InputStreamReader(is);//将字节流包装为字符流
                BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
                String info = null;
                while((info=br.readLine()) !=null){//循环读取
                    System.out.println("我是服务器,客户端说:"+info );
                }
                socket.shutdownInput();//关闭输入流
    
                //响应客户端
                OutputStream os =socket.getOutputStream();//获取字节输出流,向客户端输出信息
                PrintWriter pw = new PrintWriter(os);//将字节输出流包装为打印流
                pw.write("欢迎您!");//向客户端发送信息
                pw.flush();//刷新缓存
                socket.shutdownOutput();//关闭输出流
    
                //关闭相应资源
                pw.close();
                os.close();
                br.close();
                isr.close();
                is.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    
    • 客户端
    import java.io.*;
    import java.net.Socket;
    
    /*
    客户端
     */
    public class Client {
        public static void main(String[] args){
            try {
                //创建一个Socket,用了和服务器端进行通信
                Socket socket = new Socket("127.0.0.1",8636);
                //获取输出流,向服务器输出信息
                OutputStream os = socket.getOutputStream();//字节输出流
                PrintWriter pw = new PrintWriter(os);//将输入流包装为打印流
                pw.write("用户名:admin;密码:123");
                pw.flush();//刷新缓存,向服务器端输出信息
                socket.shutdownOutput();//关闭输出流
    
                //接受服务器的响应信息
                InputStream is = socket.getInputStream();//获取字节输入流
                System.out.println("我是字节输入流:"+is);
                InputStreamReader isr = new InputStreamReader(is);
                System.out.println("我是字符输出流:"+isr);
                BufferedReader br = new BufferedReader(isr);
                String info = null;
                while((info=br.readLine())!=null){
                    System.out.println("服务器响应我:"+info);
                }
    
                br.close();
                isr.close();
                is.close();
                //关闭其他资源
                pw.close();
                os.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    多线程

    应用多线程来实现服务器和多客户端之间的通信

    • 基本步骤

      1. 服务器端创建ServerSocket,循环调用accept()方法等待客户端连接
      2. 客户端客户端创建一个socket并请求和服务器端连接
      3. 服务器端接受客户端的请求,创建Socket与该客户端建立专线连接
      4. 建立连接的两个socket在一个单独的线程上对话
      5. 服务器继续等待新的连接
    • 服务器端:

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server  {
    
        public static void main(String[] args) {
            try {
                //创建ServerSocket
                ServerSocket serverSocket = new ServerSocket(8636);
                Socket socket=null;
                //用来记录客户端的数量
                int count =0;
                System.out.println("***服务器即将启动,等待客户端连接***");
                while(true){//循环侦听等待客户端的连接
                    //侦听
                    socket = serverSocket.accept();
                    //创建一个新的线程来与客户端进行通信
                    ServerThread serverThread = new ServerThread(socket);
                    serverThread.start();
    
                    count++;//统计客户端数量
                    System.out.println("客户端数量为:"+count);
                    System.out.println("当前客户端IP为:"+socket.getInetAddress().getHostAddress());//获得当前客户端的IP地址
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    
        }
    
    }
    
    • 线程:
    import java.io.*;
    import java.net.Socket;
    
    /*
    服务器端线程处理类
     */
    public class ServerThread extends Thread {
        //和本线程相关的Socket类
        Socket socket = null;
    
        public ServerThread(Socket socket){
            this.socket=socket;
        }
    
        //线程执行操作,来响应客户端的请求
        public void run(){
    
            InputStream is = null;//字节输入流
            InputStreamReader isr=null;
            BufferedReader br =null;
            PrintWriter pw = null;
            OutputStream os = null;
            try {
                //获取一个输入流,并读取客户端信息
                is = socket.getInputStream();
                isr = new InputStreamReader(is);//将字节流包装为字符流
                br = new BufferedReader(isr);//为输入流添加缓冲
                String info = null;
                while((info=br.readLine()) !=null){//循环读取
                    System.out.println("我是服务器,客户端说:"+info );
                }
                socket.shutdownInput();//关闭输入流
    
                //响应客户端
                os =socket.getOutputStream();//获取字节输出流,向客户端输出信息
                pw = new PrintWriter(os);//将字节输出流包装为打印流
                pw.write("欢迎您!");//向客户端发送信息
                pw.flush();//刷新缓存
                socket.shutdownOutput();//关闭输出流
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    //关闭相应资源
                    if(pw!=null)
                        pw.close();
                    if(os!=null)
                        os.close();
                    if(br!=null)
                        br.close();
                    if(isr!=null)
                        isr.close();
                    if(is!=null)
                        is.close();
                    if(socket!=null)
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 客户端
    import java.io.*;
    import java.net.Socket;
    
    /*
    客户端
     */
    public class Client {
        public static void main(String[] args){
            try {
                //创建一个Socket,用了和服务器端进行通信
                Socket socket = new Socket("127.0.0.1",8636);
                //获取输出流,向服务器输出信息
                OutputStream os = socket.getOutputStream();//字节输出流
                PrintWriter pw = new PrintWriter(os);//将输入流包装为打印流
                pw.write("用户名:admin;密码:123");
                pw.flush();//刷新缓存,向服务器端输出信息
                socket.shutdownOutput();//关闭输出流
    
                //接受服务器的响应信息
                InputStream is = socket.getInputStream();//获取字节输入流
                System.out.println("我是字节输入流:"+is);
                InputStreamReader isr = new InputStreamReader(is);
                System.out.println("我是字符输出流:"+isr);
                BufferedReader br = new BufferedReader(isr);
                String info = null;
                while((info=br.readLine())!=null){
                    System.out.println("服务器响应我:"+info);
                }
    
                br.close();
                isr.close();
                is.close();
                //关闭其他资源
                pw.close();
                os.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    通过Socket实现UDP编程

    UDP协议(用户数据宝协议)是无连接、不可靠的、无序的(速度相对较快),UDP协议以数据包作为数据传输的载体,进行数据传输室,首先需要将要传输的数据定义成数据包(Datagram),在数据保重知名数据所要达到的Socket(主机地址和端口),然后再讲数据包发送出去。
    需要是使用到的类

    • DatagramPacket:表示数据包(用来表示UDP通信中的数据单元)
    • DatagramSocket:进行端到端通信的类

    服务器端实现步骤

    1. 创建DatagramSocket,指定端口号
    2. 创建DatagramPacket
    3. 接受客户端发送的数据信息
    4. 读取数据
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    
    /*
     *基于UDP的用户登录
     */
    public class Server {
        public static void main(String args[]) throws IOException {
            //创建DatagramSocket,指定端口
            DatagramSocket socket = new DatagramSocket(8800);
            //创建数据报,用于接受客户端发送的数据
            byte[] data = new byte[1024];//创建字节数组,指定字节数组长度
            DatagramPacket packet = new DatagramPacket(data,1024);
            //接受客户端发送的数据
            System.out.println("***服务器以运行,正在接受客户端信息***");
            socket.receive(packet);//此方法在接收到数据报之前会一直处于阻塞状态
            //读取客户端发送过来的数据
            String info = new String(data,0,packet.getLength());
            System.out.println("我是服务器,客户端说:"+info);
            System.out.println("当前客户端IP为:"+packet.getAddress());
            System.out.println("当前客户端使用端口为:"+packet.getPort());
    
            /**
             * 向客户端响应数据
             */
            //定义数据报内容,客户端IP,以及客户端端口号
            byte[] data2 = "欢迎您!".getBytes();
            InetAddress address = packet.getAddress();
            //创建数据报
            DatagramPacket packe2 = new DatagramPacket(data2,data2.length,address,packet.getPort());
            //响应客户端
            socket.send(packe2);
            //关闭相应资源
            socket.close();
        }
    }
    

    客户端实现步骤

    1. 定义发送信息
    2. 创建DatagramPacket, 包含将要发送的信息
    3. 创建DatagramSocket
    4. 发送数据
    import java.io.IOException;
    import java.net.*;
    
    
    /*
    UDP客户端实现
     */
    public class Client {
        public static void main(String args[]) throws IOException {
            /**
             * 向服务器端发送数据
             */
            //定义服务器地址,端口号,数据
            byte[] data = "用户名:admin;密码:123".getBytes();
            InetAddress address = InetAddress.getByName("127.0.0.1");
            //创建数据报,包含发送的信息
            DatagramPacket packet = new DatagramPacket(data,data.length,address,8800);
            //创建DatagramSocket对象
            DatagramSocket socket = new DatagramSocket();
            //使用DatagramSocket向服务器发送信息
            socket.send(packet);
    
            /**
             * 响应服务器端数据
             */
            //创建数据报,用于接受数据
            byte[] data2 = new byte[1024];
            DatagramPacket packet2 = new DatagramPacket(data2,data2.length);
            socket.receive(packet2);
            String fuwuqi = new String(data2,0,data2.length);
            System.out.println("我是客户端,服务器端说:"+fuwuqi);
            socket.close();
        }
    }
    

    Socket总结

    终点

    1. Socket通信原理
    2. 基于TCP的Socket通信

    经验和技巧

    1. 多线程的优先级
    2. 是否关闭输出流和输入流
    3. 使用TCP通信传输对象
    4. Socket编程传递文件
  • 相关阅读:
    url
    松弛时间
    Linux下为当前用户添加 PYTHONPATH 环境变量
    ElasticSearch集群的安装(windows)
    软件开发安全
    java,判断手机设备跟adb建立连接
    question
    氚云后台代码小栗子,流程表单新增完成反写源单状态
    November Challenge 2020 Division 1
    February Challenge 2021 Division 1 选做
  • 原文地址:https://www.cnblogs.com/lanaiwanqi/p/10445666.html
Copyright © 2020-2023  润新知