Socket通信讲解及C/S结构实现UDP协议通信

news/2024/5/18 15:29:32 标签: udp, 网络, java, socket, C/S

Sokcet


一. Socket套接字

1.1 什么是套接字


所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制,是支持TCP/IP协议的路通信的基本操作单元

1.2 套接字主要类型


TCP流套接字

流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP协议。即传输层TCP通信满足如下条件:

  • 有连接可靠传输
  • 面向字节流,即可以利用IO流分开进行多次收发
  • 有接受的缓冲区和传输缓冲区,没有传输大小限制

UDP数据报套接字

数据报套接字提供一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。即传输层UDP通信满足如下条件:

  • 无连接不可靠传输
  • 面向数据报,即发送的内容必须一次性收发
  • 有接受的缓冲区,但没有发送的缓冲区,一次性最多传输64k大小

原始套接字

原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接。

二. UDP常见API

2.1 DatagramSocket

DatagramSocket 用来构造传输UDP协议的类,表格介绍如何构造类对象

构造方法含义
DatagramSocket(int port)创建一个UDP数据报套接字Socket,绑定到指定的端口

表格介绍DatagramSocket 常用的传输和接受数据包方法

方法含义
void receive(DatagramPacket p)套接字接收数据报
void send(DatagramPacket p)套接字发送数据报包
void close()关闭套接字

2.2 DatagramPacket


DatagramPacket 用来构造传输数据包的类,表格介绍如何构造类对象

构造方法含义
DatagramPacket(byte[] buffer, int length)构造数据包接受数据,parm1:接受的内容,parm2:指定接受的长度
DatagramPacket(byte[] buffer, int offset, int length,SocketAddress address)构造数据包发送数据,parm1:发送内容,parm2:从字符组下标哪里开始发送,parm3:发送的长度、parm4:封装目的IP和端口对象

表格介绍DatagramPacket 常用的方法

方法含义
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

2.3 SocketAddress


在上述DatagramPacket对象发送数据包时,需要构造SocketAddress 来封装IP和端口,我们常使用SocketAddress 的子类InetSocketAddress来构建对象

构造方法含义
InetSocketAddress(InetAddress address, int port)创建一个Socket地址,包含IP地址和端口号

三. C/S结构测试


3.1 TCP通信


TCP网络协议通信可查看这篇文章:
利用TCP网络编程实现客户端和服务端简单交互

3.2 UDP通信


下面讲解如何利用Socket实现C/S结构的UDP协议通信,如下图为传输过程
在这里插入图片描述

服务端Server

java">//构建UDP协议的服务端
public class UDPServer {
    //构建套接字
    DatagramSocket socket;

    //构建协议对象(参数表示服务器端口号)
    public UDPServer(int serverPort) throws SocketException {
        socket = new DatagramSocket(serverPort);
    }

    //开启服务器进行监听
    public void startListening() throws IOException {
        System.out.println("===============服务器开启监听===================");
        Scanner scanner = new Scanner(System.in);//用来回复
        while (true){
            //1.构建数据包用来接受数据
            DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
            //2.等待接受数据(没有返回值,但是已经接收到了数据)
            socket.receive(receivePacket);

            //3.将接受的数据取出
            String receiveData = new String(receivePacket.getData(),0,receivePacket.getLength());
            //如果客户端发送来ex或exit则退出
            if ("ex".equals(receiveData) || "exit".equals(receiveData)){
                System.out.println("===============服务器退出===================");
                break;
            }

            //4.根据请求进行回复
            System.out.println("收到消息:{"+receiveData+"}");
            System.out.println("请输入想要回复的信息:");
            String answer = scanner.nextLine();
            byte[] answerBytes = answer.getBytes();

            //5.将回复封装为数据包发送回客户端
            //注意:这里是根据接受的数据包来获取发送方的ip和端口
            DatagramPacket answerPacket = new DatagramPacket(answerBytes, 0, answerBytes.length, receivePacket.getSocketAddress());
            socket.send(answerPacket);

        }
    }
    

    public static void main(String[] args) throws IOException {
        UDPServer udpServer = new UDPServer(8899);
        udpServer.startListening();
    }

}

客户端Client

java">//构建UDP协议的客户端
public class UDPClient {
    //服务器端口号
    int serverPort;
    //服务器ip
    String serverIp;
    //构建套接字
    DatagramSocket socket;

    //构建协议对象(参数表示服务器端口号和服务器ip地址)
    public UDPClient(int serverPort, String serverIp) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        this.socket = new DatagramSocket();
    }


    public void startSend() throws IOException {
        System.out.println("===============客户端开启接受===================");
        //1.获取输入
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请输入想要发送的信息:");
            String request = scanner.nextLine();
            byte[] requestBytes = request.getBytes();

            //2.构建数据包
            //InetAddress.getByName()表示根据服务器主机名称解析ip地址
            DatagramPacket requestPacket = new DatagramPacket(requestBytes, 0, requestBytes.length, InetAddress.getByName(serverIp), serverPort);

            //3.发送数据包
            socket.send(requestPacket);
            //设定退出
            if ("ex".equals(request) || "exit".equals(request)){
                System.out.println("===============客户端退出===================");
                break;
            }

            //4.构建数据包用来获取响应
            DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
            socket.receive(receivePacket);

            //5.将获取的数据取出
            String receiveData = new String(receivePacket.getData(),0,receivePacket.getLength());
            System.out.println("收到消息:{"+receiveData+"}");

        }
    }


    public static void main(String[] args) throws IOException {
        UDPClient udpClient = new UDPClient(8899, "192.168.31.104");
        udpClient.startSend();
    }
}

服务器端运行在192.168.31.104上,利用如下代码开启监听:

java -cp NetworkSocket-1.0-SNAPSHOT.jar com.nuaa.mySocket.server.UDPServer               

客户端运行在本地,通信对话如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yKrsakMb-1685345822236)(C:\Users\29973\AppData\Roaming\Typora\typora-user-images\image-20230529153224095.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c4U7ys98-1685345822237)(C:\Users\29973\AppData\Roaming\Typora\typora-user-images\image-20230529153244166.png)]


http://www.niftyadmin.cn/n/373250.html

相关文章

【论文阅读】Analyzing group-level emotion with global alignment kernel based approach

【论文阅读】Analyzing group-level emotion with global alignment kernel based approach 摘要1.介绍与相关工作2.方法3.实验 摘要 本篇博客参考IEEE于2022年收录的论文Analyzing group-level emotion with global alignment kernel based approach,对其主要内容…

赛灵思 ZYNQ UltraScale+ MPSoC Petalinux驱动开发:Linux字符驱动开发

目录 赛灵思 ZYNQ UltraScale MPSoC:Linux字符驱动开发1、Linux驱动程序简介2、Linux字符设备开发步骤2.1、系统调用2.2、驱动模块的加载与卸载2.2.1、驱动加载/卸载方式:2.2.2、驱动注册函数和卸载注册函数2.2.3、字符设备注册与注销2.2.4、实现设备操作…

Linux 多线程

Linux 多线程 前言线程概念优点缺点异常 进程VS线程线程控制线程创建线程终止线程取消 线程分离线程库模拟实现创建线程 线程互斥线程间的互斥相关概念互斥量mutex 常见锁的概念死锁Linux线程同步条件变量 生产者消费模型概念基于阻塞队列的生产消费模型 POSIX信号量概念基于环…

第五次

1.总结变量的类型及含义 含义:顾名思义,变量就是程序设计语言中的一个可以变化的量,当然,可以变化的是变量的值。几乎所 有的程序设计语言中都有定义变量,并且其涵义也大同小异。从本质上讲,变量就是在程序…

【C++】类与对象——六个默认成员函数、构造函数的概念和特征,析构函数的概念和特征

文章目录 1.类的六个默认成员函数2.构造函数2.1构造函数的概念2.2构造函数的特性 3.析构函数3.1析构函数的概念3.2析构函数的特征 1.类的六个默认成员函数 如果一个类中什么成员都没有,简称为空类。   空类中真的什么都没有吗? 并不是,任何…

在 AWS EC2 Linux 服务器上部署Gunicorn

在 AWS EC2 Linux 服务器上部署 Flask 应用的步骤类似,你也可以使用 Gunicorn。以下是具体步骤: 1. 连接到你的 AWS EC2 实例。你可以通过 SSH 进行连接,如: ssh -i /path/to/your/key.pem ec2-useryour-ec2-ip-address 2. 在你…

【IDEA插件开发】快速入门系列01 开发一个简单的Idea插件

IDEA插件开发流程 IDEA插件开发官方文档 英文好的建议阅读官方文档 IDEA插件开发官方文档:https://plugins.jetbrains.com/docs/intellij/welcome.html 搭建IDEA插件开发环境 1.安装社区版IDEA 在这里我们需要下载IDEA社区版的历史版本。 历史版本的下载网址&a…

基于pytorch搭建多特征LSTM时间序列预测代码详细解读(附完整代码)

文章目录 LSTM时间序列预测数据获取与预处理模型构建训练与测试 LSTM时间序列预测 对于LSTM神经网络的概念想必大家也是熟练掌握了,所以本文章不涉及对LSTM概念的解读,仅解释如何使用pytorch使用LSTM进行时间序列预测,复原使用代码实现的全流…