[网络编程】网络编程的基础使用

news2024/11/13 12:44:09

系列文章目录

1、 初识网络


网络编程套接字

  • 系列文章目录
  • 前言
  • 一、TCP和UDP协议的引入
  • 二、UDP网络编程
    • 1.Java中的UDP
    • 2.UDP回显代码案例
    • 3.UDP网络编程的注意事项
  • 三、TCP网络编程
    • 1.TCP回显代码案例
    • 2.TCP多线程使用
  • 总结


前言

在学习完基础的网络知识后,完成跨主机通信的网络编程。


一、TCP和UDP协议的引入

注意:TCP协议并非TCP/IP模型。
TCP和UDP都属于传输层协议中的一种,为应用层提供服务。但是二者之间的特点和差异都很大,因此有了两套API分别应用于二者。
特点:
TCP:有连接,可靠传输,面向字节流,全双工
UDP:无连接、不可靠传输、面向数据报、全双工

其中有连接的意思是如同打电话一样,在电话接通以后才能相互通信;无连接就像发送短信,不需要“先接通”,允许直接发送。
可靠传输的意思是将要传输的数据尽可能传输给对方,不可靠传输的意思是在数据传输时不关心对方是否收到信息。
面向字节流,和文件操作中的字节流类似,读写操作十分灵活。
面向数据报:在UDP协议中,传输数据的基本单位时一个个UDP数据报,一次读写只能读写一个完整的UDP数据报。
全双工:在一条链路中能够进行双向通信;半双工:一条链路中只能进行单向通信。

二、UDP网络编程

1.Java中的UDP

在Java中,引入系统的API(称为Socket API)并进行封装,在Java中主要有两个类:DatagramSocket和DatagramPacket。
1)DatagramSocket:socke可以理解为是一种文件,socket文件可以视为对网卡的硬件设备进行的抽象化。在UDP中对于操作系统中socket概念的封装,针对该对象进行读写操作,也可以理解为对网卡硬件设备的操作。
2)DatagramPacket: 针对UDP数据报的一个抽象表示,一个DatagramPacket对象,就相当于一个UDP数据报。一次发送/接收就相当于传输了一个DatagramPacket对象。

2.UDP回显代码案例

所谓回显代码,即客户端请求什么内容,服务器就返回什么代码。回显代码中没有实现复杂的逻辑,能够最简单的反映UDP的服务器和客户端之间的互动情况。

  1. UDPEchoServer:在Server端,端口号是固定的,DaragramSocket 在构造方法中传入端口号。在服务器启动之后需要不断接收请求和返回请求值。
    在DatagramSocket中的receive方法负责接收客户端发送过来的请求, 将接收到的数据转换成字符串request,作为后面处理请求的参数。通过方法process运行之后返回的结果需要数据报进行封装,因此在结果返回之后,新建一个数据报对象并将字符串结果转换成字节流。通过socket.send方法发送。
public class UdpEchoServer {
    DatagramSocket socket = null;
    public UdpEchoServer(int port) throws SocketException {
         socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true) {
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            String response = this.process(request);
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req = %s,res = %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(9090);
        server.start();
    }
}
  1. UDPEchoClient:在客户端,用户发起请求并接收返回的结果。对服务器发送的信息应该包括用户IP地址、用户端口号的信息。通过DatagramSocket类中的send方法发送请求。
    在start()方法中,新建字符串request来保存用户所发送的请求,由于网卡的的性质需要发送数据报格式。为了解决这个问题,我们需要new一个数据报requestPacket对请求内容进行封装。同时我们需要把字符串的数据转换成字节流的数据。
    INetAddress中的getByName方法中存储着服务器的IP地址以及服务器的端口号。
    在发送请求之后等待数据接收状态下,receive()方法进入阻塞状态。
    在接收到数据之后,将字节流数据转换成字符串的形式,用response接收。
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

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

    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("请输入要发送的请求:");
            String request = scanner.next();
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            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",9090);
        client.start();
    }
}

最终,我们成功完成了UDP中基础的数据请求与通信。


3.UDP网络编程的注意事项

  1. 在上面的UDP编程中,主要可以分为以下几个步骤(如下图所示)
    在这里插入图片描述
  2. 进程的运行顺序是先启动服务器,再启动客户端。
  3. 在代码编写过程中,都没有涉及到close操作的原因:DatagreamSocket作为这个进程的对象和服务器程序的生命周期是一样的。如果在某个程序中,socket对象的生命周期和进程不一样,需要提前释放的话就需要进行close操作。

三、TCP网络编程

在TCP中的socket api中与UDP不同的是,在TCP中ServerSocket类是专门给服务器使用的。 Socket类是专门作用于客户端和服务器之间进行通信使用的。
由于TCP属于有连接和可靠传输,他们之间必须时刻保持通信状态。在ServerSocket中有accept方法接收客户端发来的请求。

1.TCP回显代码案例

我们知道TCP是面向字节流的,因此在TCP中的操作是以流对象进行操作的。

  1. 在Socket类中,通过两个方法:getInputStream和getOutpurStream 进行操作的。
  2. 在服务器中,start方法中通过accept同意客户端连接。接下来调用processConnection
  3. 使用Scanner读取InputStream流中的数据内容。
  4. 使用Scanner的好处是对于客户端传输进来的字节流,Scanner会自动将这些数据转换成String。
  5. 在方法start中,循环保持与客户端之间的通信。通过scanner.hasNext()方法判断是否还有输入,当客户端关闭了连接之后,服务器的输入流会收到一个EOF信号,从而判断出没有输入了,最终结束循环。
  6. 将回显的结果以response的结果以二进制的形式写入outputStream中。
  7. 最后,处理完client的请求之后,客户端下线之后,回收client对象,当下次重新有新的客户端时重新启用。
public void start() throws IOException {
        System.out.println("服务器启动!");
        //accept可以阻塞等待
        Socket socketClient = serverSocket.accept();
        processConnection(socketClient);
    }
    
private void processConnection(Socket socketClient) throws IOException {
        System.out.printf("[%s:%d] 客户端上线\n", socketClient.getInetAddress(),socketClient.getPort());
        try(InputStream inputStream = socketClient.getInputStream();
            OutputStream outputStream = socketClient.getOutputStream()) {

            Scanner scanner = new Scanner(inputStream);

            while (true) {
                if (!scanner.hasNext()) {
                    System.out.printf("[%s:%d] 客户端下线\n", socketClient.getInetAddress(),socketClient.getPort());
                    break;
                }
                //接收客户端发送过来的请求
                String request = scanner.next();
                //处理请求
                String response = process(request);
                //把响应写回客户端
                outputStream.write(response.getBytes(),0,response.getBytes().length);
                //服务器打印日志
                System.out.printf("[%s:%d] req = %s resp = %s",socketClient.getInetAddress(),socketClient.getPort(),request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            socketClient.close();
        }
    }

在客户端方面,通过scannerNetWork读取inputStream中的数据。将请求的内容以二进制的形式写入outputStream中。当服务器关闭后,scannerNetWork传入服务器的EOF信号,代表着双方连接中断,因此可以退出循环结束进程。

public void start() {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);

        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {

            Scanner scannerNetWork = new Scanner(inputStream);

            while (true) {
                System.out.println("输入要发送的数据");
                //1.读取数据
                String request = scanner.next();
                //2.将request作为请求发送到服务器中,通过\n标识请求内容
                request += "\n";
                outputStream.write(request.getBytes());
                //3.读取服务器返回的响应
                if (!scannerNetWork.hasNext()){
                    break;
                }
                String response = scannerNetWork.next();
                System.out.println(response);

            }

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

    }

2.TCP多线程使用

在上面的TCP回显代码中,并不能使用于多线程的形势下。在服务器中,应当有线程池之类的多线程状态中,同时处理多个客户端发送过来的请求。
因此需要对服务器实现多线程解决问题。通过线程池的方式,while循环中不断接收客户端发来的连接请求,并将任务交予线程池解决。

public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService pool = Executors.newCachedThreadPool();
        //accept可以阻塞等待
        while (true) {
            Socket socketClient = serverSocket.accept();

            pool.submit(new Runnable() {
                @Override
                public void run() {
                    try{
                        processConnection(socketClient);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }

总结

在本文中主要讲解了TCP和UDP两个协议之间的区别;同时对UDP网络编程进行了最基础的创建。
源码☞本文源码

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

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

相关文章

关于 OSPF LSA 序列号范围 0x80000001-0x7FFFFFFF 释疑正本清源

注:机翻,未校对。 正本:RFC 2328 OSPF Version 2 中相关解释 April 1998 12.1.6. LS sequence number 12.1.6. 序列号 The sequence number field is a signed 32-bit integer. It is used to detect old and duplicate LSAs. The space …

set,map(java)

前言:要了解set和map,首先需要对搜索树和哈希有一定的了解,才能进一步深入的了解set和map。 1.搜索树 (1)性质: 若它的左子树不为空,则左子树上所有节点值都小于根节点的值。 若它的右子树不…

事件如何驱动图表运行

状态流图如何响应事件 Stateflow图表仅在以循环方式响应事件时执行。 由于图表在单个线程上运行,因此基于事件发生的操作对该事件是原子性的。图表中由事件引起的所有活动都在执行返回到接收事件之前发生的活动之前完成。一旦事件启动了一个操作,除非被…

全网最全程序员接单网站

程序员客栈-领先的程序员自由工作平台-程序员兼职 (proginn.com) 闲鱼 - 闲不住,上闲鱼! (goofish.com) 猪八戒网-品质企业服务 就找猪八戒 (zbj.com) 电鸭社区-专注远程工作招聘交流-远程工作,从电鸭开始 (eleduck.com) 开源众包-百万开发者…

Java台球厅助教教练预约上门到店系统源码

🎱一杆在手,天下我有!台球助教教练预约系统,让球技飙升不是梦🚀 🎯【开篇:台球爱好者的福音来啦!】🎯 还在为找不到合适的台球教练而烦恼吗?或是想要在家就…

代码实践思考:C++和Python

起因 在人工智能工具日益强大的今天 如何更高效的进行代码学习 如何借助智能工具实现代码转换? 是否直接可以使用?为何? 如何实现不同的编程语言之间代码的无损转换? x86与arm C 云课五分钟-02第一个代码复现-终端甜甜圈C-CS…

GEE错误——文件导出的时候出现Error: User memory limit exceeded. (Error code: 3)

错误简介 在试图将我的表导出到资产文件夹,但出现了内存错误。我不知道我做错了什么。相同的脚本适用于其他年份。文件导出的时候出现Error: User memory limit exceeded. (Error code: 3) 函数 reduceToVectors(reducer, geometry, scale, geometryType, eightConnected,…

雪花算法的一些问题解析

前言 最近做项目,有些老旧项目,需要生成分布式唯一ID,不允许重复,此时如果要对其他中间件和数据库依赖小,那么就需要一套固定的ID生成规则,雪花算法就正当合适,当时Twitter就是用来存储数据库I…

服务器主机安全有多重要

一、什么是主机安全 主机安全,作为维护计算机系统核心安全的基石,旨在全面捍卫硬件与软件免受任何未经授权的侵扰、篡改、数据泄露等安全挑战。这一过程不仅聚焦于数据存储与处理的保密性、完整性及可用性,还深入至硬件构造、固件层、以及系…

利用C++11的异步操作实现一个线程池

利用C11的异步操作实现一个线程池 利用C11的异步操作实现一个线程池 介绍关于一些代码细节的解释测试 介绍 基于线程池执行任务的时候,入口函数内部执行逻辑是固定的,因此选择std::packaged_task加上std::future的组合来实现。 具体使用可以见我上一…

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)即将召开!

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)将于2025年1月10日-12日在中国香港举行。图像处理和机器视觉作为当代信息技术领域的重要分支,不仅推动了人工智能技术的飞速发展,也为各行各业带来了革命性的变革。本次会议旨在汇聚全球图像处理和机器…

极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

目录 极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图 一、环境要求 二、初识Vue Flow 2.1、安装Vue Flow 2.2、Vue Flow构成 2.3、一个小坑 2.4、入门案例 三、Vue Flow优秀的自定义功能 3.1、引入 3.2、节点与连线的自定义 ①打样(…

MySQL - 通过SQL语句导出数据到CSV文件

在 MySQL 中,可以使用 SELECT ... INTO OUTFILE 语句将查询结果导出为 CSV 文件,然后再将 CSV 文件转换为 Excel 格式。以下是一个示例: SELECT column1, column2, column3 INTO OUTFILE /path/to/file.csv FIELDS TERMINATED BY , ENCLO…

git 迁移仓库的方法

git Git是一个开源的分布式版本控制系统,由Linus Torvalds在2005年创建,用于有效、高速地处理从小到大的项目管理。它最初是为Linux内核开发而设计的,但很快被广泛用于各种项目。 以下是Git的一些主要特性: 分布式架构&#xff…

接近传感器 - 从零开始认识各种传感器【第十七期】

1、什么是接近传感器 接近传感器常被用于检测物体的距离或者是否有物体靠近。它通常发射电磁场或电磁波(例如红外线)来探测物体的位置。当有物体靠近时,传感器会接收到反射的电磁波信号,从而触发相应的电路或者控制系统。它广泛应…

Helm(二)

一、Chart模板流程控制if_with_range 1.if 修改values.yaml cat > values.yaml <<EOF myname: yeunyi service: type: ClusterIP port: 80 myport: 8080 EOF 修改service.yaml cat > templates/service.yaml <<EOF apiVersion: v1 kind: Service met…

TC8:SOMEIP_ETS_007-008

SOMEIP_ETS_007: echoBitfields 目的 检查位字段是否能够被顺利地发送和接收。 测试步骤 Tester:创建SOME/IP消息Tester:使用method echoBitfields发送SOME/IP消息DUT:返回method响应消息,其中位字段的顺序与请求相比是反向的期望结果 3、DUT:返回method响应消息,其中位…

微软蓝屏”事件暴露了网络安全哪些问题?

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

探秘数字孪生技术在智慧校园的应用

在当今教育信息化的浪潮中&#xff0c;数字孪生技术逐渐成为智慧校园建设的重要助推器。这一技术通过构建真实世界的数字化映像&#xff0c;不仅提升了校园管理的效率&#xff0c;更为师生的日常学习生活提供了全新的体验。首先&#xff0c;数字孪生可以将校园内的各类设施、环…

七夕告白攻略:天使智能体教你如何设计完美表白卡片!独属程序员地浪漫!

文章目录 &#x1f495;七夕浪漫告白天使&#x1f495;&#x1f495;浪漫风格的表白卡片设计&#x1f495;&#x1f495;甜蜜风格的表白卡片设计&#x1f495;&#x1f495;温馨风格的表白卡片设计&#x1f495;&#x1f495;幽默风格的表白卡片设计&#x1f495;&#x1f495;…