网络编程套接字Socket(通过两个用例,逐行注释,详细理解)干活满满建议收藏

news2024/11/20 7:20:40

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 1.分类
    • 1.流套接字
    • 2.数据报套接字
    • 3.原始套接字
  • 2.Socket通信模型
  • 3.UDP套接字编程
    • 1. DatagramSocket API
      • 1.构造方法
        • 1.DatagramSocket()
        • 2.DatagramSocket(int port)
      • 2.常用方法
        • 1.receive(DatagramPacket p)
        • 2.send(DatagramPacket p)
    • 2. DatagramPacket API
      • 1.构造方法
        • 1.DatagramPacket(byte[] buf,int length)
        • 2.DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)
      • 2. 常用方法
        • 1. getAddress()
        • 2.getPort()
        • 3.getData()
    • 3.InetSocketAddress API
      • 1.构造函数
      • 2.可用方法
  • 4.TCP套接字
    • 1.ServerSocket API
      • 1.构造方法
      • 2.常用方法
        • 1. accept()
        • 2. close()
    • 2.Socket API
      • 1.构造方法
      • 2.常用方法
        • 1.getInetAddress()
        • 2.getInputStream()
        • 3.getOutputStream()
  • 5.UDP示例(实现回显服务器和词典功能)
    • 1.服务器端的示例
    • 2. 客户端的示例
  • 6.TCP示例(实现词典功能)
    • 1.服务器示例
    • 2.客户端示例
  • 7.结果执行展示


前言

`Socket套接字,是系统提供的用于网络通信的技术,是基于TCP/IP协议的网络通信的基本单元,基于Socket套接字的网络程序开发就是网络编程,Sevrlet是socket的一种应用

1.分类

Socket套接字分为三类

1.流套接字

传输层使用TCP协议,对于字节流来说,传输流是基于IO流
流式数据的特征在流没有关闭的情况下,可以多次发送,切没有边界,也可以分开发送
具体TCP的特征可以看我前面的文章

2.数据报套接字

传输层使用UDP协议
对于数据来说,可以理解成是发送数据和接受数据都必须一块一块的接受和发送,切不能分次

3.原始套接字

原始套接字用于自定义传输层的协议,用于读写内核没有处理的IP协议数据

2.Socket通信模型

转载
这张图可以很好的展现出由TCP建立连接的通信模型

3.UDP套接字编程

UDP套接字编程,我们的java给我们提供了一个API叫做DatagramSocket

1. DatagramSocket API

1.构造方法

这个API有5个构造方法,但是我们只需要学习2个
我们可以去Java的官方文件中查看
在这里插入图片描述
这里只需要学习划红框的两个即可

1.DatagramSocket()

这个是将我们的数据包套接字绑定到我们本地的随机端口,一般用于客户端

2.DatagramSocket(int port)

这个是将我们的数据包套接字绑定到我们本地的指定端口,一般用于服务器

这里可能优点抽象,不过没关系,我们根据下文中的示例来理解,就会清晰很多

2.常用方法

这里我们DatagramSocket的方法有很多,但是我们只需要知道三个常用的就行了

1.receive(DatagramPacket p)

在这里插入图片描述
这个方法是从套接字中接受数据包,括号内的参数就是套接字,结果会传回到参数中去
注意:如果没有等到数据包,那么该方法会阻塞等待
DatagramPacket API我们下面就会详解

2.send(DatagramPacket p)

在这里插入图片描述
这个方法和上面的方法其实结构式一样的上面的式接受数据,这个是从参数中的这个套接字发送数据
注意:这个方法不会阻塞等待,直接就发送

2. DatagramPacket API

DatagramPacket就是UDP发送的数据报

1.构造方法

在这里插入图片描述
这里还是一样,我们只知道这两个就行了

1.DatagramPacket(byte[] buf,int length)

这里是构造一个DatagramPacket用来接受长度为length的数据包,这里的buf是用来存放接受到的数据的

2.DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)

这里是构造一个DatagramPacket用来发送长度为length的数据包,buf用来存放发送的数据,这里的offset是偏移量的意思,即从哪里开始,长度为length,address是指定目的主机的端口号的

这里我们构造数据包的时候,需要SocketAddress,这个对象可以通过我们下面介绍的InetSocketAddress来创建

2. 常用方法

它的方法也有很多,但是我们只挑我们需要的

1. getAddress()

在这里插入图片描述

这个方法是从获取到的数据包中,获取发送端主机的IP地址,或者从发送的数据报中,获取接收端的主机IP地址,并且打包到InetAddress中

2.getPort()

在这里插入图片描述
这个方法是从接收的数据包中获取到发送端主机的端口号,或者从发送的数据包中,获取接收端的主机端口号

3.getData()


这个方法,其实就是获取数据包中的数据

3.InetSocketAddress API

1.构造函数

这个构造函数我们只需要了解一个就行了
在这里插入图片描述

2.可用方法

现阶段,我们用这个API来构造一i个Socket地址即可,先不了解方法
在这里插入图片描述

4.TCP套接字

1.ServerSocket API

ServerSocket是创建TCP服务端的Socket API

1.构造方法

这里比UDP的简单些,只需要学一个构造方法即可
在这里插入图片描述

创建一个服务端流套接字,并且绑定到指定的端口上面去

2.常用方法

这里我们常用两个方法

1. accept()

在这里插入图片描述
这个方法是让我们服务端开始监听窗口,在创建的时候要先绑定端口号,有客户端连接之后,返回一个Socket对象,然后客户端基于这个对象,建立连接,否则就阻塞等待

2. close()

在这里插入图片描述
这个方法,会让我们的套接字进行关闭操作

2.Socket API

1.构造方法

这个构造方法我们也只需要学一个即可
在这里插入图片描述
这里的host是对应主机的IP地址,这里的port是对应主机的端口号

2.常用方法

1.getInetAddress()

在这里插入图片描述
这个方法就像图片上面的一样,简单易懂

2.getInputStream()

在这里插入图片描述

3.getOutputStream()

在这里插入图片描述

5.UDP示例(实现回显服务器和词典功能)

1.服务器端的示例

代码里面是逐行注释了,不存在看不懂,静下心去看

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王久实
 * Date: 2022-10-17
 * Time: 20:05
 */
//这里继承UdpEchoServer,UdpEchoServer是我们自己写的回显服务器,在下面这里为了方便,直接就继承下面写好的,只需要对process进行修改就行了
public class UdpTranslateServer extends UdpEchoServer{
//    创建一个Map用来对应单词和释意
    private Map<String,String> map = new HashMap<>();
//    构造方法,传入端口号,然后用super进行绑定
    public UdpTranslateServer(int port) throws SocketException {
        super(port);
        map.put("add","添加");
        map.put("delete","删除");
        map.put("update","修改");
    }

    //字典
//本身实现的无意义的回显服务器,现在只需要修改其中的process就可以了
    @Override
    public String process(String str) {
        return map.getOrDefault(str,"没有找到该词");
    }

    public static void main(String[] args) throws IOException {
//        创建对象,并且绑定端口号,这个类是上面我们自己定义的
        UdpTranslateServer UdpTranslateServer = new UdpTranslateServer(1231);
        UdpTranslateServer.start();
    }
}


/**
 * UDP实现回显服务器
 */
class UdpEchoServer {
//    这里是懒汉模式,只有当我们创建实例的时候,才进行对象的分配
    private DatagramSocket socket = null;
    //通过构造方法绑定端口
    public UdpEchoServer(int port) throws SocketException {
//    这里就是我们前面讲的DatagramSocket对象的应用
        socket = new DatagramSocket(port);
    }
    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器已经启动了");
        //读取socket发来的请求并解析
        //构造方法(构造一个DatagramPacket来接收数据报,接收的数据保存到传入的数组中去)
        while (true){
//            这里的数组大小我是随便指定的
//            DatagramPacket就是我们前面说的数据包,
            DatagramPacket requestPacket = new DatagramPacket(new byte[6666],6666);
            //receive方法是从requestPacket这个套接字中接收数据报,并且写回到我们传入的参数中,然后没有结果就阻塞等待,也是前面说过的
            socket.receive(requestPacket);
            //String的构造方法:通过使用平台的默认字符集解码指定的字节子阵列来构造新的 String
            String str = new String(requestPacket.getData(),0,requestPacket.getLength());
            //给数据执行对应的操作
//            process是我们自己写的方法
            String response = process(str);
            //把响应写回给客户端
//            这句语句信息量较多,首先,第一个参数是数组,也就是响应数据,第二个是数据长度,第三个就是我们的SocketAddress
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
//            这里进行发送数据
            socket.send(responsePacket);

            //4.打印日志
            System.out.printf("%s:%d req: %s;resp: %s \n",requestPacket.getAddress(),requestPacket.getPort(),str,response);
        }


    }
//    这里就是响应的具体实现,因为是回显服务器,就把传过来的字符串,原封不动的返回即可
    public String process(String str){
        return str;
    }


}

2. 客户端的示例

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王久实
 * Date: 2022-10-15
 * Time: 20:41
 */

//客户端方面就只需要发送数据即可,所以不管是回显,还是字典,客户端都是使用的同一段代码

public class UdpTranslateClient {
//    依旧是懒汉模式
    private DatagramSocket socket = null;
//    服务器的IP
    private String serverIP;
//    服务器的端口号
    private int serverPort;
//构造方法,初始化,这个我们前面的文章中讲过,这里注意,端口号必须和服务器中的端口号对应
    public UdpTranslateClient(String serverIP,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        Scanner sc = new Scanner(System.in);
//        这里用while的原因是因为要客户端可以多次发送请求
        while(true){
//            这里是我们输入的请求
            String request = sc.next();
//            这个还是构造需要发送的数据包
//            这里的InetAddress.getByName是把域名变成可访问的IP地址,比如"www.baidu.com"这种就会转换成对应的IP地址
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(this.serverIP)
                    ,this.serverPort);
            //发送数据
            socket.send(requestPacket);
            //接收响应并且解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[6666],6666);
//            这个是从这个套接字里面接收数据,并且返回到参数中去
            socket.receive(responsePacket);
            //解码
//            这里是把接收到的数据进行解码操作
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }

    }

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

6.TCP示例(实现词典功能)

1.服务器示例

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.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王久实
 * Date: 2022-10-18
 * Time: 8:47
 */
public class TcpTranslateServer {
//    依旧是懒汉模式创建Socket
    private ServerSocket listenSocket = null;
    Map<String, String> map = new HashMap<>();

    public TcpTranslateServer(int port) throws IOException {
        listenSocket = new ServerSocket(port);
        map.put("cat", "猫咪");
        map.put("dog", "小狗");
        map.put("fish", "鱼");
    }

    public void start() throws IOException {
        System.out.println("服务器已经启动");
//        创建一个service
        ExecutorService service = Executors.newCachedThreadPool();
        while (true) {
//            这个方法是监听窗口开始监听,前面也有提到,这里的端口号绑定是在上面的构造函数中已经绑定好的
            Socket clientSocket = listenSocket.accept();
//             这里我们采用多线程的方式进行执行操作,因为我们的服务器不可能只同时给一台客户端服务,UDP不一样,UDP是不建立连接的,TCP要建立连接,所以
//            要处理多台设备同时连接的情况
//            ExecutorService的submit方法是将Runnable的对象传递给ExecutorService的submit方法,则该run方法自动在一个线程上执行
            service.submit(new Runnable() {
                @Override
                public void run() {
//                    这里就是调用字典获取响应的方法了
                    processConnection(clientSocket);
                }
            });
        }

    }

    private void processConnection(Socket clientSocket) {
        System.out.println("客户端上线");
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                Scanner sc = new Scanner(inputStream);
//                说明客户端没有再输入了
                if (!sc.hasNext()) {
                    System.out.println("客户端下线");
                    break;
                }
//                这个是接收请求
                String request = sc.next();
//                这里是通过下面的函数处理request请求,然后将返回的响应复制给response
                String response = process(request);
//                这里就是建立输出流对象,将得到的response进行输出
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
//                这里是刷新缓存区
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s res: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
//  处理发送过来的请求,并返回响应
    public String process(String request) {
        return map.getOrDefault(request, "没有找到该单词");
    }

    public static void main(String[] args) throws IOException {
        TcpTranslateServer tcpTranslateServer = new TcpTranslateServer(1234);
        tcpTranslateServer.start();
    }


}

2.客户端示例

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王久实
 * Date: 2022-10-18
 * Time: 8:48
 */
public class TcpTranslateClint {
//    懒汉模式
    private Socket socket = null;
//    构造方法,传入服务器IP和服务器端口号,并且创建socket对象
    public TcpTranslateClint(String serverIP,int serverPort) throws IOException {
        socket = new Socket(serverIP,serverPort);
    }

    public void start(){
        Scanner scanner = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            while(true){
//                输入请求
                String request = scanner.next();
//                将请求放进IO输出流对象
                PrintWriter printWriter = new PrintWriter(outputStream);
//                将请求通过IO对象输出
                printWriter.println(request);
//                刷新缓存区
                printWriter.flush();
//                创建接收结果的输入流
                Scanner responseScanner = new Scanner(inputStream);
//                通过输入流将数据写入到结果集
                String response = responseScanner.next();
//                打印结果集
                System.out.println(response);

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

    public static void main(String[] args) throws IOException {
        TcpTranslateClint tcpTranslateClint = new TcpTranslateClint("127.0.0.1",1234);
        tcpTranslateClint.start();
    }
}

7.结果执行展示

这里的两个结果是一样的,我这里就执行TCP的拿来做展示
在这里插入图片描述
在这里插入图片描述
注意这里需要先运行服务端,再执行客户端

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

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

相关文章

C语言之复合类型上卷(十八)(阴阳两极)

上一篇: C语言之内存管理&#xff08;十七&#xff09;&#xff08;转世灵童现世&#xff09; 逐梦编程&#xff0c;让中华屹立世界之巅。 简单的事情重复做,重复的事情用心做,用心的事情坚持做&#xff1b; 文章目录前言一、什么是结构体&#xff1f;二、结构体的定义及初始化…

USB TO SPI(上海同旺电子)调试器调试MCP3201 A/D 转换器

所需设备&#xff1a; 1、USB TO SPI(上海同旺电子)&#xff1b; 2、MCP3201 12 位A/D 转换器; 特性 • 12 位分辨率 • 1 LSB DNL &#xff08;最大值&#xff09; • 1 LSB INL &#xff08;最大值&#xff09;&#xff08;MCP3201-B&#xff09; • 2 LSB INL &#xff…

pdf文件太大怎么变小,如何压缩pdf大小

pdf文件太大怎么变小&#xff1f;如果你是Windows电脑&#xff0c;可以使用PDF编辑器来减小PDF文件的大小&#xff0c;比如这款出色的PDF压缩工具-易我PDF编辑器&#xff0c;它的“压缩”功能提供了两种减小文件大小的方法&#xff0c;这使得它既适合那些只想获得更小的PDF的人…

【vscode】c++程序的自动编译及调试(环境centos)

目录1.新增配置文件&#xff08;1&#xff09;c_cpp_properties.json&#xff08;2&#xff09;files.associations&#xff08;3&#xff09;tasks.json(4)CMakeLists.txt2.断点调试1.新增配置文件 VS Code的配置文件一般是指特定目录下的JSON文件。所谓JSON是一种文本格式&a…

LCF-ATEPC(2020 Elsevier)面向中文的方面级提取和分类

论文题目&#xff08;Title&#xff09;&#xff1a;A Multi-task Learning Model for Chinese-oriented Aspect Polarity Classification and Aspect Term Extraction &#xff08;面向中文的方面极性分类和方面项提取的多任务学习模型) 研究问题&#xff08;Question&#…

适用于 Windows 10/11 电脑 的 5 大好用的离线录屏软件

屏幕录制应用程序可以数字记录出现在任何设备或 PC 屏幕上的内容&#xff0c;并同时以高清流式传输音频和视频。 因此&#xff0c;他们帮助创建营销视频、跟踪客户行为、设计产品演示、监控员工活动、录制教育内容、网络研讨会内容和业务会议内容。 现在您已经意识到屏幕录…

VS系列多通道振弦传感器无线采发仪的数据发送说明

每次设备启动后会将采集到的传感器数据进行内部存储&#xff0c;并在设置好的时间间隔将数据发送出去&#xff0c;通过修改“数据发送方式”参数&#xff0c;监测数据可由数据接口输出也可经由无线网络发送。在发送监测数据时&#xff0c;可通过修改“数据包协议”参数来设置所…

函数和数组习题

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C语言基础习题】 文章目录知识点习题2.实现一个整型数组的冒泡排序&#xff08;编程体&#xff09;。3.编程题&#xff1a;创建一个整型…

springcloud,springboot各个版本之间的关系

1 版本关系 在实际的开发中如果要自己搭建矿建&#xff0c;发现springcloud&#xff0c;springboot的版本可能是首先需要确定的&#xff0c;那么他们之间的关系是什么呢&#xff1f;看官网&#xff0c;地址 Spring Cloud 左侧是cloud的版本&#xff0c;右侧是对应的文档&…

Splunk Window 客户端迁移

最近客户的Splunk deployment server 要迁移,伴随着client 端的配置也要相应的调整: 先看一下架构: 看一下主要的参数: Summary of key terminology Heres a recap of the key definitions: TermMeaningdeployment serverA Splunk Enterprise instance that acts as a c…

Java中的日期与时间

Java中的日期与时间\huge{Java中的日期与时间}Java中的日期与时间 JavaJavaJava中有很多类是专门用于描述日期类的。 Date类 DateDateDate类&#xff1a;用于表示当前所在系统的日期时间信息。 Date类的构造器 示例&#xff1a; Date d new Date(); System.out.println(d);…

12月第3周榜单丨B站UP主排行榜(飞瓜数据B站)发布!

飞瓜轻数发布2022年12月12日-12月18日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的…

Redis高级篇

redis的四个问题&#xff1a; 1.Redis是基于内存存储,服务重启可能会丢失数据; 2.并发能力问题&#xff1a;单节点Redis能力虽然不错,但也无法满足如618这种高并发的场景(618并发 数量达到数十万甚至上百万); 3.如果reids宕机,服务不可用,则需要一种自动的故障恢复手段; 4.存…

自学Python可以找到工作吗?

自学Python可以找到工作吗&#xff1f;自学Python找工作主要看自己的学习能力&#xff0c;自学能力很强学完并精通当然可以工作&#xff0c;不过对于大多数人而言一般都挺难&#xff0c;学习不成系统&#xff0c;遇到问题没人解决很容易放弃半途而废。 学Python能干很多很多事…

NodeJS安装-Vue模块化项目构建

NodeJS安装-Vue模块化项目构建 一、环境准备&#xff08;NodeJS安装&#xff09; 1. 安装NodeJS 官网自行下载&#xff0c;并安装 2. 配置npm的全局安装路径 npm config set prefix "D:\soft_install\dev\qianduan_dir\nodejs"3. 切换npm的淘宝镜像&#xff0c…

C++11标准模板(STL)- 算法(std::is_permutation)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 判断一个序列是否为另一个…

《记忆力心理学》5个方法 让你过目不忘

《记忆力心理学》 关于作者 赫尔曼•艾宾浩斯&#xff0c;西方心理学泰斗级人物&#xff0c;生活在19世纪的德国心理学家。他是最早用实验的方法对记忆进行量化研究的 人&#xff0c;最受人瞩目的贡献&#xff0c;就是发现了记忆保持曲线。 关于本书 这本书可以看作是记忆心…

全国职业院校技能大赛网络搭建与应用赛项——云平台底层的一些命令

1.列出运行的虚拟机 virsh list 2.列出所有的虚拟机virsh list --all 3.网络信息表&#xff08;20分&#xff09; 显示网络名及所在的vlan idopenstack network show Network10 -c name -c provider:segmentation_id openstack network show Network20 -c name -c provider:s…

学习->C++篇十九:四种智能指针及其实现

目录 为什么需要智能指针&#xff1f; 什么是内存泄露&#xff1f; 如何避免内存泄露&#xff1f; 什么是RAII&#xff1f; RAII有什么用&#xff1f; 智能指针的原理是什么&#xff1f; C的智能指针有哪些&#xff1f; auto_ptr unique_ptr shared_ptr weak_ptr 为什…

【第十五章 分库分表(垂直拆分,水平拆分),MyCat】

第十五章 分库分表&#xff08;垂直拆分&#xff0c;水平拆分&#xff09;&#xff0c;MyCat 1.分库分表&#xff1a; &#xff08;1&#xff09;介绍&#xff1a; ①采用单数据库进行数据存储&#xff0c;存在以下性能瓶颈&#xff1a; A.IO瓶颈&#xff1a;热点数据太多&…