网络编程:掌握TCP Socket和UDP Socket

news2024/9/27 18:15:13

IP地址:

两台计算机通信,双方都必须有IP地址。

IPV4地址有32位,由四个8位二进制组成,因为不好记所以我们把二进制转化为十进制,比如192.168.0.20,这称为点分十进制。

IPV6有128位,由8个16位的无符号整数组成,每个整数用4个十六进制数表示,这些数之间用冒号(:)分开。

IP地址的分类:

IP地址 = 网络地址 +主机地址

网络地址决定网络数

主机地址决定了一个网络中可以存在的计算机最大数量

A类IP地址:前八位表示网络地址,取值范围1-126

B类IP地址:前十六位表示网络地址,取值范围128-191

C类IP地址:前三组表示网络地址,取值范围192-223

D类IP地址:不分网络地址和主机地址, 用于多播(Multicast)。多播通信是一种将数据包发送到多个特定接收者的方式,而不是广播给网络上的所有设备。常用于视频会议、流媒体传输等应用。

特殊的IP地址:

0.0.0.0表示主机

127.0.0.1表示本机回环地址,通常用于本机ping此地址来检查TCP/IP协议安装是否正确

255.255.255.255表示当前子网

IP地址的配置和检测:

查看本机的IP地址:
ipconfig

测试网络是否通畅:

ping  目标IP地址

DNS域名解析(域名系统):

访问网站时,为什么输入网址而不是IP地址?

因为ip地址都是数字,人们输入的时候太枯燥,所以需要一个系统将一个名称映射为它的IP地址,DNS域名解析系统。

网络通信协议:

TCP/IP:五层

首先应用层准备好要发送的数据,然后给了传输层。

传输层的主要作用就是为发送端和接收端提供可靠的连接服务,传输层将数据处理完后就给了网络层。

网络层的功能就是管理网络,其中一个核心的功能就是路径的选择(路由选择),从发送端到接收端有很多条路,网络层就负责管理下一步数据应该到哪个路由器。选择好了路径之后,数据就来到了数据链路层,

数据链路层就是负责将数据从一个路由器送到另一个路由器。然后就是物理层了,可以简单的理解,

物理层就是网线一类的最基础的设备。

TCP协议:

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议

例子:

发货之前工作人员首先得要确认一下路是不是通吧,比如现在是过年,物流全部停运不就是路不通吗,那还发什么货呀。要是没什么问题,物流全部正常运作就发货呗。手机到达小明家后,小明先拆开看看手机在运输途中有没有损坏,有损坏就联系客服处理,没问题就确认收货。再回到上面的定义中,面向连接指的是先建立连接再发送数据,也就是先确认路可以走得通再发货。可靠就是如果货物在运输过程中有损坏或者丢失就让京东重新发货,确保小明收到的手机是没有任何问题的。基于字节流的意思就是比如小明买了手机又买了手机配件,分开发货,几件物品不是在一个包裹里,一个一个发。在这个例子中,京东的工作人员和小明充当了TCP协议的角色,他们两个共同确保了货物的完整性。

总结:确定是通的,如果丢失就重新再发,数据是以字节流的方式传送的。

建立连接 接收数据 发送数据

三次握手四次挥手:

三次握手:

A:是B吗?我要跟你通信,听得到我说话吗?

B:可以通信,你听得到我说话吗?

A:我也听得到。

之所以挥手三次是为了防止丢包的链接被服务端等待

四次挥手:

A:我困了,先不聊了吧

B:还有几件事,说完我们就睡觉…… ……(说完之后)

B:好了,说完了,我挂线了

A:好,你挂吧

B挂断电话

A说完之后就直接睡觉了,不知道电话挂没挂断,在几分钟后听到手机没有声音传来了,即使不用睁眼也知道B挂断了

四次挥手如图:

之所以还需要最后的ack发送后还需要等待,是因为服务端需要收到后才可以断开连接,所有如果ack丢失的话服务端可以再给客户端发一次。

UDP协议:

面向无连接的

TCP和Socket:

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通信之前要保证连接已建立。

通过Socket产生I/O流来进行网络通信。

客户端:

public class Socket01 {
    public static void main(String[] args) {
        Socket socket =null;
        OutputStream os =null;
        //客户端
        try {
            socket = new Socket("127.0.0.1",8888);
            //创建输出流
             os = socket.getOutputStream();
            os.write("chenmengyu Hello".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                os.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务器端:

首先要运行接收端,不然发送端连接不上就不会发送数据

Socket s = ss.accept();会一直等待发送端的连接,死等

第一种:循环的接收

不需要字符串了,但是缺点是只能够传输字母,不能传中文

public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream =null;
        try {
            //创建serverSocket
             serverSocket = new ServerSocket(8888);
            //监听客户端获取socket对象
             socket = serverSocket.accept();
            //获取输出流
             inputStream = socket.getInputStream();
            int read;
            while ((read=inputStream.read())!=-1){
                System.out.print((char)read);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                serverSocket.close();
                socket.close();
                inputStream.close();

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

第二种数组接收:

byte b[] = new byte[100];

String str = new String(b);

用byte数组接收再转成字符串输出

public class Socket02 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream =null;
        try {
            //创建serverSocket
             serverSocket = new ServerSocket(8888);
            //监听客户端获取socket对象
             socket = serverSocket.accept();
            //获取输出流
             inputStream = socket.getInputStream();
           byte b[] = new byte[100];
           inputStream.read(b);
           String str = new String(b);
           System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                serverSocket.close();
                socket.close();
                inputStream.close();

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

TCP传输序列化对象:

客户端:
public class ObjSocket01 {
    public static void main(String[] args) {
        //客户端

        Socket socket = null;
        OutputStream os = null;
        ObjectOutputStream objectOutputStream = null;
        try {
             socket = new Socket("127.0.0.1",8888);
             os = socket.getOutputStream();
             objectOutputStream = new ObjectOutputStream(os);
             objectOutputStream.writeObject(new Student("陈梦雨",21));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                socket.close();
                os.close();
                objectOutputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

服务器端:

readObject()方法的作用是从输入流中读取一个序列化的对象,并将其转换为Java对象。它会返回一个Object类型,通常需要进行类型转换

public class ObjSocket02 {
    public static void main(String[] args) {
        ServerSocket socket = null;
        InputStream inputStream = null;
        ObjectInputStream ois = null;
        try {
             socket = new ServerSocket(8888);
             //监听客户端
            Socket socket1 = socket.accept();
            //获取输入流
             inputStream= socket1.getInputStream();
             //创建一个反序列化对象,并且把输入流当参数放进去
             ois = new ObjectInputStream(inputStream);
             //readObject()方法则从流中读取对象并将其转换为Student类型的实例
             Student stu= (Student)ois.readObject();
            System.out.println(stu.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

例题:多客户端用户登录:

TCP的Socket和多线程联动

需要创建子线程的是服务端,它创建多个子线程去处理客户端发送的东西

不使用多线程:

就是用while(true)使服务端一直等一直监听

服务器端:

package QuestionPpt02;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class demo01 {
    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket socket = null;
        //服务器端
        try {
            serverSocket = new ServerSocket(8888);
             socket = new Socket();
             while(true){
                 //监听
                 socket = serverSocket.accept();
                 InputStream is = socket.getInputStream();
                 byte b[] = new byte[50];
                 is.read(b);
                 String msg = new String(b);
                 System.out.println(msg);

             }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

客户端:


public class demoCelint01 {
    public static void main(String[] args){
      //客户端1
        System.out.println("客户端01————————————");

        try {
            Socket socket = new Socket("127.0.0.1",8888);
            OutputStream os = socket.getOutputStream();
            os.write("用户名:张三".getBytes());
            os.close();
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
使用多线程:

它的客户端和上面一样

服务端主线程:

通过构造方法传入监听过来的socket对象,然后进入子线程

package QuestionPpt02;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class demo02 {
    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket socket = null;
        //服务器端
        try {
            serverSocket = new ServerSocket(8888);
            socket = new Socket();
            while(true){
                //监听
                socket = serverSocket.accept();
               //一旦有用户来就创建一个子线程
                ThreadTest threadTest = new ThreadTest(socket);
                threadTest.start();
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

服务端子线程:

package QuestionPpt02;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ThreadTest extends Thread{

    private Socket socket;

    public  ThreadTest(Socket socket){
        this.socket = socket;

    }

    //服务端创建子线程
    @Override
    public  void run(){

        try {
            InputStream is = null;
            is = socket.getInputStream();
            byte b[] = new byte[50];
            is.read(b);
            String msg = new String(b);
            System.out.println(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

UDP和socket:

DatagramSocket:用来发送和接收数据包

DatagramPacket:用来装包和拆包

dp.getData()拆包

ds.send(dp);发送包

基于UDP协议的sokect实现

发送端(客户端):

DatagramPacket的构造方法最常用的,接收(发送内容的比特数组,数组长度,地址对象,端口号)

InetAddress.getByName("127.0.0.1")是一个地址对象,反正这里不能直接填地址

public class LoginCelint {
    //客户端
    public static void main(String[] args) {
        System.out.println("我是客户端---------------");
        //发送信息
        Scanner scanner = new Scanner(System.in);
        DatagramPacket dp = null;
        DatagramSocket ds = null;

        try {
            
                System.out.print("客户端请输入:");
                String msg = scanner.nextLine();
                dp = new DatagramPacket(msg.getBytes(),
                        msg.getBytes().length,
                        InetAddress.getByName("127.0.0.1"),
                        8888);

                ds = new DatagramSocket();
                ds.send(dp);
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            ds.close();

        }
    }
}

接收端(服务器):
  1. 一定要先运行接收方, 在 UDP 通信中,接收方需要在指定的端口上监听和等待数据包

DatagramPacket的构造方法(byte数组,数组长度)

  1. String msg = new String(dp.getData());先 获取DatagramPacket中存储的数据的字节数组。再转成String
public class LoginServer {
    //服务器
    public static void main(String[] args) {
        System.out.println("我是服务端——————————");
        Scanner scanner = new Scanner(System.in);
        DatagramPacket dp = null;
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(8888);
                byte b[] = new byte[100];
                dp = new DatagramPacket(b, b.length);

                //等待接收
                ds.receive(dp);
                //拆包
                String msg = new String(dp.getData());
                System.out.println("客户端对我说:" + msg);
          

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            ds.close();
        }

    }
}

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

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

相关文章

Splashtop 自收购 Foxpass 以来新业务增长62%

2024年9月24日 加利福尼亚州库比蒂诺 Splashtop 在简化远程办公解决方案领域处于领先地位,今天宣布继去年收购 Foxpass 之后,新的 Foxpass 业务实现了62%的增长。Splashtop 的 Foxpass Cloud RADIUS 可确保企业 Wi-Fi 网络安全,防止未经授权…

牛羊饲料加工机械成套设备:满足养殖需求

饲料加工机械成套设备在畜牧业中扮演着至关重要的角色,是保障畜禽健康成长和畜牧业发展的重要基础。这些设备通过配料、粉碎、混合等步骤,生产出不同畜禽需求的饲料,为畜牧业的可持续发展提供了有力支持。 饲料加工机械成套设备是牛羊养殖场…

机器学习常用的评价指标原理和代码

最近面试的时候,很多面试官问道了我项目中的一些评价指标的算法和原理,我觉得这确实也是一个很重要的内容,所以趁这个机会综合起来一块复习一下,在刷力扣的时候也不能忘记项目最常用的内容嘛。当然还包括一些深度学习的例如我项目…

OJ在线评测系统 判题机开发 保证Docker容器执行的安全性

实现Docker容器的安全性 我们现在怎么保证使用docker容器执行的安全性? docker只不过实现了系统与系统之间的隔离 真实情况还是需要我们去排查安全问题 毕竟没有绝对的安全 执行超时 占用内存 读文件信息泄露 执行死程序 超时设置 执行容器的时候 增加超时参…

FileLink跨网文件交换:高效、安全、灵活的企业文件传输新方案

在当今数字化时代,企业间的数据交流与协作已成为推动业务发展的关键要素。然而,网络边界的存在往往成为文件传输的障碍,尤其是跨网络环境的文件交换,更是面临诸多挑战。为了打破这一瓶颈,FileLink跨网文件交换系统应运…

《动手学深度学习》笔记2.1——神经网络从基础→进阶 (层和块 - 自定义块)

目录 0. 前言 原书正文(第五章) 第五章 - 第一节 - 层和块 - 自定义块 1. Sequential() PyTorch高级API 2. MLP() 无传入参数 3. MySequential() 传入任意层(块) 4. FixedHiddenMLP() 无传入参数-固定隐藏层 5. NestMLP() 传入嵌套块-多次嵌套 …

GPU共享技术深度剖析与总结

在人工智能和深度学习领域,GPU(图形处理器)已成为不可或缺的计算工具。随着深度学习模型的规模和复杂性的增加,单个GPU已经难以满足所有训练需求,GPU共享技术应运而生,成为提高训练效率的重要手段。本文将深…

【十八】MySQL 8.0 新特性

MySQL 8.0 新特性 目录 MySQL 8.0 新特性 概述 简述 1、数据字典 2、原子数据定义语句 3、升级过程 4、会话重用 5、安全和账户管理 6、资源管理 7、表加密管理 8、InnoDB增强功能 9、字符集支持 10、增强JSON功能 11、数据类型的支持 12、查询的优化 13、公用…

SQL进阶技巧:如何计算块熵?

目录 0 信息量定义 信息熵 1 块熵定义 2 问题描述 ​3 数据准备 4 问题分析 5 小结 想要进一步了解SQL这门艺术语言的,可以订阅我的专栏数字化建设通关指南,将在该专栏进行详细解析。专栏 原价99,现在活动价39.9,按照阶梯式…

240927-各种卷积最清晰易懂blender动画展示

240927-一些常用卷积清晰易懂的blender动画展示(Conv、GConv、DWConv、1*1Conv、Shuffle) 在几个月前,写过一篇关于卷积过程中输入图像维度变化的博客240627_关于CNN中图像维度变化问题_图像的尺寸为什么又四个维度-CSDN博客,但是…

新手教学系列——在MySQL分表中批量调整表结构的实践与优化

在当今的互联网业务中,随着数据量的不断增长,单个数据库的处理能力往往难以满足高并发、高性能的要求。因此,分库分表已经成为解决数据库扩展性问题的主流方案之一。然而,分表虽然能有效提升数据库的读写性能,但也带来了一个新的挑战:当业务需求变化时,需要对大量分表进…

【DAY20240927】经典深度学习模型对比:LeNet5、CNN、ResNet20、AlexNet、TextCNN 与 VGG-11

文章目录 前言一、LeNet5二、CNN三、AlexNet四、ResNet20五、TextCNN六、VGG-11 前言 We leverage 6 models to deal with the data, i.e., LeNet5 (LeNet) (LeCun et al. 1989), a synthetic CNN network (CNN), ResNet20 (ResNet) (He et al.2016), AlexNet (Krizhevsky, Su…

矿山、石场重型机械设备数据集-挖掘机-自卸卡车-轮式装载机

描述 本项目旨在创建一个高效的计算机或机器视觉模型,用于在建筑工地检测不同种类的施工设备,我们从三个类别开始:挖掘机、卡车和轮式装载机。 数据集的理学硕士提供。 原始图像(v1)包含: 1,532个标注…

Git的安装 + 基本操作

一、Git初识 1. 提出问题 ​ 不知道你在工作或学习中,有没有遇到这样的情况:我们在创建并编写各种文档时,为了防止文档丢失,更改失误,失误后能恢复到原来的版本,不得不复制出一个一个的副本,保…

中东电商:下一个蓝海,Google Cloud和Google Maps助力企业乘风破浪

随着“一带一路”倡议的深入推进,中东地区已成为全球瞩目的新兴市场。庞大的年轻消费群体、丰富的石油资源以及不断完善的数字基础设施,为中国企业提供了前所未有的发展机遇。中东电商市场,无疑是下一个蓝海! 中东电商市场&#x…

学日语必备神器!这4款翻译APP你用过吗?

小伙伴们,你们有没有在日常生活或工作中遇到过需要翻译日语的场景呢?无论是阅读日本原著、工作文档还是和日本小伙伴交流,一个好的翻译工具绝对能成为你的贴心小助手;今天,我就来跟大家分享几款我个人非常喜欢的日语翻…

开放原子超级链内核XuperCore可搭建区块链

区块链是一种分布式数据库技术,它以块的形式存储数据,并使用密码学方法保证数据的安全性和完整性。 每个块包含一定数量的交易信息,并通过加密链接到前一个块,形成一个不断增长的链条。 这种设计使得数据在网络中无法被篡改,因为任何尝试修改一个块的数据都会破坏整个链的…

鼎阳加油-IOC关键技术问题的解决记

鼎阳SDS6204示波器EPICS IOC的搭建-CSDN博客 这款示波器在labview下工作的很好,以前搭建逐束团3D系统时连续几个月不间断的工作连接从没断过线,并做过速率测试,单通道时10Hz的波形更新速率都可以达到: 鼎阳SDS6204示波器波形读取…

hive分区详细教程

为什么要分区? 为了提高sql的查询效率 比如: select * from orders where create_date20230826; 假如数据量比较大,这个sql就是全表扫描,速度肯定慢。 可以将数据按照天进行分区,一个分区就是一个文件夹,当…

C++之STL—常用算术生成算法

#include <numeric> accumulate(iterator beg, iterator end, value); // 计算容器元素累计总和 // beg 开始迭代器 // end 结束迭代器 // value 起始值 fill (iterator beg, iterator end, value); // 向容器中填充元素 // beg 开始迭代器 // end 结束迭代器 // val…