网络编程原理:回显服务器与客户端通信交互功能

news2025/1/24 19:03:42

文章目录

  • 路由器及网络概念
  • 网络通信基础
  • TCP/IP 五层协议
  • 封装和分用
      • 封装
      • 分用
  • 网络编程(网络协议)
    • UDP类 API使用
      • 实现回显通信程序
        • 回显服务器(UDP代码)
        • 回显客户端(UDP代码)
    • TCP API使用
        • 回显服务器(TCP代码)
        • 回显客户端(TCP代码)

路由器及网络概念

网络发展是由单机时代->局域网时代->广域网时代->移动互联网时代
局域网:通过路由器的LAN为媒介来链接不同电脑,使其进行互相通信,而路由器通常为5个网口,1个WAN(用来连接上级的路由器)4个LAN。
当局域网连接的更多时,网络也会覆盖的更大。
在这里插入图片描述

交换机概念

交换机是因为路由器的LAN口过少,而需要连接到路由器的节点过多,这时候交换机的WAN通过连接路由器的LAN口,然后通过交换机的LAN口来连接其他的路由器的WAN或者电脑,来实现层层连接,构成更复杂的网络结构。

而广域网是通过更多的局域网的来连接到一起,构成的更加庞大的网络结构,覆盖一个城市或者更大。


网络通信基础

IP地址

描述一个设备,在网络中的地址,计算机中使用32位的字节数字来表示地址。
点分十进制
计算机地址由32位字节数构成,但是32位的byte字节过长,一般会表示为4个0~255之间的十进制数字,每个数字之间通过点进行分隔。
在这里插入图片描述


端口号

端口号:区分一个主机中不同的应用程序。
端口号是一个整数0~65535(2个字节)不同的程序可以关联/绑定相同的端口号,但是同一个主机上的应用程序,不能关联同一个端口号(一个端口号只能被一个程序绑定,而一个程序可以绑定多个端口)。
在实际的通信过程中,IP和端口是相互绑定的。


协议

在网络中,本质是通过光/电信号来传输数据,通过低电平表示1,高电平表示0 ,高频光信号表示1 ,低频光信号表示0。
协议就是通过一种约定,来约定通信的双方以同样的方式进行传输数据。


网络五元组

源IP 、源端口、目的IP、目的端口 、协议的类型,是在通信过程中必不可少的信息。


协议分层

通过对协议的定位或者是作用进行分类,将定位/作用相似放到同一层,然后通过上层协议调用下层协议,下层协议给上层协议提供支持。
通过协议分层不仅能够让多个层级直接交互配合,还可以对上层和下层彼此之间进行封装,使用上层协议,不必关注上层,使用下层协议不必关注下层。


TCP/IP 五层协议

物理层:描述网络通信的硬件设备
数据链路层:两个相邻节点之间的数据传输情况
网络层:进行路径规划,规划出最合适的路径
传输层:关注起点和终点
应用层:应用程序如何使用数据
在这里插入图片描述


封装和分用

封装

分装和分用描述了在网络通信中,基本的数据传输流程
1.应用层
开发者自定义通过设计数据报的格式,当用户通过输入进行传输,给打包成一个数据报来进行封装。
例如:当用户通过信息输入发送给另一个用户。
应用层协议(数据报格式):用户A(源头) 、 用户B(目的地)、时间 、发送的内容"hello"
转换为数据报:15239(源头)、 32643(目的地) 、2024-12-27 、hello
在这里插入图片描述


当应用层的数据报打包好后,可以通过调用下层协议,调用系统的API将数据传给数据层。
2.传输层

当到达传输层后,继续对应用层传输的数据进行打包,“拼接”。
在应用层的基础上进行拼接传输层的报头
UDP报头的关键信息:源端口和目的端口
在这里插入图片描述


网络层

网络层最主要的协议:IP协议,在原有的传输层的基础上进行拼接打包。
IP报头中包含的最重要的熟悉:源IP和目的IP
在这里插入图片描述


数据链路层

以太网:传输给数据链路层之后,通过以太网再次进行打包,通过拼接以太网报头来打包。
以太网包含的最重要信息:源mac地址和目的mac地址(描述一个设备在网络中的地址)

在这里插入图片描述
以下每一都是通过报头和载荷的形式进行封装,数据链路层通过报头和报尾来进行打包。每一次的传输都被封装成为一个载荷
在这里插入图片描述


物理层

当传输到物理层后,将这些打包好的数据转换成2禁止的0 1序列,通过光信号/电信号进行传输。


分用

当数据在传输给目的地(用户B)的时候,会经历一系列的交换机和路由器的转发。
当我们的的数据通过一系列步骤到达用户B后,这时候就需要进行分用解析这个包。
当接收时通过由物理层到应用层的步骤层层解析。

1.物理层

拿到光电信号后转换成二进制的数据,得到以太网的数据报。

2.数据链路层

通过以太网协议对物理层传输过来的数据报进行解析,得到报头和报尾和中间的载荷。

3.网络层

通过IP协议对数据对数据链路层传输过来的数据报进行解析,去掉IP报头得到载荷。

4.传输层

通过UDP协议,针对网络层传输的数据报进行解析,拿到载荷,去掉UDP报头,得到载荷。

5.应用层

根据端口号来负责将数据交给指定的应用程序,然后根据开发者自定义的应用层协议进行解析并显示。


网络编程(网络协议)

在计算机中,通过网络,可以让两个主机之间相互通信,在实现相互通信的过程时,需要我们开发者通过应用程序(应用层)通过系统的API与传输层进行交互。
Socket API这套协议,可以完成不同主机之间,不同系统之间的通信。

在传输层中,提供的网络协议主要由两个,UDP和TCP

UDP和TCP的区别

1.TCP可以进行连接,UPD不可以连接。
在计算机中,通过与双方建立连接,各自保存双方的信息。
如果TCP需要通信,需要建立连接,保存对方信息,才可以进行
UDP无需建立连接,就可以通信(虽然不需要建立连接,但是需要开发者通过socket API来进行对方信息作为参数进行传输)

2.TCP时可靠传输的,UDP时不可依靠传输的
网络通信中,A与B发送消息,消息有可能无法进行传输(传输的概率无法达成100%),可能存在物理干扰。
而可靠传输是当A与B发送消息时,如果发送失败,则需要采取一定的补救措施(重写发送等),这个可靠传输也无法保证必定传达成功,只是尽力补救。
当进行可靠传输时,则必定要付出一定的代价,这样的机制会复杂且传输的效率也会大大降低。

3.TCP是面向字节流的,UDP时面向数据报的
TCP通过以字节为单位进行传输,UDP以数据报为单位进行传输。

4.TCP和UDP都是全双工的
一个信道中,允许双向通信的,就是全双工。
一个信道中,只能单向通信的,就是半双工。

UDP类 API使用

DatagramSocket类

Socket是操作系统中的概念,是系统抽象出来的”文件“,本质Socket是属于网卡
当Socket在写数据时,相当于网卡在发送数据。
当Socket在读数据时,相当于网卡接收数据。

DatagramPacket类

通过此类,表示一个UDP的数据报(UDP面向的是数据报)
每次传输以UDP数据报为基本单位。


实现回显通信程序

编写服务器和客户端的代码通过回显显示在屏幕上
上述内容描述Socket本质是一个网卡,服务器则需要网卡中指定一个端口,但是客户端无须指定端口通过系统直接分配端口,防止程序端口冲突

回显服务器(UDP代码)
package UDPECHO;

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

public class UdpEchoServer {
    private DatagramSocket socket=null;//设置socket网卡
    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);//这里服务器需要指定端口
    }
    public void start() throws IOException {
        System.out.println("Server is Running");
        //这里receive接收客户端的请求,需要准备一个字节数组进行接收
        //这里的while循环只要不倒闭,服务器一直在循环状态
      while(true){
          DatagramPacket requestPacket=new DatagramPacket(new byte[5080],5080);
          socket.receive(requestPacket);
          //这里接收到请求将请求转换为String类型的字符串
          //这里的参数第一个是以字符串形式来获取字节数组,第二个参数表示下标,第三个表示最终的长度
          String request=new String(requestPacket.getData(),0,requestPacket.getLength());
          //对获取到的请求进行响应
          String response=process(request);
          //这里回应后开始准备继续返回给客户端影响的结果
          //这里的参数,第一个将响应继续转换为字节
          //参数2,因为是字符,所以需要转换为字节后在获取长度,如果是UTF-8的汉字则为三个字节
          //参数3,是传送给客户的地址,系统随机推送的地址
          DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
          socket.send(responsePacket);//socket里面的参数就是响应的结果,需要使用一个Packet参数
          //服务器打印的内容
          System.out.printf("[%s:%d] request:%s response:%s\n",requestPacket.getAddress(),requestPacket.getPort(),request,response);
      }
    }

    private String process(String request) {
        //返回响应,我们在程序中大部分都在维护响应中的代码,这里是回显,我们请求是什么响应就是什么
    return  request;
    }

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


回显客户端(UDP代码)
package UDPECHO;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class UdpEchoClient {
    private DatagramSocket socket=null;
    private String serverIp=" ";
    private int serverPort=0;
    public  UdpEchoClient(String ip,int port) throws SocketException {
        socket=new DatagramSocket();//默认随机指定端口
        serverIp=ip;
        serverPort=port;
    }
    public void start() throws IOException {
        System.out.println("Client is Running");
//            输入的内容
        Scanner scanner=new Scanner(System.in);
        while(true){
            System.out.println("Please enter:>");
            String request=scanner.next();//输入的内容
            //这里发送给服务器数据然后服务器进行接收
            //这里指定的是请求的内容长度,还有传送给服务器的IP地址和端口
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //客户端阻塞等待服务器传回来的数据,当服务器进行一系列操作后进行返回,接收服务器返回的
            DatagramPacket responsePacket=new DatagramPacket(new byte[5080],5080);//申请一个字节数组进行接收
            socket.receive(responsePacket);
            //最后将字节数组转换成字符串
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            //打印显示到屏幕中
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
    UdpEchoClient client=new UdpEchoClient("127.0.0.1",8070);
    client.start();
    }
}


TCP API使用

ServerSocket类使用

针对服务器使用的类,来实现网卡,对客户端的请求进行操作,并最终将获取到的响应返回给客户端

Socket类使用

针对客户端的网卡,通过这个网卡来对服务器进行发起请求,并且接收服务器返回的响应,连接这两台机器的端点。


回显服务器(TCP代码)
package 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 {
        ExecutorService thread=Executors.newCachedThreadPool();//创建一个线程池来进行并发执行
        System.out.println("Server is running.....");
      while(true){//多个客户端需要循环
          Socket clientSocket = serverSocket.accept();//通过此方法,将内核中已经建立好的连接拿出来给到Socket类型对象
          //这个方法包含请求回应响应
          thread.submit(new Runnable() {
              @Override
              public void run() {
                  try {
                      connection(clientSocket);
                  } catch (IOException e) {
                      throw new RuntimeException(e);
                  }
              }
          });
      }

    }

    private void connection(Socket clientSocket) throws IOException {
        //对客户端的上线进行日志打印
        System.out.printf("客户端上线Ip:%s,端口:%d\n",clientSocket.getInetAddress(),clientSocket.getPort());
        //这里通过流对象来进行输入和输出,通过try包裹来避免流对象后续的释放
        try(InputStream inputStream=clientSocket.getInputStream();
        OutputStream outputStream=clientSocket.getOutputStream();
            PrintWriter printWriter=new PrintWriter(outputStream)){
        while(true){//一个客户端在运行期间不只接收一次数据,需要循环控制
            Scanner scanner=new Scanner(inputStream);//这里来接收输入的内容
            if(!scanner.hasNext()){
                //这里条件说明客户端退出,下线日志进行打印
                System.out.printf("客户端下线,Ip:%s port:%d\n",clientSocket.getInetAddress(),clientSocket.getPort());
                break;
            }
            //这里对客户端传入给服务器的数据进行解析得到字符串
            String request=scanner.next();
            //对请求的数据进行响应并进行接收
            String response=process(request);
            //1.通过PrintWriter来将response传入给客户端
            printWriter.println(response);
            printWriter.flush();//刷新一下
            System.out.printf("[%s:%d] request:%s,response:%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);


        }
        }finally {
            //最后释放一下clientSocket对象,引用对象如果不释放,容易将文件描述符占满,导致文件泄漏
            clientSocket.close();
        }
    }

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

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


回显客户端(TCP代码)

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

public class TcpEchoClient {
    private Socket socket=null;

    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        //这里的客户端需要与服务器进行连接,这是连接条件,ip和port为与服务器进行连接的条件
        socket=new Socket(serverIp,serverPort);
    }
    public void start() throws IOException {
        System.out.println("Client is Running......");
        Scanner scanner=new Scanner(System.in);
        //防止文件描述泄漏
       try(InputStream inputStream=socket.getInputStream();
           OutputStream outputStream=socket.getOutputStream();
           PrintWriter printWriter=new PrintWriter(outputStream);
           Scanner scannerNetwork=new Scanner(inputStream)){
           while(true){
               //1.输入
               System.out.print("enter:>");
               String request=scanner.next();//客户端控制台输入的内容
               //2.这里将数据发送给客户端
               printWriter.println(request);
               printWriter.flush();
               //3.接收服务器返回的数据
               String response=scannerNetwork.next();
               System.out.println(response);
           }
       }
    }
    public static void main(String[] args) throws IOException {
    TcpEchoClient client=new TcpEchoClient("127.0.0.1",8090);
    client.start();
    }
}

在这里插入图片描述


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

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

相关文章

AIGC视频扩散模型新星:Video 版本的SD模型

大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍慕尼黑大学携手 NVIDIA 等共同推出视频生成模型 Video LDMs。NVIDIA 在 AI 领域的卓越成就家喻户晓,而慕尼黑大学同样不容小觑,…

[Day 15]54.螺旋矩阵(简单易懂 有画图)

今天我们来看这道螺旋矩阵,和昨天发的题很类似。没有技巧,全是循环。小白也能懂~ 力扣54.螺旋矩阵 题目描述: 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: …

用Python绘制一只懒羊羊

目录 一、准备工作 二、Turtle库简介 三、绘制懒羊羊的步骤 1. 导入Turtle库并设置画布 2. 绘制头部 3. 绘制眼睛 4. 绘制嘴巴 5. 绘制身体 6. 绘制四肢 7. 完成绘制 五、运行代码与结果展示 六、总结 在这个趣味盎然的技术实践中,我们将使用Python和Turtle图形…

QT QTreeWidget控件 全面详解

本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…

掌握Spring事务隔离级别,提升并发处理能力

Spring框架支持的事务隔离级别与标准的JDBC隔离级别保持一致,共包括五大隔离级别,它们分别是:DEFAULT(默认隔离级别)、READ_UNCOMMITTED(读未提交)、READ_COMMITTED(读已提交&#x…

Vue基础(2)

19、组件之间传递数据 组件与组件之间不是完全独立的&#xff0c;而是有交集的&#xff0c;那就是组件与组 件之间是可以传递数据的 传递数据的解决方案就是 props ComponentA.vue <template><!-- 使用ComponentB组件&#xff0c;并传递title属性 --><h3>…

Git知识分享

一、理解git首先要理清楚下面五个概念&#xff1a; 1、工作区(git add 命令之前的样子) 2、stash 暂存(暂存工作区和暂存区的更改) 3、暂存区(git add 命令之后的存储区, 4、本地仓库(git commit提交的位置) 5、远程仓库(git push提交的位置) 二、git常用命令&#xff1a; 1、g…

【2024 - 年终总结】叶子增长,期待花开

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言论博客创作保持2024的记录清单博客科研开源工作生活 总结与展望互动致谢参考 前言…

分类问题(二元,多元逻辑回归,费歇尔判别分析)spss实操

分类模型&#xff1a; 二分类和多分类&#xff1a; 对于二分类模型 &#xff0c;我们将介绍逻辑回归和Fisher线性判别分析两种分类算法; 对于多分类模型&#xff0c;我们将简单介绍Spss中的多分类线性判别分析和多分类逻辑回归的操作步骤 二分类: 基于广义线性模型&#x…

k8s使用nfs持久卷

开启持久化卷后可以实现服务开启在不同节点也能读取到和拿到服务节点的文件。 基本流程为将集群中一个节点作为服务节点安装共享储存应用的服务端选择目录和开启端口&#xff0c;其他节点根据端口挂载目录。然后使用kubesphere选择相应的镜像并将端口信息和挂载目录信息作为参…

kalman滤波器C++设计仿真案例

很多同学看了我之前的文章&#xff0c;都对kalman滤波器的原理有了理解&#xff0c;但我发现&#xff0c;在具体工程设计过程中&#xff0c;还是很多人都感觉到无从下手&#xff0c;一些参数也不知道如何选取。 这样吧。我这里举一些简单的例子&#xff0c;并用C来一步一步的进…

2025.1.21——六、BUU XSS COURSE 1 XSS漏洞|XSS平台搭建

题目来源&#xff1a;buuctf BUU XSS COURSE 1 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;输入框尝试一下 step 2&#xff1a;开始xss注入 step 3&#xff1a;搭建平台 step 4&#xff1a;利用管理员cookie访问地址 三、小结 二编&#…

微信小程序使用上拉加载onReachBottom。页面拖不动。一直无法触发上拉的事件。

1&#xff0c;可能是原因是你使用了scroll-view的标签&#xff0c;用onReachBottom触发加载事件。这两个是有冲突的。没办法一起使用。如果页面的样式是滚动的是无法去触发页面的onReachBottom的函数的。因此&#xff0c;你使用overflow:auto.来使用页面的某些元素滚动&#xf…

Linux-arm(1)ATF启动流程

Linux-arm(1)ATF启动流量 Author&#xff1a;Once Day Date&#xff1a;2025年1月22日 漫漫长路有人对你微笑过嘛… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档&#xff1a; ARM Trusted Firmware分析——启动、PSCI、OP-TEE接口 Arnold Lu 博…

docker 部署 java 项目详解

在平常的开发工作中&#xff0c;我们经常需要部署项目&#xff0c;开发测试完成后&#xff0c;最关键的一步就是部署。今天我们以若依项目为例&#xff0c;总结下部署项目的整体流程。简单来说&#xff0c;第一步&#xff1a;安装项目所需的中间件&#xff1b;第二步&#xff1…

ARM64平台Flutter环境搭建

ARM64平台Flutter环境搭建 Flutter简介问题背景搭建步骤1. 安装ARM64 Android Studio2. 安装Oracle的JDK3. 安装 Dart和 Flutter 开发插件4. 安装 Android SDK5. 安装 Flutter SDK6. 同意 Android 条款7. 运行 Flutter 示例项目8. 修正 aapt2 报错9. 修正 CMake 报错10. 修正 N…

MySQL5.7安装超详细步骤(图文教程)

一.下载MySQL 1.在浏览器搜索MySQL&#xff0c;进入MySQL官网&#xff0c;点击下载&#xff0c;选下面的社区版本。 官网地址&#xff1a;MySQL :: Download MySQL Installer (Archived Versions) 二.安装MySQL 1.双击下载好的文件&#xff0c;选择自定义安装&#xff0c;然…

Tomcat下载配置

目录 Win下载安装 Mac下载安装配置 Win 下载 直接从官网下载https://tomcat.apache.org/download-10.cgi 在圈住的位置点击下载自己想要的版本 根据自己电脑下载64位或32位zip版本 安装 Tomcat是绿色版,直接解压到自己想放的位置即可 Mac 下载 官网 https://tomcat.ap…

语音转文字的先驱-认识Buzz的前世今生

Buzz 是一款基于 OpenAI Whisper 模型开发的开源语音转文字工具&#xff0c;其历史可以追溯到 Whisper 模型的推出&#xff0c;并在之后逐渐发展为一个功能强大且广泛使用的工具。以下是关于 Buzz 的详细历史介绍&#xff1a; 1. Whisper 模型的背景 Buzz 的核心是 OpenAI 开…

WPF5-x名称空间

1. x名称空间2. x名称空间内容3. x名称空间内容分类 3.1. x:Name3.2. x:Key3.3. x:Class3.4. x:TypeArguments 4. 总结 1. x名称空间 “x名称空间”的x是映射XAML名称空间时给它取的名字&#xff08;取XAML的首字母&#xff09;&#xff0c;里面的成员&#xff08;如x:Class、…