UDP和TCP的区别、网络编程(UDP回显服务器、TCP回显服务器)

news2024/11/26 14:30:06

目录

一、什么是网络编程

二、网络编程的内容概念

接受端和发送端

请求和响应

服务端和客户端

三、UDP和TCP协议的区别

四、UDP网络编程的类和函数(回显服务器)

DatagramSocket

DatagramPacket 

InetSocketAddress

基于UDP的回显服务器和客户端:

UDP回显服务器 

 UDP回显客户端

五、TCP网络编程的类和函数(回显服务器)

ServerSocket 

Socket

基于TCP的回显服务器和客户端:

TCP回显服务器

 Tcp回显客户端


一、什么是网络编程

⽹络上的主机,通过不同的进程,以编程的⽅式实现⽹络通信(或称为⽹络数据传输)。也就是客户端和服务器之间的通信。 

我们如果去xx视频看电视剧,也就是发出请求(我要看这个电视剧,请服务器给我响应),然后服务器就会给你这个视频的地址(响应),然后你就能看到电视剧了。 

当然,我们只要满⾜进程不同就⾏;所以即便是同⼀个主机,只要是不同进程,基于⽹络来传输数 据,也属于⽹络编程。 (由于设备有限,这里都用一个主机来示范)

如上图:

服务器就是个进程,客户端也是个进程。服务器为客户端提供数据。

二、网络编程的内容概念

接受端和发送端

在⼀次⽹络数据传输时: 

接收端收数据的一方,也就是网络通信的源主机。

发送端发数据的一方,也就是网络通信的目的主机。

请求和响应

获取⼀个⽹络资源,涉及到两次⽹络数据传输,如下: 

请求请求数据的发送。

响应响应数据的发送。

比如:你去一个餐馆,要点餐。

请求:你说老板我要一份酸菜鱼。响应:老板听完后做了份酸菜鱼 。

服务端和客户端

 在常⻅的⽹络数据传输场景下: 

服务端提供服务的⼀⽅进程,可以提供对外服务。

客户端获取服务的⼀⽅进程,称为客⼾端。

三、UDP和TCP协议的区别

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

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

有无连接这里的“连接”是一种抽象的连接,是绑定对方信息。若双方都绑定对方的信息,则是有连接,没有绑定对方的信息则是无连接。就像结婚证,一式两份上面都有自己和爱人的信息。

可不可靠传输这个也不是我们说这个人可不可靠的那种可靠,而是这个协议它有没有“尽可能”的去传输数据。就比如要传一个信息,可能会失败,这时候采取什么样的行动呢?如果可靠,它可能会进行重新发送啊,或者过一会儿发送什么什么的;但是不可靠传输只管传,其他什么都不会做,所以是不可靠传输。

面向字节流,面向数据报这里指的是传输的基本单位是什么,面向字节流的基本是字节流,而面向数据报的基本单位是数据报。两者不同,传输的方式也会不一样。

全双工同个时间内,A->B和B->A可以同步进行。而半双工则是同个时间,只能单向进行。

四、UDP网络编程的类和函数(回显服务器)

DatagramSocket

DatagramSocket 是UDP Socket,⽤于发送和接收UDP数据报。

DatagramSocket 构造⽅法:

方法签名方法说明
DatagramSocket()创建⼀个UDP数据报套接字的Socket,绑定到本机任 意⼀个随机端⼝(⼀般⽤于客⼾端)
DatagramSocket(int port)创建⼀个UDP数据报套接字的Socket,绑定到本机指 定的端⼝(⼀般⽤于服务端)

DatagramSocket ⽅法: 

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该⽅法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket 

DatagramPacket是UDP Socket发送和接收的数据报。

DatagramPacket 构造⽅法: 

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造⼀个DatagramPacket以⽤来接收数据报,接收的 数据保存在字节数组(第⼀个参数buf)中,接收指定 ⻓度(第⼆个参数length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造⼀个DatagramPacket以⽤来发送数据报,发送的 数据为字节数组(第⼀个参数buf)中,从0到指定⻓ 度(第⼆个参数length)。address指定⽬的主机的IP 和端⼝号

 DatagramPacket ⽅法:

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

构造UDP发送的数据报时,需要传⼊ SocketAddress ,该对象可以使⽤ InetSocketAddress 来创建。

InetSocketAddress

InetSocketAddress ( SocketAddress 的⼦类 )构造⽅法:

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建⼀个Socket地址,包含IP地址和端⼝号

基于UDP的回显服务器和客户端:

UDP回显服务器 

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

public class UdpEchoServer {
    private DatagramSocket socket=null;

    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器开启!");
        while(true){
            // 1. 读取客户端的请求并解析
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            // 上述收到的数据, 是二进制 byte[] 的形式体现的. 后续代码如果要进行打印之类的处理操作
            // 需要转成字符串才好处理.
            String request=new String(requestPacket.getData(),
                    0,requestPacket.getLength());
            // 2. 根据请求计算响应, 由于此处是回显服务器. 响应就是请求.
            String respond=process(request);
            // 3. 把响应写回到客户端
            DatagramPacket respondPacket =new DatagramPacket(respond.getBytes(),
                    0,respond.getBytes().length,requestPacket.getSocketAddress());
            socket.send(respondPacket);
            // 4. 把日志打印一下.
            System.out.printf("[%s:%d] req=%s,res=%s\n",requestPacket.getAddress(),
                    requestPacket.getPort(),request,respond);
        }
    }

    public String process(String request) {
        return request;
    }

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

1)用DatagramSocket创建出一个UDP服务器,参数为端口号(比如9090,就是约定客户端找到服务器的地方,就像约会地点);这里不需要ip地址,因为每个机子才有ip地址,所以直接在客户端new一个对象,参数输入服务器的ip地址就行了。

2)开始服务器,由于服务器基本上都是7*24小时运行的,所以我们用个while循环来一直给它运行;

3)我们用DatagramPacket来接受服务器传来的数据报,传满这个byte数组,然后包装成DatagramPacket对象,让服务器来接收;

4)我们现在是学习,为了方便查看里面的数据,所以我们把数据报转成字符串,给服务器去响应。

5)写一个process响应函数(回显服务器,其实就是return客户端发来的信息),来响应客户端发来的信息,这里我们就把刚刚的字符串传进去,然后返回同样的数据。

6)把这个返回来的信息,我们拿DatagramPacket来包装起来,发回给客户端,这样就完成了响应。(注意的是,发回去的时候要传客户端的ip和端口号,不然都不知道要传给谁)

7)打印日志。

 UDP回显客户端

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    private void start() throws IOException {
        System.out.println("启动客户端");
        // 1. 从控制台读取到用户的输入.
        Scanner scanner = new Scanner(System.in);

        while (true) {

            System.out.print("->");
            String request = scanner.next();
            // 2. 构造出一个 UDP 请求, 发送给服务器.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes()
                    , request.getBytes().length, InetAddress.getByName(serverIP), this.serverPort);
            socket.send(requestPacket);
            // 3. 从服务器读取到响应
            DatagramPacket respondPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(respondPacket);
            String respond = new String(respondPacket.getData(), 0, respondPacket.getLength());
            // 4. 把响应打印到控制台上.
            System.out.println(respond);
        }
    }

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

1)我们UDP的客户端的构造函数是要有服务器IP和端口号的,因为客户端要主动发数据报给服务器,但是new客户端对象的时候却不需要,因为服务器最开始不需要主动找客户端,而且指定端口号的话,可能会和客户的电脑中的端口号冲突,就会产生bug;

2)因为客户端可能7*24小时都有人发数据,所以我们也是做一个while循环,输入字符串,这时候我们构建DatagramPacket来接受一下,所以这个字符串传进来的时候要getByte()一下,然后send发送这个datagrampacket对象;

3)然后等待响应,接收服务器传来的响应,也是用DatagramPacket来接收;

4)为了方便观看,也是转成字符串,打印出来。

五、TCP网络编程的类和函数(回显服务器)

ServerSocket 

ServerSocket 是创建TCP服务端Socket的API。

ServerSocket 构造⽅法: 

方法签名方法说明
ServerSocket(int port)创建⼀个服务端流套接字Socket,并绑定到指定端⼝

 ServerSocket ⽅法:

方法签名方法说明
Socket accept()开始监听指定端⼝(创建时绑定的端⼝),有客⼾端连接后,返回⼀个服务端Socket对象,并基于该 Socket建⽴与客⼾端的连接,否则阻塞等待
void close()关闭此套接字

因为TCP是有连接的,所以需要accept来连接一下,但这里的连接是抽象的连接(这里的连接我们是察觉不到的,是系统内核做的),这里的accept类似于做了一个“确认连接”的作用。

就像打电话,A打给B,会经历一系列的数据传输(比如给基站发数据说我要大给B,但这里我们是察觉不到的,很快B就响铃了)这时B接通了,就相当于accept连接完成了。

Socket就像去揽客,,然后accept连接出来的是一个客户端对象(网卡),把它揽进来,相当于我们对它进行一对一的服务。

Socket

Socket 是客⼾端Socket,或服务端中接收到客⼾端建⽴连接(accept⽅法)的请求后,返回的服 务端Socket。

不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后,保存的对端信息,及⽤来与对⽅收发数据的。

Socket 构造⽅法:

方法签名方法说明
Socket(String host, int port)创建⼀个客⼾端流套接字Socket,并与对应IP的主机 上,对应端⼝的进程建⽴连接

Socket ⽅法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输⼊流
OutputStream getOutputStream()返回此套接字的输出流

基于TCP的回显服务器和客户端:

TCP回显服务器

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket=null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("启动服务器!");
        ExecutorService service= Executors.newCachedThreadPool();
        while (true){
            Socket clientSocket=serverSocket.accept();
            //不止可以创建线程,还可以使用线程池
//            Thread t=new Thread(()->{
//                processConnection(clientSocket);
//            });
//            t.start();
            //可以使用线程池,效率更高
            service.submit(()->{
                processConnection(clientSocket);
            });
        }
    }
    // 针对一个连接, 提供处理逻辑
    private void processConnection(Socket clientSocket) {
        // 先打印一下客户端的信息
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
        // 获取到 socket 中持有的流对象.
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            // 使用 Scanner 包装一下 inputStream. 就可以更方便的读取这里的请求数据了.
            Scanner scanner=new Scanner(inputStream);
            PrintWriter writer=new PrintWriter(outputStream);
            while (true){
                // 1. 读取请求并解析
                if (!scanner.hasNext()){
                    // 如果 scanner 无法读取出数据, 说明客户端关闭了连接, 导致服务器这边读取到 "末尾"
                    break;
                }

                String request=scanner.next();
                // 2. 根据请求计算响应
                String respond=process(request);
                //3. 把响应写回给客户端
                // 此处可以按照字节数组直接来写, 也可以有另外一种写法.
                // outputStream.write(response.getBytes());
                writer.println(respond);
                writer.flush();

                // 4. 打印日志
                System.out.printf("[%s:%d],req=%s res=%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,respond);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());


    }

    private String process(String request) {
        return request;
    }

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

 1)用ServerSocket创建出一个TCP服务器,参数为端口号(比如9090,就是约定客户端找到服务器的地方,就像约会地点),这里不需要ip地址,因为每个机子才有ip地址,所以直接在客户端new一个对象,参数输入服务器的ip地址就行了。

2)因为服务器都是7*24小时运行的,所以我们用while循环把他们框起来,然后因为客户很多,频繁的创建和开销很消耗资源,所以我们考虑使用线程池来解决这个问题,注意这里使用的是newCachedThreadPool(),因为这个方法的线程池数量很大,21亿可以解决这个问题。

3)我们通过服务器的accept()方法来接收客户端对象,用Socket接收,得到的就是操作客户端的网卡;

4)因为TCP是面向字节流的,所以我们使用IO操作,来获取这些字节流,为了方便,我们把inputstream对象读到的字节传到scanner里面,这样非常的方便读取。同理outputstream作为参数传入printwriter里面,为什么用这个呢,因为这个输出的时候是需要结尾为空白符作为结束标志的,而printwriter有个方法println,会有\n作为结束标志,就不要手动打\n了。这样数据流就取一个完整的数据流了,就不会和下一个数据流混一起了。

5)其余的看看源代码,其实也差不多和UDP类似,就那么一些出入而已。

6)flush()是“冲刷缓存区”,IO操作时间长,很消耗资源,所以内核优化了一下,得攒一堆IO才会一起发送,不然的话就会卡着,发不出去。

7)打印日志

 Tcp回显客户端

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

public class TcpEchoClient {
    private Socket clientSocket=null;

    public TcpEchoClient(String serverIP,int serverPort) throws IOException {
        clientSocket=new Socket(serverIP,serverPort);
    }

    public void start(){
        System.out.println("客户端启动!");
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            Scanner scanner=new Scanner(inputStream);
            Scanner scannerIn=new Scanner(System.in);
            PrintWriter writer=new PrintWriter(outputStream);
            while (true){
                // 1. 从控制台读取到用户的输入.
                System.out.print("->");
                String request=scannerIn.next();
                // 2. 构造出一个 UDP 请求, 发送给服务器.
                writer.println(request);
                writer.flush();
                // 3. 从服务器读取响应
                if(!scanner.hasNext()){
                    break;
                }
                String respond=scanner.next();
                // 4. 打印响应结果
                System.out.println(respond);
            }

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

    public static void main(String[] args) throws IOException {
        TcpEchoClient tcpEchoClient=new TcpEchoClient("127.0.0.1",9090);
        tcpEchoClient.start();
    }
}

1)我们UDP的客户端的构造函数是要有服务器IP和端口号的,因为客户端要主动发数据报给服务器,但是new客户端对象的时候却不需要,因为服务器最开始不需要找客户端,而且指定端口号的话,可能会和客户的电脑中的端口号冲突,就会产生bug。

2)接下来的基本上与前面几个同理,看看代码,这里就不赘述了。

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

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

相关文章

​​​​​​​​​​Proxifier安装步骤

​​​​​​​​​​Proxifier ​​​​​​​​​​Proxifier下载连接 进入Proxifier官网后,点击下面按钮,下载安装包 下载完成后,打开压缩包 双击运行 选择试用 安装完成

Vue 3 全屏切换组件(附Demo)

目录 1. 基本知识2. 拓展3. 延伸 1. 基本知识 全屏 API document.documentElement.requestFullscreen():请求全屏模式 document.exitFullscreen():退出全屏模式 document.fullscreenElement:返回当前处于全屏状态的元素 基本的Demo如下&…

大模型进军医疗行业:实验揭示LLMs在临床建议中的表现

近年来,大型语言模型(LLMs)如GPT-4等以其强大的自然语言处理能力,引发了科技界和公众的广泛关注。随着技术的不断进步,越来越多的人开始探索将LLMs应用于医疗行业,以期提高医疗服务的效率和质量。然而&…

第170天:应急响应-战中溯源反制对抗上线CSGoby蚁剑Sqlmap等安全工具

目录 案例一:溯源反制-Webshell工具-Antsword 案例二:溯源反制-SQL注入工具-SQLMAP 案例三:溯源反制-漏洞扫描工具-Goby 案例四:溯源反制-远程控制工具-CobaltStrike 反制Server,爆破密码(通用&#x…

吴恩达演讲全文:AI Agent工作流的趋势

本文是吴恩达今年3月的演讲,题目为“Agentic Reasoning”,对AI Agent工作流的趋势进行了讲解。 本文对AI Agent翻译为了AI代理。 吴恩达指出,随着AI技术的发展,AI代理被视为一个能显著提升软件开发效率和质量的工具。 他通过展…

umi配置阿里云短信验证登录流程

首先 开通短信服务,融合认证,设置签名,模板,templateparams,调试板块可以发送成功并测试; s​​​​​​​​​​​​​​SendSmsVerifyCode_云通信号码认证服务_API调试-阿里云OpenAPI开发者门户 下图的s…

荆州团市委领导一行赴点赋科技公司参观考察

近日,荆州团市委书记熊燃、副书记陈杰一行前往点赋科技公司进行参观考察,为荆州科技领域与青年工作的交流合作开启新篇。 在考察过程中,熊燃书记和陈杰副书记深入点赋科技公司的办公区域、设备点位等进行实地走访。他们仔细聆听了公司董事长崔…

HUAWEI_HCIA_实验指南_Lib3.1_VLAN 基础配置及 Access 接口

1、原理概述 早期的局域网技术是基于总线型结构的。总线型拓扑结构是由一根单电缆连接着所有主机,这种局域网技术存在着冲突域问题,即所有用户都在一个冲突域中,那么同一时间内只有一台主机能发送消息,从任意设备发出的消息都会被…

Monad 101 杭州线下活动:解锁创新技术,引领低成本高效 DApp 开发之路!

以太坊等区块链在处理传统金融大规模交易时面临巨大挑战,有限的可扩展性成为阻碍其广泛应用的主要瓶颈。为了解决这一难题,并缩小传统金融与去中心化金融(DeFi)之间的差距,Keone 创立了 Monad。通过显著提升交易速度和…

STM32(十八):SPI通信

SPI通信: SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)主机输出从机输入、MISO&…

Idea 2024.2.3 找不到Cache Recovery设置

idea找不到官网所说的设置 下面是解决办法 1.找到对应位置 2.增加配置文件内容 idea.is.internaltrue3.重启idea 4.查看结果 解决方案原文

Android列表组件api

目录 1.ListView控件 1)android:divider 2)android:dividerHeight 3)android:entries 4)android:footerDividersEnabled 5)android:headerDividersEnabled 6)android:listSelector 7)android:sc…

JavaScript Set 必备指南:深入理解 Set 的特性和方法

一. 了解 Set 1. 概念和用途 Set 是 JavaScript 中的一种集合(collection)数据结构,它类似于数组,但是集合中的元素是唯一的,不允许重复。Set 提供了一种存储不重复数值或对象的机制,可以用于存储一组唯一…

【03】手把手教你0基础部署SpringCloud微服务商城教学-Docker前置篇(附Linux虚拟机配置调试及Docker安装全流程)

前文回顾:【02】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(下) 首先我们第一次看见这个东西,第一步就是需要知道它到底是用来干什么的? 简单来说,Docker就是一个快速构建、运行、管理应用的…

K8s-services+pod详解1

一、Service 我们能够利用Deployment创建一组Pod来提供具有高可用性的服务。 虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题: Pod IP 会随着Pod的重建产生变化Pod IP 仅仅是集群内可见的虚拟IP,外部无法访问 这样对于访问这…

【干货】2024新学期期中考试,老师成绩发布工具

老师们别再为期中发成绩发愁了,我给各位带来了一个解决方案——易查分小程序,它可以将彻底改变您发布成绩的方式!一分钟发布期中考试成绩。不管您是教育界的新手还是老手,易查分都能成为您的得力助手。它的界面既美观又实用&#…

大数据毕业设计选题推荐-音乐数据分析系统-音乐推荐系统-Python数据可视化-Hive-Hadoop-Spark

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

一些近期值得关注的存储和备份潜在漏洞

时刻保持警惕,及时、适时地检测暴露于安全建议和警告的相关设备,这一点对企业数据安全再重要不过了。 Continuity调研指出了最近几个月,存储和备份解决方案中存在的、可被攻击者发现和利用的潜在漏洞,包括: Veeam Ba…

YOLOv10改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进

必读内容📖 如何寻找创新点?为什么要使用这个模块?如何才能提升模型的精度?这是贯穿我们研究始终的问题。创新点在这个专栏中我已经整理好了,这已经省去了大部分时间,但是当我们使用这些新的模块去优化已有…

LDR6500取电诱骗协议芯片:革新电子设备充电体验

在当今电子设备日新月异的时代,Type-C接口以其高效、便捷的特点迅速成为市场主流。这一接口不仅支持高速数据传输,还实现了正反插拔的便利性,极大地提升了用户体验。然而,在Type-C接口的广泛应用背后,一个关键的技术组…