Java网络通信

本文深入探讨Java网络编程,包括IP、端口和传输协议的基础知识,详细讲解了UDP和TCP通信的原理及实现。通过实例展示了如何进行UDP数据包发送和接收,以及TCP的Socket编程,涵盖了多线程、文件传输和多客户端连接等高级话题。
摘要由CSDN通过智能技术生成

背景知识

  • 网络编程的三要素:

    IP地址:InetAddress: 网络中设备的标识,不易记忆,可用主机名;
    端口号:用于标识进程的逻辑地址,不同进程的标识 ;
    传输协议:通讯的规则常见协议:TCP,UDP

  • UDP协议与TCP协议的区别:

UDP——发短信

将数据源和目的封装成数据包中,不需要建立连接;
每个数据报的大小在限制在64k;
因无连接,是不可靠协议;
不需要建立连接,速度快

TCP——打电话、视频

建立连接,形成传输数据的通道;
在连接中进行大数据量传输;
需要连接所以是可靠协议;
必须建立连接,效率会稍低;

网络编程(Socket编程)

1、Socket是什么

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口;
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议;
应用程序可以通过套接字发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作;套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信;

2、Socket原理

网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字,即就是Socket=IP+端口号;
通信的两端都有Socket、网络通信其实就是Socket间的通信、数据在两个Socket间通过IO传输;

3、Java如何进行网络编程

针对不同协议的Socket,Java给我们提供了相应的Socket;
UDP协议使用的Socket,Java提供了DatagramSocket类来描述;TCP协议使用的Socket,Java使用了Socket类来描述;

动态获取IP、主机名

在Java中,使用InetAddress类来描述IP,它的子类有:Inet4Address、Inet6Address,我们可以直接使用父类;

常用方法:
在这里插入图片描述

获取本机的主机名和IP

package org.westos.test;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class test3 {
   
    public static void main(String[] args) {
   
        //可以传递主机名或IP地址获取InetAddress对象
        InetAddress ip1 = null;
        try {
   
            ip1 = InetAddress.getByName("LAPTOP-B7JPDQ6Q");
            System.out.println(ip1.getHostName());//LAPTOP-B7JPDQ6Q
            System.out.println(ip1.getHostAddress());//192.168.1.101
            System.out.println("===================");
            InetAddress ip2 = InetAddress.getByName("192.168.1.101");
            System.out.println(ip2.getHostName());//LAPTOP-B7JPDQ6Q
            System.out.println(ip2.getHostAddress());//192.168.1.101

            System.out.println(ip1==ip2);//false
        } catch (UnknownHostException e) {
   
            e.printStackTrace();
        }
    }
}

UDP通信

UDP协议传输数据

1、UDP协议发送数据 DatagramSocket类: 此类表示用来发送和接收数据报包的套接字,启用 UDP 广播发送;
在这里插入图片描述构造方法:
在这里插入图片描述

常用方法:

public void send(DatagramPacket p) throws IOException
从此套接字发送数据报包;
public void receive(DatagramPacket p) throws IOException
从此套接字接收数据报包。

注意:这里的receive()是一个阻塞式方法,如果没有收到数据,他就会一直阻塞在那里,不往下执行;

2、DatagramPacket类: 此类表示数据报包;
在这里插入图片描述构造方法:
在这里插入图片描述
成员方法:
在这里插入图片描述
UDP发送数据步骤:

通讯客户端对象DatagramSocket
创建数据报包 DatagramPacket
发送数据
释放资源

客户端:代码里面,我们使用无参构造创建了Socket对象,然后将要发送的IP以及端口号都放在数据报包里面发送出去;

因为UDP协议是一个不可靠协议,就好比你发送信息,有可能你要发送的那个手机号已经为空或者停机了,但是你不需要关心这些,你只负责将信息发送出去;代码里面我们将数据发送出去,但是没有服务端接收,他就会被自动丢弃,而不会返回任何错误;

package org.westos.test;

import java.net.*;

public class test1 {
   
    // DatagramSocket 此类表示用来发送和接收数据报包的套接字。

     /*   DatagramSocket()
        构造数据报套接字并将其绑定到本地主机上任何可用的端口。
         void send (DatagramPacket p)
        从此套接字发送数据报包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。


	UDP 发短信
		将数据源和目的封装成数据包中,不需要建立连接;
		每个数据报的大小在限制在64k;
		因无连接,是不可靠协议;
		不需要建立连接,速度快
        */
     public static void main(String[] args) throws SocketException {
   
         //
         //1.创建客户端的Soket
         DatagramSocket datagramSocket = new DatagramSocket();
         //2.发送数据  DatagramPacket 此类表示数据报包 数据报包用来实现无连接包投递服务。
         byte[] bytes = "你好:服务端".getBytes();
         try {
   
             DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.1.101"), 8888);
             datagramSocket.send(datagramPacket);
             //3.释放资源
             datagramSocket.close();
         } catch (Exception e) {
   
             e.printStackTrace();
         }
     }

}

UDP协议接收数据

我们一般是客户端发送数据给服务端,服务端处理数据,那服务端怎么接受数据呢?
步骤:
创建UDP通讯协议服务器端对象(DatagramSocket) 注意要用有参数构造,指定端口号;
创建数据报包,作用用来接收数据;
接收数据 receive(数据包对象) ;
解析数据报包,拿出数据;
释放资源;

服务端:

package org.westos.test;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

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

        try {
   
            // DatagramSocket
            //1.创建服务端的Socket 并暴露一个端口号 0-65535 0-1023系统端口。
            DatagramSocket datagramSocket = new DatagramSocket(8888);
            //void receive(DatagramPacket p)  从此套接字接收数据报包。
            System.out.println("服务器已经开启....");
        /*DatagramPacket( byte[] buf, int length)
        构造 DatagramPacket,用来接收长度为 length 的数据包。*/
            byte[] bytes = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            //此方法在接收到数据报前一直阻塞。
            datagramSocket.receive(datagramPacket);

            //取出数据报包中的数据
            byte[] data = datagramPacket.getData();
            String address = datagramPacket.getAddress().getHostAddress();
            int length = datagramPacket.getLength();
            String s = new String(data,0, length);
            System.out.println("IP: "+address+"发送msg: "+s);
            //释放资源
            datagramSocket.close();
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }

}

先开启服务端,客户端再发送数据:执行结果如下:
在这里插入图片描述

UDP通信之键盘录入数据的通信

客户端发送数据 发送给服务端,要输入服务端的端口号与IP:

package org.westos.test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class test1 {
   
     public static void main(String[] args) throws SocketException {
   
         //1.创建客户端的Soket
         DatagramSocket datagramSocket = new DatagramSocket();
         try {
   
             while (true) {
   

                 //2.发送数据  DatagramPacket 此类表示数据报包 数据报包用来实现无连接包投递服务。
                 //通过键盘录入数据不断发送,服务端不断接收
                 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                 System.out.println("请输入要发送的数据: ");

                 String s = reader.readLine();
                 byte[] bytes = s.getBytes();
                 DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("LAPTOP-B7JPDQ6Q"), 9999);
                 datagramSocket.send(datagramPacket);

                 if ("886".equals(s)){
   break;}
             }

             //3.释放资源
             datagramSocket.close();

         } catch (Exception e) {
   
             e.printStackTrace();
         }
     }

}

服务端接收数据 暴露自己的端口号:

package org.westos.test;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

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

        try {
   
            //创建服务端socket
            DatagramSocket datagramSocket = new DatagramSocket(9999);
               System.out.println("服务端开始接收数据: ");
          while (true){
   

              //接收数据  使用1024字节的数组接收数据 放入datagramPacket的数据包中
              byte[] bytes = new byte[1024];
              DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
          
              datagramSocket.receive(datagramPacket);
              //查看数据
              byte[] data = datagramPacket.getData();
              int length = datagramPacket.getLength();
              String hostAddress = datagramPacket.getAddress().getHostAddress();
              String s = new String(data, 0, length);
              System.out.println("IP: "+hostAddress+"发送msg: "+s);

              if ("886".equals(s)){
   break;}

          }
          //关闭服务端,一般来说不关闭
          datagramSocket.close();
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }

}

在这里插入图片描述
在这里插入图片描述

客户端与服务端放入线程中开启

模拟两台计算机之间的通信

主线程发数据,子线程收数据

两台计算机的端口号一样,IP不一样,这样才可以通信。如果都通过端口9999来发送和接收数据:

发送数据:输入对方IP与端口号;
接收数据:暴露自己的端口号

例如:计算机A,B的端口号设置为9999
计算机A给计算机B发送数据,此时要输入B的的端口号指定为9999,计算机A接收计算机B的数据,此时暴露自己的端口指定为9999

在这里插入图片描述

如果在同一台计算机上测试,模拟AB的端口要不同,否则会端口占用。
下面代码设置A端口为8888,B端口为9999

B开启子线程等待A的数据,主线程发送数据886;A开启子线程接收B的数据886,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值