【Java网络编程】TCP通信(Socket 与 ServerSocket)和UDP通信的三种数据传输方式

目录

1、TCP通信

[1.1、Socket 和 ServerSocket](#1.1、Socket 和 ServerSocket)

1.3、TCP通信示例

2、UDP的三种通信(数据传输)方式

1、TCP通信

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象

通信之前要保证连接已经建立(注意TCP是一定要建立连接的)

TCP是通过Socket产生I0流来进行网络通信的,所以发送端和接收端的两个流的方向是不一样的,比如客户端和服务器进行通信(通信前要确保建立了连接),然后客户端向服务器发送了"你好帅",这一次发送数据的过程,它们流的方向是不一样的,针对客户端来说,它是往外发所以用的是输出流,而针对服务器来说,它是接收数据所以用的是输入流。

1.1、Socket 和 ServerSocket

socket可以使一个应用从网络中读取和写入数据,不同计算机上的两个应用可以通过连接发送和接受字节流,当发送消息时,你需要知道对方的ip和端口,在java中,socket指的是java.net.Socket类。

一旦成功创建一个Socket类的实例,可以用它来发送和接收字节流,发送时调用getOutputStream方法获取一个java.io.OutputStream对象,接收远程对象发送来的信息可以调用getInputStream方法来返回一个java.io.InputStream对象。
Socket类代表一个客户端套接字,即任何时候连接到一个远程服务器应用时构建所需的socket。现在,要实现一个服务器应用,需要不同的做法。服务器需随时待命,因为不知道客户端什么时候会发来请求,此时,我们需要使用ServerSocket,对应的是java.net.ServerSocket类。
  ServerSocket与Socket不同,ServerSocket是等待客户端的请求,一旦获得一个连接请求,就创建一个Socket示例来与客户端进行通信。

1.3、TCP通信示例

(1)写TCP通信的步骤:

客户端:

创建客户端的Socket对象(Socket)与指定服务端连接:Socket(string host,int port)--host为服务器ip地址,port为端口

获取输出流,写数据:OutputStream getoutputstream()

释放资源:void close()

服务器:

创建服务器端的Socket对象(ServerSocket):Serversocket(int port)

监听客户端连接,返回一个Socket对象:Socket accept()

获取输入流,读数据,并把数据显示在控制台:InputStream getInputStream()

释放资源:void close()

示例:

**提示:**在客户端创建了Socket对象的同时会去连接服务端,如果连接不上,代码会报错;用来通信的I0流可以关可不关,因为这个流是TCP连接通道里的流,关闭TCP连接通道时这个流自然就关了

客户端代码

java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        //TCP协议,发送数据
        // 1.创建Socket对象
        // 提示:在创建对象的同时会连接服务端,如果连接不上,代码会报错
        Socket socket = new Socket("127.0.0.1",10001);
        //2.可以从连接通道中获取输出流(OutputStream是引用型数据类型)
        OutputStream os = socket.getOutputStream();
        //写出数据
        //os.write("aaa".getBytes());
        os.write("你好aaa是吧".getBytes());
        //3.释放资源
        os.close();//这里的流可以关可不关,因为这个流是TCP连接通道里的流,关闭TCP连接通道时这个流自然就关了
        socket.close();
    }
}

服务器代码

java 复制代码
public class Server {
    public static void main(String[] args) throws IOException {
        //TCP协议,接收数据
        // 1.创建对象ServerSocket
        ServerSocket ss = new ServerSocket(10001);
        //2.监听客户端的链接
        Socket socket = ss.accept();
        //3.从连接通道中获取输入流读取数据
        InputStreamReader br = new InputStreamReader(socket.getInputStream());//这时候才能正确的读取到中文数据
        int b;
        while ((b = br.read()) != -1) {
            System.out.print((char) b);
        }
        //4.释放资源
        br.close();//这里的流可以关可不关,因为这个流是TCP连接通道里的流,关闭TCP连接通道时这个流自然就关了
        ss.close();
    }
}

先运行服务器,再运行客户端

结果结果

(2)客户端不断发送消息

客户端代码

java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        //客户端:多次发送数据
        //服务器:接收多次接收数据,并打印
        //1.创建Socket对象
        Socket socket = new Socket("127.0.0.1",10001);
        //2.可以从连接通道中获取输出流(OutputStream是引用型数据类型)
        OutputStream os = socket.getOutputStream();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("输入要发送的数据:");
            String str = sc.nextLine();
            if ("886".equals(str)) {
                break;
            }
            //写出数据
            os.write(str.getBytes());
        }
        //3.释放资源
        socket.close();
    }
}

服务器代码

java 复制代码
public class Server {
    public static void main(String[] args) throws IOException {
        //客户端:多次发送数据
        //服务器:接收多次接收数据,并打印
        // 1.创建对象ServerSocket
        ServerSocket ss = new ServerSocket(10001);
        //2.监听客户端的链接
        Socket socket = ss.accept();
        //3.从连接通道中获取输入流读取数据
        InputStreamReader br = new InputStreamReader(socket.getInputStream());
        int b;
        while ((b = br.read()) != -1) {
            System.out.print((char) b);
        }
        //4.释放资源
        ss.close();
    }
}

运行结果:客户端发送886后结束通信

(3)客户端和服务器互发互收消息

java 复制代码
//客户端代码
public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10001);
        OutputStream os = socket.getOutputStream();
        String str = "你看的到我发信息吗?";
        os.write(str.getBytes());
        //往服务器写出结束标记,shutdownOutput()是关闭输出流,如果不关闭,服务器那边的输入流就不会关闭,就会继续阻塞在读信息的过程中
        socket.shutdownOutput();

        InputStreamReader br = new InputStreamReader(socket.getInputStream());
        int b;
        while ((b = br.read()) != -1) {
            System.out.print((char) b);
        }
        socket.close();
    }
}



//服务器代码
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10001);
        Socket socket = ss.accept();
        InputStreamReader br = new InputStreamReader(socket.getInputStream());
        int b;
        while ((b = br.read()) != -1) {
            System.out.print((char) b);
        }
        socket.getOutputStream().write("是的,我看到了。".getBytes());//链式编程
        //写出结束标记,shutdownOutput()是关闭输出流
        socket.shutdownOutput();
        socket.close();
        ss.close();
    }
}

运行结果

服务器端:

客户端:

2、UDP的三种通信(数据传输)方式

Java网络编程中的UDP(User Datagram Protocol)通信编程支持单播、组播和广播这三种方式。

  • 单播(Unicast):单播是指将数据从一个发送者发送到一个接收者的传输方式。在UDP编程中,通过指定目标主机的IP地址和端口号,可以实现单播通信。
  • 组播(Multicast):组播是指将数据从一个发送者发送到一组特定的接收者的传输方式。在UDP编程中,可以使用Java的MulticastSocket类来支持组播通信。
  • 广播(Broadcast):广播是指将数据从一个发送者发送到网络中的所有设备的传输方式。在UDP编程中,可以通过指定广播地址(通常是特定的子网地址)来实现广播通信。
    **单播:**前面的发送接收数据的通信方式就是单播

**组播:**组播地址:224.0.0.0~239.255.255.255;其中224.0.0.0~224.0.0.255为预留的组播地址

**广播:**广播地址:255.255.255.255

UDP组播示例:

java 复制代码
//发送端代码
public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        //组播发送端代码
        // 创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket();
        String str = "你好,你好!";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("224.0.0.2");//这里设置的ip为组播地址
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length,address,port);
        //调用MulticastSocket发送数据方法发送数据
        ms.send(dp);
        //释放资源
        ms.close();
    }
}



//接收端代码
public class ReceiveMessageDemo1 {
    public static void main(String[] args) throws IOException {
        //1.创建MulticastSocket对象,并且设置端口为10000
        MulticastSocket ms = new MulticastSocket(10000);
        //2.将将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.2");
        ms.joinGroup(address);

        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
        //接收数据包
        ms.receive(dp);
        //3.解析数据包
        byte[] data = dp.getData();//获取数据包dp中的数据
        int len = dp.getLength();//获取这次收到了多少个字节的数据
        String str = new String(data,0,len);
        //因为字节数组data的长度是1024,太大了,所以要用到这次收到了多少个字节的数据个数len来决定把字节数组data中的多少数据转换成字符串
        String ip = dp.getAddress().getHostAddress();//ip
        String name = dp.getAddress().getHostName();//主机名

        System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + str);
        //释放资源
        ms.close();
    }
}

要想运行并验证这个示例,修要允许运行多个发送端,步骤如下:

完成这些操作后,多运行几个接收端就可以了

发送端运行结果

接收端1显示结果

接收端2显示结果

UDP广播示例:

发送端把目的主机的IP设置为:255.255.255.255,这就是广播了

java 复制代码
public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        /*
        按照下面的要求实现程序
        UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束
        UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
         */
        //1.创建对象DatagramSocket的对象
        DatagramSocket ds = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你想说的话:");
            String str = sc.next();
            byte[] bytes = str.getBytes();
            //InetAddress address = InetAddress.getByName("127.0.0.1");//设置目标主机的IP为:127.0.0.1,这是单播方式
            InetAddress address = InetAddress.getByName("255.255.255.255");//设置目标主机的IP为:255.255.255.255,这是广播方式
            int port = 10086;//设发送到目标主机的10086端口
            //2.打包数据
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
            //3.发送数据
            ds.send(dp);
            if ("886".equals(str)) {//如果输入的数据是886,发送数据结束
                break;
            }
        }
        //4.释放资源
        ds.close();
    }
}

推荐:

【Java网络编程】网络编程概述、UDP通信(DatagramPacket 与 DatagramSocket)-CSDN博客https://blog.csdn.net/m0_65277261/article/details/137928825?spm=1001.2014.3001.5501

【java多线程】线程池 ThreadPoolExecutor类和Executors工厂类以及线程池的最优大小_threadpool 线程池工厂类-CSDN博客https://blog.csdn.net/m0_65277261/article/details/137673188?spm=1001.2014.3001.5501

【Spring】依赖注入(DI)时常用的注解@Autowired和@Value-CSDN博客https://blog.csdn.net/m0_65277261/article/details/137784706?spm=1001.2014.3001.5501

相关推荐
好奇的菜鸟1 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
tan180°1 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
巴伦是只猫1 小时前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
DuelCode2 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社22 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
why技术2 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理2 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码2 小时前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot
YuTaoShao3 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
ai小鬼头3 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github