Socket、UDP、TCP协议和简单实现基于UDP的客户端服务端

news2025/1/16 16:58:52

目录

Socket

TCP和UDP区别

UDP:无连接,不可靠传输,面向数据报,全双工

TCP:有连接,可靠传输,面向字节流,全双工

无连接和有连接

可靠传输和不可靠传输 

面向数据报和面向字节流 

全双工和半双工

Java中对于传输层的一些API 

DatagramSocket 

DatagramSocket构造方法 

send()和receive()方法

close()方法 

DatagramPacket 

 DatagramPacket构造方法

实现一个UDP客户端-服务端的代码 

明确服务端做的事

UDP服务端代码编写 

明确客户端做的事 

UDP客户端代码编写 

通信结果: 

为什么客户端不需要指定一个特定的端口号呢? 


Socket

我们都知道用户在进行网络通信的时候,应用层会将报文发送给传输层,发送的这个过程,应用层需要调用操作系统的一些api,准确来说就是调用传输层的api,应用层和传输层之间沟通调用的api就是Socket。严格意义上讲,socket的api属于传输层。

TCP和UDP就是Socke的apit提供的两种不同的风格。

TCP和UDP区别

UDP:无连接,不可靠传输,面向数据报,全双工

TCP:有连接,可靠传输,面向字节流,全双工

无连接和有连接

无连接:不确保接收方是否接收到信息。比如发短信,发微信都是无连接通信,不需要对方在线什么的就能直接把要传递的信息发送出去

有连接:确保接收方会收到信息 。比如打电话,打视频,需要对方接起才能让双方进行信息的传递

原因:UDP协议当中发送方和接收方的运输层进程之间没有建立握手,只负责把应用层的报文打包成UDP报文段进行发送,不关注接收方是否能收到,所以UDP协议是无连接的。而TCP协议在传输数据之前会进行“三次握手”来确保接收方是能够收到信息的,所以TCP协议是有连接的

可靠传输和不可靠传输 

可靠传输就是发送方发送完信息后,接收方如果收到了信息,发送方可以知晓接收方已经收到了信息,比如有些聊天的已读功能

不可靠传输就是发送方发送完信息后,不知道接收方是否收到了信息,比如微信聊天,发送方并不知道接收方是否接受到信息。

面向数据报和面向字节流 

UDP协议就是面向数据报的协议。

传输层协议是以数据报为基本单位进行传输的,操作系统不会对消息进行拆分,也就是直接把应用层传过来的报文打包为UDP数据段,然后传输到网络层 

而TCP协议是面向字节流的协议。

TCP把数据看成一个没有结构的,但是有序的字节流。

当使用TCP协议进行传输的时候,一条应用层消息可能会被操作系统分成多个TCP报文。也就是说应用层发送过来的报文会被拆分成多个数据段,比如:|

应用层打算发送Hello This is Java,使用TCP协议就有可能拆分成两个TCP段:

也有可能只有一个TCP段。

而对于UDP协议是不会拆分的:

全双工和半双工

全双工:一个通信通道可以双向传输(既可以发送,又可以接收) 比如很多道路都是可以双向通行的

半双工:通信通道只能单向传输(只能发送或接收) 比如青藏铁路这样的,只能单向通行。

Java中对于传输层的一些API 

DatagramSocket 

在操作系统中一切皆为文件。

使用DatagramSocket这个类,可以创建socket对象,操作系统中把这个socket当做一个文件来处理,相当于文件描述符表上的某一项。 

使用一个socket对象就可以和另外一个主机进行通信了,如果要和多个主机进行通信,可以创建多个socket对象。 

DatagramSocket构造方法 

DatagramSocket()   系统自动分配一个空闲的端口号

DatagramSocket(int port)   指定端口号,将socket和对应的端口相关联。

send()和receive()方法

void send(DatagramPacket packet)  代表socket发送应用层报文的方式
void receive(DatagramPacket packet) 代表socket接收应用层报文的方式

需要发送/接收的DatagramPackett就是一个应用层报文。 

close()方法 

用于关闭文件描述符表项,释放进程当中的文件描述符表项所占用的空间。

DatagramPacket 

表示的是UDP当中传输的一个应用层报文 

 DatagramPacket构造方法

DatagramPacket(byte[] buf,int length)把buf数组作为地址
DatagramPacket(byte[] buf,int offset,int length,SocketAddress)把buf数组作为地址,并且指定了需要传输的目标主机IP和端口号

实现一个UDP客户端-服务端的代码 

假设约定:客户端是运行在用户手中的,服务器是运行在我们程序员自己的电脑 。

明确服务端做的事

1、读取客户端的请求

2、根据请求计算响应

3、将响应返回给客户端 

需要指定的属性:DatagramSocket socket(socket对象) 用来为客户端提供socket来接收应用层报文

构造方法当中初始化socket对象,并且指定本机当中需要建立通信的端口号。 

 注意:应用层和传输层建立连接的时候一定要指明socket端口号,不然就会导致选用无参构造方法,无法明确UDP和应用层的哪个端口建立联系,从而无法通信。 

UDP服务端代码编写 

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;

public class UdpEchoServer2 {
    //与服务端建立联系的socket
    private DatagramSocket datagramSocket;

    //使用构造方法并传入端口(关联端口)
    public UdpEchoServer2(int port) throws SocketException {
        //创建对象
        datagramSocket=new DatagramSocket(port);//port是服务端进程端口号
    }

    //创建start方法作为服务器启动
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            //1、packet存放接收应用层内容
            DatagramPacket receivePacket=new DatagramPacket(new byte[4096],4096);
            //2、使用socket来接收应用层信息并将其存放在packet的byte数组中
            datagramSocket.receive(receivePacket);
            //3、截取byte数组中应用层信息的实际长度的内容,比如hello就截取hello长度的内容
            //也就是获取数据报的实际长度部分
            String request = new String(receivePacket.getData(),0,receivePacket.getLength());

            //4、模拟回显服务器,将提取出来的数据报传给process进行处理并把响应赋值给response
            String response= process(request);

            //5、将响应字符串转化为字节数组
            byte[] responseByte=response.getBytes();
            //6、获取响应数组长度
            int responseByteLength= responseByte.length;
            //7、获取对应的客户端的IP和端口号(SocketAddress)根据packet的信息获取对应的地址
            SocketAddress address = receivePacket.getSocketAddress();
            //8、构造返回给客户端的socket对象
            DatagramPacket responsePacket=new DatagramPacket(responseByte,responseByteLength,address);
            //9、使用构造的socket对象将响应发送给客户端
            datagramSocket.send(responsePacket);
            //输出处理结果作为验证
            System.out.println("客户端IP:"+receivePacket.getAddress()+
                    "客户端端口号:"+receivePacket.getPort());

        }

    }
    //服务器响应
    public String process(String request){
        return "udp服务器已响应"+request;
    }

    //服务端启动
    public static void main(String[] args) throws IOException {
        UdpEchoServer2 udpEchoServer2=new UdpEchoServer2(9090);
        udpEchoServer2.start();
    }

}

启动服务端:(指定服务器端口号为9090)此时启动后服务器正常启动,但是由于客户端没有向服务端发送任何请求,所以服务端会在receive方法出进行阻塞等待。

    public static void main(String[] args) throws IOException {
        UdpEchoServer2 udpEchoServer2=new UdpEchoServer2(9090);
        udpEchoServer2.start();
    }

  

明确客户端做的事 

客户端主要做的事就是和服务端建立通信,并且为服务端的receive方法内部的数据(DatagramPacket)等待服务端的send方法发送数据(DatagramPacket)回来并做出响应

UDP客户端代码编写 

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    /**
     * 客户端需要有的属性:
     * 1、和服务端建立联系的socket
     * 2、服务端的ip地址
     * 3、服务端的端口号
     */
    private DatagramSocket socket;//和服务端建立联系的socket

    private String serverIp;//服务端的ip地址(目的IP)

    private int serverPort;//服务端的端口号(目的端口)

    //构造方法
    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        socket=new DatagramSocket();
        this.serverIp=serverIp;
        this.serverPort=serverPort;
    }

    //启动客户端
    public void start() throws IOException {
        System.out.println("客户端已启动!");
        Scanner input=new Scanner(System.in);
        while(true){
            //1.用户从控制台输入想要发送给服务端的数据
            System.out.println("请输入您想要发送给服务端的数据:");
            String request= input.next();
            //2、构造Udp请求
                //将请求转为请求数组
            byte[] requestBytes=request.getBytes();
                //获取请求数组的长度
            int length= requestBytes.length;
            //3、指定服务端的ip和端口号
            DatagramPacket requestPacket=new DatagramPacket(requestBytes,length,
                    InetAddress.getByName(serverIp),serverPort);
            //4、将请求发送到服务端的receive方法中
            socket.send(requestPacket);
            //5、读取并接收服务端的响应结果
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);//存放读取的结果
                //接收服务端的响应
            socket.receive(responsePacket);
            //6、构造响应的字符串
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            //7、输出响应的字符串
            System.out.println(response);
        }

    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient=new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start();//客户端启动
    }

}

先启动服务端,再启动客户端,否则无法顺利完成通信。

通信结果: 

 

客户端和服务端通信的流程图解:

 

为什么客户端不需要指定一个特定的端口号呢? 

首先,客户端指定特定的端口号,如果该端口号被占用,那么就无法取得和服务端的通信了,会抛出BindException异常。其次,客户端是不可控的,因为客户端往往是有很多台的,不同客户端的程序运行情况我们是不知道的,无法有效的进行控制,这些不受到我们程序员的控制,所以不如让客户端自由分配一个可以使用的端口号即可,而服务端是可控的,程序员可以手动的控制服务端的端口占用情况是非常方便的,如果是随机分配的反而会提高程序员的工作难度。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1470526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pclpy 最小二乘法拟合平面

pclpy 最小二乘法拟合平面 一、算法原理二、代码三、结果1.左边原点云、右边最小二乘法拟合平面后点云投影 四、相关数据 一、算法原理 平面方程的一般表达式为: A x B y C z D 0 ( C ≠ 0 ) Ax By Cz D 0 \quad (C\neq0) AxByCzD0(C0) 即: …

【深度学习笔记】 3_13 丢弃法

注:本文为《动手学深度学习》开源内容,部分标注了个人理解,仅为个人学习记录,无抄袭搬运意图 3.13 丢弃法 除了前一节介绍的权重衰减以外,深度学习模型常常使用丢弃法(dropout)[1] 来应对过拟合…

HDL FPGA 学习 - Quartus II 工程搭建,ModelSim 仿真,时序分析,IP 核使用,Nios II 软核使用,更多技巧和规范总结

目录 工程搭建、仿真与时钟约束 一点技巧 ModelSim 仿真 Timing Analyzer 时钟信号约束 SignalTap II 使用 In-System Memory Content Editor 使用 记录 QII 的 IP 核使用 记录 Qsys/Nios II 相关 记录 Qsys 的 IP 核使用 封装 Avalon IP 更多小技巧教程文章 更多好…

【C语言】linux内核ipoib模块 - ipoib_tx_poll

一、中文注释 这段代码是 Linux 内核网络栈中与 InfiniBand 协议相关的一个部分,特别是与 IP over InfiniBand (IPoIB)相关。该函数负责去处理IPoIB的发送完成队列(发送CQ)上的工作请求(work completions)。以下是对这…

前后端分离Vue+ElementUI+nodejs蛋糕甜品商城购物网站95m4l

本文主要介绍了一种基于windows平台实现的蛋糕购物商城网站。该系统为用户找到蛋糕购物商城网站提供了更安全、更高效、更便捷的途径。本系统有二个角色:管理员和用户,要求具备以下功能: (1)用户可以修改个人信息&…

YOLO系列论文阅读(v1--v3)

搞目标检测,绕不开的一个框架就是yolo,而且更糟糕的是,随着yolo的发展迭代,yolo网络可以做的事越来越多,语义分割,关键点检测,3D目标检测。。。这几天决定把YOLO系列彻底梳理一下,在…

奇异递归模板模式应用6-类模板enable_shared_from_this

异步编程中存在一种场景,需要在类中将该类的对象注册到某个回调类或函数中,不能简单地将this传递给回调类中,很可能因为回调时该对象不存在而导致野指针访问(也有可能在析构函数解注册时被回调,造成对象不完整&#xf…

【变压器故障诊断分类及预测】基于GRNN神经网络

课题名称:基于GRNN神经网络的变压器故障诊断分类及预测 版本日期:2024-02-10 运行方式:直接运行GRNN0507.m文件 代码获取方式:私信博主或QQ:491052175 模型描述: 对变压器油中溶解气体进行分析是变压器…

基于springboot+vue的精准扶贫管理系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

前端工程化面试题 | 15.精选前端工程化高频面试题

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Linux系统前后端分离项目

目录 一.jdk安装 二.tomcat安装 三.MySQL安装 四.nginx安装 五.Nginx负载均衡tomcat 六.前端部署 一.jdk安装 1. 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录,将安装包拖进去 2. 解压安装包 这里需要解压到usr/local目录下,在这里新建一个…

基于yolov5的电瓶车和自行车检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示: 基于yolov5的电瓶车和自行车检测系统_哔哩哔哩_bilibili (一)简介 基于yolov5的电瓶车和自行车检测系统是在pytorch框架下实现的,这是一个完整的项目,包括代码,数据集,训练好的模型…

低于API等级30的应用将无法在上述应用商店

minSdkVersion minSdkVersion用于指定应用兼容的最低Android版本(API等级)。 如果APP某些功能无法支持低版本Android系统的设备,可以配置minSdkVersion确保APP只能安装到指定Android版本以上的设备。HBuilder|HBuilderX中可在manifest.json中…

单词倒排——c语言解法

以下是题目: 这个题中有三个点, 一个是将非字母的字符转换为空格, 第二是如果有两个连续的空格, 那么就可以将这两个连续的空格变成一个空格。 第三个点就是让单词倒排。 那么我们就可以将这三个点分别封装成三个函数。 还有就是…

Spring Security源码学习

Spring Security本质是一个过滤器链 过滤器链本质是责任链设计模型 1. HttpSecurity 【第五篇】深入理解HttpSecurity的设计-腾讯云开发者社区-腾讯云 在以前spring security也是采用xml配置的方式&#xff0c;在<http>标签中配置http请求相关的配置&#xff0c;如用户…

Linux下的版本控制系统——Git:初学者指南

引言 在软件开发的世界中&#xff0c;版本控制是一项至关重要的技术。它允许开发者追踪和管理代码的变更历史&#xff0c;协同工作&#xff0c;并在必要时恢复到之前的版本。而在Linux系统下&#xff0c;Git已经成为事实上的版本控制标准。本文将带领大家走进Git的世界&#x…

【人脸朝向识别与分类预测】基于PNN神经网络

课题名称&#xff1a;基于PNN神经网络的人脸朝向识别分类 版本日期&#xff1a;2024-02-20 运行方式&#xff1a;直接运行PNN0503.m文件 代码获取方式&#xff1a;私信博主或 QQ:491052175 模型描述&#xff1a; 采集到一组人脸朝向不同角度时的图像&#xff0c;图像来自不…

React组件详解

React组件分为两大类 1.函数组件 2.类组件&#xff08;最常用&#xff09; 组件化 import ReactDom from "react-dom";// // 1.通过函数创建一个组件 // 2.函数名字必须大写开头 // 3.函数必须有返回值 function Func1() {return <h2>这是一个基础组件</h…

[设计模式Java实现附plantuml源码~行为型]对象间的联动~观察者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

数字化转型导师鹏:政府数字化转型政务服务类案例研究

政府数字化转型政务服务类案例研究 课程背景&#xff1a; 很多地方政府存在以下问题&#xff1a; 不清楚标杆省政府数字化转型的政务服务类成功案例 不清楚地级市政府数字化转型的政务服务类成功案例 不清楚县区级政府数字化转型的政务服务类成功案例 课程特色&#x…