栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java中网络编程的相关知识

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java中网络编程的相关知识

目录
  • 一、InetAddress和InetSocketAddress
  • 二、套接字(Socket/DatagramSocket)
    • 1、基于TCP的网络编程
    • 2、基于UDP的网络编程

一、InetAddress和InetSocketAddress

InetAddress:Java中封装IP的一个类;
InetSocketAddress:封装IP,端口号

		//InetAddress ia = new InetAddress();   //不能直接创建对象,因为InetAddress()被default修饰
        InetAddress ia1 = InetAddress.getByName("localhost");    // 本机ip/localhost/127.0.0.1均代指本机ip地址
        System.out.println(ia1);

        InetAddress ia2 = InetAddress.getByName("www.baidu.com");//封装域名
        System.out.println(ia2);

        System.out.println(ia2.getHostName());  //获取域名
        System.out.println(ia2.getHostAddress());   //获取ip地址


        InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 8080);
        System.out.println(isa);
        System.out.println(isa.getHostName());
        System.out.println(isa.getPort());
        InetAddress ia = isa.getAddress();
        System.out.println(ia.getHostName());
        System.out.println(ia.getHostAddress());

二、套接字(Socket/DatagramSocket)

TCP:
客户端:Socket      程序感觉的是输入/出流
服务器端:ServerSocket  程序感觉的是输入/出流
客户端和服务器端地位是不平等的,服务器端需要一直等待接收数据

UDP:
发送方:DatagramSocket  发送:数据包 DatagramPacket
接收方:DatagramSocket  接收:数据包 DatagramPacket
发送方和接收方地位是平等的


1、基于TCP的网络编程

(1)模拟客户端和服务器端双向通信

客户端(步骤):创建套接字,使用输出流向外发数据,使用输入流接收数据,关闭流和网络资源;
服务器(步骤):创建套接字,等待客户端发数据,使用输入流接收数据,使用输出流发送数据,关闭流和网络资源。

代码示例:

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

        //1.创建套接字,需指定服务器端ip和端口号
        Socket s = new Socket("127.0.0.1", 8888);

        //2.向外发送数据-->使用输出流
        OutputStream os = s.getOutputStream();              //利用OutputStream就可以向外发送数据了,但没有发送String的方法
        DataOutputStream dos = new DataOutputStream(os);    //因此,又套了一个处理流:DataOutputStream
        dos.writeUTF("你好,我是客户端!");

        //接收服务器发回的信息-->输入流
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        System.out.println("服务器发来的信息为:"+dis.readUTF());

        //3.关闭流,关闭网络资源
        dis.close();
        dos.close();
        s.close();
    }
}
public class ServerTest {
    public static void main(String[] args) throws IOException {
        //1.创建套接字,指定服务器的端口号
        ServerSocket ss = new ServerSocket(8888);

        //2.等待客户端发来信息
        Socket s = ss.accept(); //是一个阻塞方法:等待接收客户端的数据,接收到了就继续向下执行
                                //accept()返回是一个Socket,这个Socket就是客户端的Socket
                                //接收到这个Socket之后,客户端和服务器才真正产生连接,才可以通信

        //3.接收信息
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String str = dis.readUTF();
        System.out.println("客户端发来的数据为:"+str);

        //向客户端发信息-->输出流
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF("你好,我是服务器,我收到你的请求了!");

        //4.关闭流,关闭网络资源
        dos.close();
        dis.close();
        s.close();
        ss.close();
    }
}

(2)模拟用户登录

改进的要点:
1、将数据接收/发送改为对象流,用于接收/发送用户名和密码封装成的一个对象;
2、加入完整的处理异常方式(try-catch方式);

代码示例:
User:封装一个用户的用户名和密码

public class User implements Serializable {

    private String account;
    private String pwd;

    public User(String account, String pwd) {
        this.account = account;
        this.pwd = pwd;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

客户端:

public class ClientTest {
    public static void main(String[] args){

        Socket s = null;
        OutputStream os = null;
        ObjectOutputStream oos = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            s = new Socket("127.0.0.1", 8888);

            Scanner sc = new Scanner(System.in);
            System.out.println("请输入账户:");
            String account = sc.next();
            System.out.println("请输入密码:");
            String pwd = sc.next();

            User user = new User(account, pwd);

            os = s.getOutputStream();
            oos = new ObjectOutputStream(os);
            oos.writeObject(user);

            is = s.getInputStream();
            dis = new DataInputStream(is);
            System.out.println("服务器发来的信息为:"+dis.readUTF());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(dis != null)
                    dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(oos != null)
                    oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(s != null)
                    s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务器:

public class ServerTest {
    public static void main(String[] args){

        ServerSocket ss = null;
        Socket s = null;
        InputStream is = null;
        ObjectInputStream ois = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        try {
            ss = new ServerSocket(8888);

            s = ss.accept();

            is = s.getInputStream();
            ois = new ObjectInputStream(is);
            User user = (User)ois.readObject();

            os = s.getOutputStream();
            dos = new DataOutputStream(os);
            dos.writeUTF("登陆成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if(dos != null)
                    dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ois != null)
                    ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(s != null)
                    s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ss != null)
                    ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

(3)进一步改进

多线程接收用户请求:解决客户端程序结束,服务器端也跟着结束的问题,服务器应一直监听是否有客户端发送数据。

客户端和User类都不需要进行修改。
代码示例:
服务器:

public class ServerTest {
    public static void main(String[] args){
        ServerSocket ss = null;
        Socket s = null;

        int count = 0;  //记录请求的客户端数量

        try {
            ss = new ServerSocket(8888);
            while (true){   //服务器一直监听客户端是否发送数据
                s = ss.accept();
                //每次过来的客户端的请求,靠线程处理
                new Thread(new ServerThread(s)).start();
                System.out.println("当前是第"+(++count)+"个用户访问!对应的用户是:"+s.getInetAddress());
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

线程:

public class ServerThread implements Runnable{  //处理客户端的请求
    InputStream is = null;
    ObjectInputStream ois = null;
    OutputStream os = null;
    DataOutputStream dos = null;

    Socket s = null;
    public ServerThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            is = s.getInputStream();
            ois = new ObjectInputStream(is);
            User user = (User)ois.readObject();

            os = s.getOutputStream();
            dos = new DataOutputStream(os);
            dos.writeUTF("登陆成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if(dos != null)
                    dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ois != null)
                    ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2、基于UDP的网络编程

(1)模拟双向通信

发送端(步骤):准备套接字(指定发送方的端口号),准备数据包(需要转为byte[]数组),DatagramPacket(包含四个参数),回复,关闭资源;
接收端(步骤):准备套接字(指定接收端的端口号),准备数据包(用来接收对方传过来的数据包),DatagramPacket(接收对方的数据包填充到dp数据包中),取数据,回复,关闭资源。

发送端:

public class SendTest {
    public static void main(String[] args){
        System.out.println("学生上线了。");

        //1.准备套接字:指定发送方的端口号
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(8888);

            //2.准备数据包,需要转为byte[]数组
            Scanner sc = new Scanner(System.in);
            System.out.print("学生说:");
            String str = sc.next();
            byte[] b = str.getBytes();

            //3.DatagramPacket需要四个参数:传送的字节数组、字节数组的长度、接收方的ip、接收方的端口号
            DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName("localhost"), 9999);
            ds.send(dp);

            //回复
            byte[] b1= new byte[1024];
            DatagramPacket dp2 = new DatagramPacket(b1, b1.length);
            ds.receive(dp2);
            byte[] data = dp2.getData();
            String s = new String(data, 0, dp2.getLength());
            System.out.println("老师对我说:"+s);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭资源
            if(ds != null)
                ds.close();
        }
    }
}

接收端:

public class ReceiveTest {
    public static void main(String[] args){
        System.out.println("老师上线了。");

        //1.创建套接字:指定接收方的端口
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(9999);

            //2.有一个空的数据包,打算用来接收对方传过来的数据包
            byte[] b= new byte[1024];
            DatagramPacket dp = new DatagramPacket(b, b.length);

            //3.接收对方的数据包,然后填充到dp数据包中
            ds.receive(dp);

            //4.取数据
            byte[] data = dp.getData();
            String s = new String(data, 0, dp.getLength()); //数据包中的有效长度
            System.out.println("学生对我说:"+s);

            //回复
            Scanner sc = new Scanner(System.in);
            System.out.print("老师说:");
            String str = sc.next();
            byte[] b1 = str.getBytes();
            DatagramPacket dp2 = new DatagramPacket(b1, b1.length, InetAddress.getByName("localhost"), 8888);
            ds.send(dp2);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5.关闭资源
            if(ds != null)
                ds.close();
        }
    }
}

(2)进一步改进
上述代码中,发送方和接收方各发送一条数据即结束,为了实现完整的正常的通信(可以一直对话),做出如下改进。

1、对双方的发送和接收行为进行循环,使用while(true){…};
2、当发送端发送"byebye"为终止交互信号。

发送端:

public class SendTest {
    public static void main(String[] args){
        System.out.println("学生上线了。");

        //1.准备套接字:指定发送方的端口号
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(8888);

            while(true){
                //2.准备数据包,需要转为byte[]数组
                Scanner sc = new Scanner(System.in);
                System.out.print("学生说:");
                String str = sc.next();
                byte[] b = str.getBytes();

                //3.DatagramPacket需要四个参数:传送的字节数组、字节数组的长度、接收方的ip、接收方的端口号
                DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName("localhost"), 9999);
                ds.send(dp);

                if(str.equals("byebye")) {
                    System.out.println("学生下线。");
                    break;
                }

                //回复
                byte[] b1= new byte[1024];
                DatagramPacket dp2 = new DatagramPacket(b1, b1.length);
                ds.receive(dp2);
                byte[] data = dp2.getData();
                String s = new String(data, 0, dp2.getLength());
                System.out.println("老师对我说:"+s);
            }
            
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭资源
            if(ds != null)
                ds.close();
        }
    }
}

接收端:

public class ReceiveTest {
    public static void main(String[] args){
        System.out.println("老师上线了。");

        //1.创建套接字:指定接收方的端口
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(9999);

            while(true){
                //2.有一个空的数据包,打算用来接收对方传过来的数据包
                byte[] b= new byte[1024];
                DatagramPacket dp = new DatagramPacket(b, b.length);

                //3.接收对方的数据包,然后填充到dp数据包中
                ds.receive(dp);

                //4.取数据
                byte[] data = dp.getData();
                String s = new String(data, 0, dp.getLength()); //数据包中的有效长度
                System.out.println("学生对我说:"+s);

                if(s.equals("byebye")){
                    System.out.println("学生下线,老师也下线了。");
                    break;
                }

                //回复
                Scanner sc = new Scanner(System.in);
                System.out.print("老师说:");
                String str = sc.next();
                byte[] b1 = str.getBytes();
                DatagramPacket dp2 = new DatagramPacket(b1, b1.length, InetAddress.getByName("localhost"), 8888);
                ds.send(dp2);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5.关闭资源
            if(ds != null)
                ds.close();
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821721.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号