UDP和TCP的区别与代码实现(详解)


一、传输层协议

UDP和TCP区别

UDP:无连接,不可靠传输,面向数据报,全双工.
TCP:有连接,可靠传输,面向字节流,全双工.

1.有连接,无连接:

在这里插入图片描述

2.可靠传输,不可靠传输

在这里插入图片描述
TCP是可靠传输, UDP是不可靠传输,因此TCP比 UD更安全.
错。安全:谈到"网络安全"
指的是,如果你传输的数据是否容易被黑客截获.以及如果被截获后是否会泄露一些重要信息.

3.面向字节流,面向数据报

面向字节流:
TCP和文件操作类似,都是“流”式的(由于这里传输的单位是字节,称为字节流)
如:
在这里插入图片描述
面向数据报:
UDP是面向数据报,读写的基本单位,是一个UDP数据报(包含了一系列的数据/属性)

4.全双工,半双工

全双工一个通道,可以双向通信
半双工一个通道,只能单向通信.

二、UDP代码实现

1.UDP的socket api.

两个核心的类.
在这里插入图片描述

在这里插入图片描述

1.DatagramSocket

是一个Socket对象,Java中的socket对象,就对应这系统里的socket文件.(最终还是要落到网卡)。要进行网络通信,必须得先有socket对象。

操作系统,使用文件这样的概念,来管理一些软硬件资源.
网卡,操作系统也是使用文件的方式来管理网卡的。表示网卡的这类文件,称为Socket 文件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.客户端给服务器发数据:
源端口:就是客户端的端口。目的端口:服务器的端口
2.服务器给客户端发数据:
源端口:服务器的端口。目的端口:客户端的端口

客户端端口号:让系统自动分配一个端口,不指定固定值。
(一个客户端的主机,上面运行的程序很多,天知道手动指定的端口是不是被别的程序占用了.让系统自动分配一个端口是更明智的选择。)
服务器端口号:程序员指定固定值。

2.DatagramPacket

表示了一个UDP数据报.
代表了系统中设定的UDP数据报的二进制结构
在这里插入图片描述

2.动手写udp服务器.

最简单的UDP服务器.回显服务器(echo server).客户端发啥,服务器返回啥

//UDP回显服务器
public class UdpEchoServer {
    private DatagramSocket socket=null;
    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);//当端口号被占用就new失败
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true){
            //反复长期执行针对客户端请求处理逻辑
            //1.读取请求,并解析
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            //如果此时客户端的请求还没来,receive方法就会阻塞等待.=>阻塞到真正有客户端发起请求过来了.
            socket.receive(requestPacket);
            //这样转字符串的前提是,后续客户端发的数据就是一个文本的字符串
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求,计算出响应(具体做了啥,由于写的是回显服务器,没第二步)
            String responce=process(request);
            //3.把响应写回给客户端
            //告知网卡,需要发的内容是什么,要发给谁
            DatagramPacket responsePacket=new DatagramPacket(responce.getBytes(),responce.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //记录日志,方便观察程序执行效果
            System.out.printf("[%s:%d] req:%s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,responce);
        }
    }

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

在这里插入图片描述

1)最典型的情况,端口号被占用.端口号用来区分主机上的应用程序。
一个应用程序可以占据主机上的多个端口。一个端口只能被一个进程占用.(这句话其实不够严谨,有特例, 此处不讨论)
端口已经被别的进程占用了,此时你再尝试创建这个socket对象,占用该端口,此时就会报错
在这里插入图片描述
2)一个服务器要给很多客户端提供服务.服务器也不知道客户端啥时候来.
服务器只能"时刻准备着",随时客户端来了,就随时提供服务.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3)把响应写回给客户端,告知网卡,需要发的内容是什么,要发给谁。
在这里插入图片描述

3.动手写udp客户端

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

    //服务器的ip,服务器的端口号
    public  UdpEchoClient(String ip,int port) throws SocketException {
        serverIp=ip;
        serverPort=port;
        //这个new操作就不再指定端口了,让系统自动分配一个空闲端口
        socket=new DatagramSocket();
    }
    //让这个客户端反复从控制台读取用户输入内容,把这个内容构造UDP请求发送给服务器
    //再读取服务器返回的UDP响应,最终显示在客户端的屏幕上。
    public void start() throws IOException {
        Scanner scanner=new Scanner(System.in);
        System.out.println("客户端启动");
        while (true){
            //1.从控制台读取用户输入内容
            System.out.println("->");
            String request=scanner.next();
            //2.构造一个请求对象并发给服务器
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length
            , InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //3.读取响应并解析响应内容
            DatagramPacket responcePacket=new DatagramPacket(new byte[4096],4096);//构造一个空的对象
            socket.receive(responcePacket);
            String response=new String(responcePacket.getData(),0,responcePacket.getLength());//从0开始
            //4.显示到屏幕上
            System.out.println(response);
        }
    }

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


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
客户端和服务器执行顺序如下:
下面的4是同时执行的。服务器端执行到4后继续执行,客户端执行到4阻塞等待直到服务器返回响应。
在这里插入图片描述

在这里插入图片描述
2)
在这里插入图片描述
启动多个客户端,多个客户端也是可以被服务器应对的
IDEA上启动多个程序,需要稍微设置一下:

在这里插入图片描述
在这里插入图片描述
#手动写TCP

1.TCP服务端

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("服务器启动");
       while (true){
           //进入循环之后,要做的事情不是读取客户端的请求,而是先处理客户端的"连接"
           Socket clientSocket=serverSocket.accept();
           processConnection(clientSocket);
       }
   }

   private void processConnection(Socket clientSocket) {
       System.out.printf("[%s:%d]客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
       //接下来就可以读取请求,根据请求计算响应,返回响应
       try(InputStream inputStream=clientSocket.getInputStream();
           OutputStream outputStream=clientSocket.getOutputStream()){
           //一次连接中可能有多次请求,响应
           while (true){
               //读取请求并解析,直接使用Scanner
               Scanner scanner=new Scanner(inputStream);
               if(!scanner.hasNext()){
                   //读取完毕,客户端下线
                   System.out.printf("[%s,%d] 客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                   break;
               }
               //这个代码暗含约定,客户端发过来的请求,得是文本数据,同时暗含约定读到空白符结束
               String request=scanner.next();
               //根据请求计算响应
               String response=process(request);
               //把响应写回客户端
               PrintWriter writer=new PrintWriter(outputStream);
               //使用PrintWriter的printIn方法,把响应返回给客户端
               writer.println(response);
               writer.flush();//刷新缓冲区
               //日志
               System.out.printf("[%s:%d] req:%s,resp:%s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),
                       request,response);
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
   public  String process(String request){
       return request;
   }
   public static void main(String[] args) throws IOException {
       TcpEchoServer server=new TcpEchoServer(9090);
       server.start();
   }
}

在finally中加上close,确保socket及时关闭
在这里插入图片描述

2.TCP客户端

客户端代码~~要做的事情:
1.从控制台读取用户的输入
⒉.把输入的内容构造成请求并发送给服务器
3.从服务器读取响应
4.把响应显示到控制台上.

package TCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket=null;
    //要和服务器通信要需先知道服务器位置
    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        //这个new操作完成,完成了tcp建立
        socket=new Socket(serverIp,serverPort);

    }
    public  void start(){
        System.out.println("客户端启动");
        Scanner scannerConsole=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()) {
            while (true){
                //1.从控制台输入字符串
                System.out.println("->");
                String request =scannerConsole.next();
                //2.把请求发送给服务器
                PrintWriter printWriter=new PrintWriter(outputStream);
                //使用printIn带上换行,后续服务器读取请求,就可以使用scanner.next来获取了
                printWriter.println(request);
                //不要忘记flush,确保数据发送
                printWriter.flush();
                //3.从服务器读取响应
                Scanner scannerNetwork=new Scanner(inputStream);
                String response=scannerNetwork.next();
                //4.把响应打印出来
                System.out.println(response);
            }

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

    }

}

注意点

当前代码还存在一个很大的问题!!
当启动两个客户端,会咋样??
现象:
当第一个客户端连接好了之后,第二个客户端,不能正确被处理.服务器看不到客户端上线,同时客户端发来的请求也无法被处理。

当第一个客户端退出之后,之前第二个客户端发的请求,就能正确响应了。
在这里插入图片描述
1.使用多线程完成:
在这里插入图片描述
在这里插入图片描述
2.使用线程池也可以解决上述问题
在这里插入图片描述

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UDPTCP在数据传输方面有很大的区别。首先,UDP是无连接的,而TCP是面向连接的。这意味着在发送数据之前,TCP需要建立一个连接,而UDP不需要。其次,UDP是不可靠的,而TCP是可靠的。UDP在传输数据时不会进行重传,而TCP会确保数据的可靠传输。因此,在网络环境不好的情况下,UDP可能会丢失数据包,而TCP会进行重传以确保数据的完整性。 此外,UDPTCP还有不同的数据传输方式。TCP是面向字节流的,这意味着它将数据视为一个连续的字节流。而UDP是面向报文的,它将数据分割成报文进行传输。 对于一包数据,根据UDPTCP不同特性,它们在处理和传输数据包的方式上会有所不同TCP会将数据包拆分成较小的数据段,每个数据段都会有TCP头部信息,并按序传输和重组。而UDP会将整个数据包作为一个报文传输,不进行拆分和重组。 总结来说,UDPTCP在数据传输方面有很大的差异。UDP是无连接、不可靠的,面向报文的协议,适用于实时性要求高的场景。而TCP是面向连接、可靠的,面向字节流的协议,适用于需要保证数据完整性和顺序的场景。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Qt UDPTCP对比](https://blog.csdn.net/kchmmd/article/details/122175211)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [TCPUDP详解](https://blog.csdn.net/qq15035899256/article/details/126073927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值