心湖维基

Java网络编程

概述

概述:网络通信协议下,不同计算机上运行的程序,可以进行数据传输

例如,A电脑中的飞秋,发送消息给B电脑中的飞秋,需要哪些条件才能发送嗯?

IP地址

  • 设备在网络中的地址,是唯一的标识。

端口

  • 应用程序在设备中唯一的标识。

协议

  • 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。

IP

ip:全称为:互联网协议地址,也称IP地址,是分配给上网设备的数字标签,常见的IP分类为:ipv4和ipv6

  • IPv4: 是网际协议开发过程中的第四个修订版本,也是此协议第一个被广泛部署的版本。IPv4是互联网的核心,也是使用最广泛的网际协议版本,其后继版本为IPv6,直到2011年,IANA IPv4位址完全用尽时,IPv6仍处在部署的初期。

  • IPv6:由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍 [1] 。 互联网数字分配机构(IANA)在2016年已向国际互联网工程任务组(IETF)提出建议,要求新制定的国际互联网标准只支持IPv6,不再兼容IPv4。

具体可以通过百度百科了解。

常用命令:

  • ipconfig:查看本机IP
  • ping IP地址:检查网络是否连通

我们ping一下博客地址,其中47.106.67.159就是我服务器电脑的ip了。可以检测当前电脑与服务器之间是否畅通,同时确定服务器的IP。

特殊IP地址:

  • 127.0.0.1:回送地址也称本地回环地址,可以代表本机的IP地址,一般是用来做测试使用。

InetAddress

为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress供我们使用

InetAddress:此类表示Internet协议(IP)地址

具体查看JDK的官方API文档

端口

端口:要用程序在设备中的唯一标识

端口号:用两个字节表示的数据,它的取值范围是0~65535,其中0~1023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号

注意:一个端口号只能被一个应用程序使用。

协议

协议:计算机网络中,连接和通信的规则被称为网络通信协议

UDP协议

  • UDP是面向无连接通信协议。速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。
  • 不管你有没有建立连接,他都会发送出去。
  • 常用于:传递音频、数据、普通数据等

TCP协议

  • TCP协议是面向连接的通信协议
  • 速度慢,没有大小限制,数据安全

总结

网络编程:就是让两台计算机进行数据交互

网络编程三要素

  • IP:设备在网络中唯一的标识
  • 端口号:应用程序在设备中唯一的标识
  • 协议:数据在传输过程中遵循的规则

UDP通信程序

UDP发送数据:

步骤:

  • 创建发送端的DatagramSocket对象
  • 创建数据,并把数据打包进箱子(DatagramPacket)
  • 调用DatagramSocket对象的方法发送数据
  • 释放资源

代码示例。

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        //设置要传输的数据,并转化为byte类型,不能直接穿字符串
        String s = "你家孩子被录取了";
        byte[] bytes = s.getBytes();
        //创建主机且命名为localhost
        InetAddress address = InetAddress.getByName("localhost");
        //设置端口
        int port = 1000;
        //保存进箱子
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);

        socket.send(packet);
        socket.close();
    }
}

运行结果为空白,我们没有设置接收端,UDP协议只管发,收不收得到都不管。

UDP接收数据

步骤:

  • 创建接收端的DatagramSocket对象
  • 创建一个箱子,用于接收数据
  • 调用DatagramSocket的方法接收数据并将数据放进箱子中保存
  • 解析数据,在控制台显示
  • 释放资源
public class ServeDemo {
    public static void main(String[] args) throws IOException {
        //表示从1000端口接受数据
        DatagramSocket socket = new DatagramSocket(1000);

        //给箱子设置一个byte数组进行接收
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        socket.receive(packet);
        //在控制台打印数据
        System.out.println(new String(bytes));

        //我们也可以通过getData()方法将箱子里的数据重新拿出,一般不需要
        byte[] data = packet.getData();
        System.out.println(new String(data));

        //记得释放资源
        socket.close();
    }
}

我们运行起来,发现程序正在运行,但是没有打印出任何东西。

这很正常,因为我们并没有发送数据给它呀,这时我们保持接收端不动,去运行前面已经写好的发送端,他们端口都是1000。

我们看到效果已经出现了!

  • 如果你先运行了发送端,它就已经把数据发送出去了,你此时再运行接收端就没有效果了。

  • 如果接收端启动之后,没有收到数据,那么它就会死等(阻塞)。也就是它会运行到示例代码中的第9行就等在了那里。

  • 在接收数据的时候,需要调用一个getLength方法,表示接收到了多少字节。这里我们使用了1024个字节去接收数据,所以导致我们接收到数据后,后面带了很多空格,具体看下图。所以我们在打印输出中传入长度即可。

System.out.println(new String(bytes,0,packet.getLength()));

UDP通信程序练习

需求:

  • UDP发送数据:数据来自键盘录入,直到输入的数据是886,发送数据结束。
  • UPD接收数据:因为接收端不知道发送端什么时候停止发送,所以我们采用死循环接收。
public class Serve {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(996);
        while (true) {
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
            socket.receive(packet);
            System.out.println(new String(bytes, 0, packet.getLength()));
        }
    }
}
public class Client {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        while (true) {
            String s = sc.nextLine();
            if ("886".equals(s)){
                break;
            }
            byte[] bytes = s.getBytes();
            InetAddress address = InetAddress.getByName("127.0.0.1");
            int port = 996;
            DatagramPacket packet = new DatagramPacket(bytes,bytes.length,address,port);
            socket.send(packet);
        }
        socket.close();
    }
}

UDP三种通信方式

  • 单播,一对一
  • 组播,一对多
  • 广播,一对所有

UDP通信组播代码实现

组播地址:224.0.0.0~239.255.255.255

其中224.0.0.0~224.0.0.255为预留的组播地址

组播的发送端跟单播类似,也就是跟我们已经演示过的代码类似。但是在单播中,我们是发给指定IP的电脑,在组播中,是发给组播地址。

我们可以看到下面的代码中,我们开头创建了MulticastSocket对象并传入了端口,后面再加入组IP接收数据。这就是组播的接收端示例代码:

public class Serve2 {
    public static void main(String[] args) throws IOException {
        MulticastSocket multicastSocket = new MulticastSocket(10000);
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);

        //把当前计算机绑定一个组播地址,表示添加到这一组中
        //注意,这里要跟发送端设置的IP一样
        multicastSocket.joinGroup(InetAddress.getByName("224.0.1.0"));
        multicastSocket.receive(packet);
        System.out.println(new String(bytes,0,packet.getLength()));
    }
}

发送端:

public class Client2 {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        String s = "我是乐心湖啊";
        byte[] bytes = s.getBytes();
        //设置IP
        InetAddress address = InetAddress.getByName("224.0.1.0");
        int port = 10000;
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
        socket.send(packet);
        socket.close();
    }

测试,只要你的小伙伴都设置了这个IP和端口(即使用了示例中的接收端),你运行发送端就可以发送 “我是乐心湖啊” 给他们了。

UDP通信广播代码实现

广播地址:255.255.255.255 (必须)

接收端跟单播没有两样。

public class Serve3 {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(10000);
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        socket.receive(packet);
        System.out.println(new String(bytes, 0, packet.getLength()));
        socket.close();
    }
}
public class Client3 {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        String s = "是广播哦";
        byte[] bytes = s.getBytes();
        //设置IP
        InetAddress address = InetAddress.getByName("255.255.255.255");
        int port = 10000;
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
        socket.send(packet);
        socket.close();
    }
}

TCP通信程序

原理:

  • TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
  • 通信之前必须要建立连接
  • 通过Socket产生IO流来进行网络通信

TCP发送数据:

步骤:

  1. 创建客户端的Socket对象与指定服务端连接 , Socket(String host,int port)
  2. 获取输出流,写数据 OutputStream getOutputStream()
  3. 释放资源,void close()

此时运行客户端必然报错,因为我们没有写服务端,而TCP协议通信之前必须要建立连接

public class Client4 {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 996);
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,leixnhu".getBytes());
        outputStream.close();
        socket.close();
    }
}

TCP接收数据

步骤:

  1. 创建服务端的Socket对象(ServerSocket) ServerSocket(int port)
  2. 监听客户端连接,返回一个Socket对象 Socket.accept()
  3. 获取输入流,读数据,并把数据显示在控制台上 InputSteam getInputStream()
  4. 释放资源 void close()
public class Serve4 {
    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(996);
        Socket accept = socket.accept();
        InputStream inputStream = accept.getInputStream();
        int a;
        while ((a = inputStream.read())!=-1){
            System.out.print((char) a);
        }
        inputStream.close();
        socket.close();
    }
}

注意:

  • accept方法是阻塞的,为了等待客户端连接
  • 客户端创建对象连接服务器,此时是通过三次握手协议保证跟服务器之间的连接。
  • 针对客户端来讲,是往外写的,所以是输出流
  • 针对服务器来讲,是往里读的,所以是输入流
  • read方法也是阻塞的
  • 在关流的时候,还多了一个往服务器写结束标记的动作
  • 最后一步断开连接,通过四次挥手协议保证连接终止
Copyright © 2020 乐心湖 Hosted By 云开发