[JAVAee]网络编程-套接字Socket

news2024/12/24 3:58:40

目录

基本概念

发送端与接收端

请求与响应

​编辑客户端与服务器

Socket套接字 

分类

数据报套接字

流套接字传输模型  

UDP数据报套接字编程

DatagramSocket API

DatagramPacket API

InetSocketAddress API

示例一:

示例二:

TCP流数据报套接字编程

ServerSocket API

Socket API

示例一:

 


网络编程指的是,网络上的主机的不同进程通过编程的方式实现网络通信.同一主机下只要满足不同进程间的通信就可以成为"网络通信"

基本概念

发送端与接收端

在网络通信中:

作为发送数据的进程称为"发送端",发送端主机即网络通信中的"源主机" 

作为接收数据的进程称为"接收端",接收端主机即网络通信中的"目的主机"

注意:网络通信中的发送端与接收端都是相对的.

请求与响应

一般来说,一次网络通信中设计到两次数据传输:

  • 第一次:A端向B端发送的请求
  • 第二次:B端向A端发送的响应

客户端与服务器

服务器:在网络通信下,提供服务的一端.(服务可以指:响应一定的要求)

客户端:获取服务的一端

Socket套接字 

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元.基于Socket套接字的网络程序开发就是网络编程.

分类

套接字根据传输层协议主要分成:

  • 数据报套接字:使用传输层UDP协议(User Datagram Protocol)用户数据报协议
  • 流套接字:使用传输层TCP协议(Transmission Control Protocol)传输层控制协议
  • 原始套接字:用于自定义传输层协议

数据报套接字

数据报固定每次传输的字节,更像是写信,有来有回的.

流套接字传输模型  

面对的是字节流.

打电话一般,接通后就可以无节制的传输.

UDP数据报套接字编程

DatagramSocket API

构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口
(一般用于客户端)
DatagramSocket(int
port)
创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用
于服务端)

常用方法 

方法方法说明
void
receive(DatagramPacket p)
从此套接字接收数据报(如果没有接收到数据报,该方法会阻
塞等待)
void send(DatagramPacket
p)
从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket API

构造方法

方法签名方法说明
DatagramPacket(byte[]
buf, int length)
构造一个DatagramPacket以用来接收数据报,接收的数据保存在
字节数组(第一个参数buf)中,接收指定长度(第二个参数
length)
DatagramPacket(byte[]
buf, int length,
SocketAddress address)
构造一个DatagramPacket以用来发送数据报,发送的数据为字节
数组(第一个参数buf)中,从0到指定长度(第二个参数
length)。address指定目的主机的IP和端口号

常用方法 

方法签名方法说明
InetAddress
getAddress()
从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取
接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号
byte[] getData()获取数据报中的数据

InetSocketAddress API

InetSocketAddress是ScketAddress的一个子类,用来包装IP与端口号

方法方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

示例一:

客户端像服务器发出请求,但服务器无响应版本

服务器:

public class UdpServer {

    private DatagramSocket socket= null;

    public UdpServer(int port) throws SocketException {//构造方法
        this.socket = new DatagramSocket(port);
    }

    public void start() throws IOException {//作为启动服务器的方法
        while(true){//因为不知道什么时候客户端会发送请求
            //作为服务器,需要不停的接收客户端的请求
            //创建packet
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes,bytes.length);//用bytes作为接收,使用的长度为bytes的长度

            System.out.println("等待接收数据中...");
            socket.receive(packet);//还没收到之前会进行阻塞等待
            //此处的版本没有作出响应
            //我们可以打印出收到的packet中的数据看看有什么东西

            System.out.println("IP: " + packet.getAddress().getHostAddress());
            System.out.println("端口号: " + packet.getPort());
            System.out.printf("文本数据为: " + new String(packet.getData()));
            System.out.println("原始数据为: " + Arrays.toString(packet.getData()));
        }
    }
    public static void main(String[] args) throws IOException {
        UdpServer udpServer = new UdpServer(1024);
        udpServer.start();
    }
}

客户端:

方法一:
public class UdpClient {
    public static void main(String[] args) throws IOException {
        //创建Socket
        DatagramSocket socket = new DatagramSocket();//创建一个socket,端口号为系统随机分配
        //构建Packet
        byte[] bytes = "Hello World".getBytes();//字符串转换成byte再塞进数组
        SocketAddress address = new InetSocketAddress("localhost",1024);//目的IP为本地地址,端口号为1024
        DatagramPacket packet = new DatagramPacket(bytes,bytes.length,address);//构建packet
        socket.send(packet);//发送
        System.out.println("发送完成");
    }
}
方法二:
public class UdpClient {
    private DatagramSocket socket = null;//socket
    private String serverIp;
    private int serverPort;

    public UdpClient(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 text = scanner.next();
            if(text.equals("exit")){
                System.out.println("再见");
                break;
            }
            //需要用InetAddress将字符串钟的IP转换成地址形式
            //SocketAddress address = new InetSocketAddress("localhost",1024);//也可以创建一个实例进行包装IP与端口号
            //此处的长度是字节的长度噢,注意单位
            DatagramPacket packet = new DatagramPacket(text.getBytes(),text.getBytes().length,InetAddress.getByName(serverIp),serverPort);
            socket.send(packet);
            System.out.println("发送成功");
        }
    }
    public static void main(String[] args) throws IOException {
        UdpClient client = new UdpClient("127.0.0.1",1024);
        client.start();
    }

先启动服务器后启动客户端发送.

记得打开IDEA可以同时运行两个进程的选项噢!

服务器接收到的信息为:

示例二:

做一个服务器对客户端有响应的版本

简单的英汉翻译

服务器:

public class UdpServerResponse{
    private DatagramSocket socket= null;

    public UdpServerResponse(int port) throws SocketException {//构造方法
        this.socket = new DatagramSocket(port);
    }

    public void start() throws IOException {//启动服务器
        while(true){
            byte[] bytes = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(bytes,bytes.length);//创建包来接收

            System.out.println("等待接收数据中...");
            socket.receive(receivePacket);//接收包
            String request = new String(receivePacket.getData(),0,receivePacket.getLength());//根据接收到的包转换成字符串
            String response = process(request);//对请求进行分析
            //记得是getSocketAddress噢里面通常包含了IP与端口号
            DatagramPacket sendPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,receivePacket.getSocketAddress());
            socket.send(sendPacket);//对客户端作出响应
            System.out.println("客户端IP: " + receivePacket.getAddress());
            System.out.println("客户端端口号: " + receivePacket.getPort());
            System.out.println("收到的文本: " + request);
            System.out.println("返回的文本: " + response);
        }
    }

    public String process(String request){//解析请求,看看要做什么
        //这里就做一个英汉翻译吧
        HashMap<String,String> map = new HashMap<>();
        map.put("人","human");
        map.put("猫","cat");
        map.put("狗","dog");
        return map.getOrDefault(request,"查阅失败");
    }

    public static void main(String[] args) throws IOException {
        UdpServerResponse udpServerResponse = new UdpServerResponse(1024);
        udpServerResponse.start();
    }
}

客户端:

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

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

    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("输入: ");
            String request = scanner.next();
            if(request.equals("exit")){
                System.out.println("再见!");
                break;
            }
            //根据请求创建包
            DatagramPacket sendPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName("127.0.0.1"),1024);
            socket.send(sendPacket);
            System.out.println("发送成功");
            DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);//创建接收包
            socket.receive(receivePacket);
            String receive = new String(receivePacket.getData(),0,receivePacket.getLength());
            System.out.println(receive);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpClientResponse udpClientResponse = new UdpClientResponse("127.0.0.1",1024);
        udpClientResponse.start();
    }
}

服务器的打印

客户端的打印

TCP流数据报套接字编程

ServerSocket API

创建TCP服务端的API

构造方法

构造方法方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

方法

方法签
方法说明
Socket
accept()
开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket
对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void
close()
关闭此套接字

Socket API

用来建立链接后保存对方的信息

构造方法:

方法方法说明
Socket(String host, int
port)
创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的
进程建立连接

常用方法 

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

在TCP协议中的连接还分为长连接与短链接.

  • 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据
  • 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据

示例一:

一请求一响应

此处为长连接(把代码里的while(true)去掉就是短连接啦!只进行一次请求响应)

服务器:

对于服务器来说,每次与客户端连接后会创建一个socket来暂时存储客户端的信息数据

断开连接后,记得要将这个存储客户端数据的socket进行close释放掉

在服务器进程中,一个客户端socket会占用文件描述符的一个位置,一个服务器可能会要与成千上万个客户端进行通信,不释放就会将文件描述符的位置沾满造成泄露.

而服务器的serverSocket的生命周期与整个进程相当,且只有一个.所以可以不进行释放

使用线程池,用多线程的方式来运行服务器达到同时与多个客户端进行通信的功能.

public class TcpServer {
    private ServerSocket socket = null;
     public TcpServer(int port) throws IOException {
         socket = new ServerSocket(port);
     }

     public void start() throws IOException {
         //尝试链接
         ExecutorService threadPool = Executors.newCachedThreadPool();//创建一个线程池,一个线程对应一个客户端进行通信
         while (true) {
             Socket clientSocket = socket.accept();//会阻塞等待接受
             threadPool.submit(() -> {//向线程提供任务
                 try {
                     processConnect(clientSocket);
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             });
         }
     }
     public void processConnect(Socket clientSocket) throws IOException {
         System.out.println("已与客户端进行链接-" + clientSocket.getInetAddress() + clientSocket.getPort());
         try(InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()){
             while(true){
                 Scanner scanner = new Scanner(inputStream);//读
                 PrintWriter printWriter = new PrintWriter(outputStream);//写
                 if(!scanner.hasNext()){//客户端不再传输数据就断开链接
                     System.out.println("结束");
                     break;
                 }
                 String request = scanner.next();//接收请求
                 String response = process(request);//处理请求
                 printWriter.println(response);//向客户端写回响应
                 printWriter.flush();//记得写回后进行刷新缓冲区
                 System.out.println("响应:" + clientSocket.getInetAddress() + clientSocket.getPort() + "文本: "+ response);
             }
         } catch (IOException e) {
             e.printStackTrace();
         }finally {
             clientSocket.close();//记得要关闭
         }
     }

     public String process(String request){
         HashMap<String,String> map = new HashMap<>();
         map.put("人","human");
         map.put("猫","cat");
         map.put("狗","dog");
         return map.getOrDefault(request,"查阅失败");
     }

    public static void main(String[] args) throws IOException {
        TcpServer tcpServer = new TcpServer(1024);
        tcpServer.start();
    }
}

客户端:

public class TcpClient {
    private Socket socket = null;
    private String serverIp;
    private int serverPort;

    public TcpClient(String serverIp,int serverPort) throws IOException {
        socket = new Socket(serverIp,serverPort);//客户端随机分配端口号
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start(){
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            //创建流对象进行写与读
            while(true){
                Scanner scanner = new Scanner(System.in);//用来写入
                PrintWriter printWriter = new PrintWriter(outputStream);//包装output流对象
                String request = scanner.next();//写请求
                if(request.equals("exit")){
                    System.out.println("结束与服务器连接");
                    break;
                }
                //把请求放到流对象中写出去
                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 {
        TcpClient tcpClient = new TcpClient("127.0.0.1",1024);
        tcpClient.start();
    }
}

服务器打印:

 

客户端打印:

 

 


 

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

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

相关文章

Go学习第七天

Golang反射reflect机制用法 重点&#xff1a; 转换的时候&#xff0c;如果转换的类型不完全符合&#xff0c;则直接panic&#xff0c;类型要求非常严格&#xff01;转换的时候&#xff0c;要区分是指针还是指也就是说反射可以将“反射类型对象”再重新转换为“接口类型变量” …

6.5.tensorRT高级(1)-alphapose模型导出、编译到推理(无封装)

目录 前言1. alphapose导出2. alphapose推理3. 讨论总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-alphap…

探究Vue源码:mustache模板引擎(11) 递归处理循环逻辑并收尾算法处理

好 在上文 探究Vue源码:mustache模板引擎(10) 解决不能用连续点符号找到多层对象问题&#xff0c;为编译循环结构做铺垫 我们解决了js字符串没办法通过 什么点什么拿到对象中的值的问题 这个大家需要记住 因为这个方法的编写之前是当做面试题出现过的 那么 本文 我们就要去写上…

vue中点击添加类名,并且实现升降序

1.介绍 要求&#xff1a;掌握indexOf()用法&#xff1b;动态绑定类名的对象写法&#xff1b;iconfont使用&#xff1b;split()用法&#xff1b;三元运算符用法&#xff1b;es6模板字符串&#xff1b; 说明&#xff1a;首先综合元素默认有元素并且是降序。服务器传来的数据格式…

ELK、ELFK日志分析系统

菜单一、ELK简介1.1 ELK组件说明1.1.1 ElasticSearch1.1.2 Kiabana1.1.3 Logstash 1.2 可以添加的其它组件1.2.1 Filebeat1.2.2 缓存/消息队列&#xff08;redis、kafka、RabbitMQ等&#xff09;1.2.3 Fluentd 1.3 为什么要用ELK1.4 完整日志系统的基本特征1.5 ELK 的工作原理 …

laravel安装composer依赖

一.问题描述 拉取的新项目没有依赖 项目根目录没有vendor目录 报错 二.安装composer,拉取依赖 1.如果没有composer先去下载 官网地址:Packagist / Composer 中国全量镜像 我的博客安装composer:composer最新版本安装_荒-漠的博客-CSDN博客 2.进入项目根目录cmd或者在项目中…

js-6:typeof和instanceof的区别

1、typeof typeof操作符返回一个字符串&#xff0c;表示未经计算的操作数的类型。 operand表示对象或原始值的表达式&#xff0c;其类型将被返回。 从上面的例子可以看出&#xff0c;前6个都是基础数据类型&#xff0c;虽然typeof null为object&#xff0c;但这只是javascrip…

chaitin-Nginx+Docker

Nginx实战 任务一 1、源码包安装NGINX A&#xff0c;搭建Web Server&#xff0c;任意HTML页面&#xff0c;其8080端口提供Web访问服务&#xff0c;截图成功访问http(s)&#x1f615;/[Server1]:8080并且回显Web页面 官网地址&#xff1a;http://nginx.org/en/download.html 步骤…

webpack基础知识九:如何提高webpack的构建速度?

一、背景 随着我们的项目涉及到页面越来越多&#xff0c;功能和业务代码也会随着越多&#xff0c;相应的 webpack 的构建时间也会越来越久 构建时间与我们日常开发效率密切相关&#xff0c;当我们本地开发启动 devServer 或者 build 的时候&#xff0c;如果时间过长&#xff…

【CSS3】CSS3 2D 转换 - 三种变换的综合写法 ( 同时进行 移动 / 旋转 / 缩放 变换 | 代码示例 )

文章目录 一、三种变换的综合写法 - 同时进行 移动 / 旋转 / 缩放 变换二、代码示例 一、三种变换的综合写法 - 同时进行 移动 / 旋转 / 缩放 变换 CSS3 的 2D 转换有 移动 / 旋转 / 缩放 , 上述 三种 变换 可同时使用 , 使用语法如下 : transform: translate() rotate() sc…

Vue3+Vite+Pinia+Naive后台管理系统搭建之九:layout 动态路由布局

前言 如果对 vue3 的语法不熟悉的&#xff0c;可以移步Vue3.0 基础入门&#xff0c;快速入门。 1. 系统页面结构 由 menu&#xff0c;面包屑&#xff0c;用户信息&#xff0c;页面标签&#xff0c;页面内容构建 ​ 2. 创建页面 创建 src/pages/layout.vue 布局页 创建 sr…

接口测试——电商网站接口测试实战(四)

1. 接口测试需求分析 常见接口文档提供的两种方式 ①word文档 ②在线文档 电商网站网址模拟练习&#xff1a;Swagger UI 2. 登陆的分析 慕慕生鲜网址&#xff1a;慕慕生鲜账号密码点击execute后 输入账号密码后点击开发者工具&#xff0c;再登录&#xff0c;点击网络&…

PHP 门户信息网站系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 门户信息网站系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载地址https://download.csdn.net/download/qq_41221322/88179035https://downlo…

EVE-NG MPLS LDP LSP

目录 1 拓扑 2 配置步骤 2.1 配置接口IP 2.2 配置OSPF 2.3 使能LDP 2.3 在VPC上验证 1 拓扑 2 配置步骤 2.1 配置接口IP LER1 interface LoopBack 0ip address 1.1.1.9 32 quitinterface GigabitEthernet1/0ip address 10.1.1.1 255.255.255.0quitinterface GigabitEth…

Harbor企业镜像仓库部署

目录 一、Harbor 架构构成 二、部署harbor环境 1、安装docker-ce&#xff08;所有主机&#xff09; 2、阿里云镜像加速器 3、部署Docker Compose 服务 4、部署 Harbor 服务 5、启动并安装 Harbor 6、创建一个新项目 三、客户端上传镜像 1、在 Docker 客户端配置操作如下…

Leetcode 每日一题 - 删除有序数组中的重复项题 #算法 #Java

1.1 题目 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff…

寻找最佳项目管理工具?这些优秀选择值得一试!

优秀的项目管理工具可以帮助提高管理效率&#xff0c;缩短完成时间&#xff0c;减少困惑和挫折等等。 你的团队是否面临以下问题&#xff1a; 各组织信息独立&#xff0c;缺乏统一管理&#xff1f; 数字建设成本高、周期长、落地难&#xff1f; 数据孤岛&#xff0c;无法复用、…

抖音怎么录屏?这3种方法请你收好

抖音作为全球流行的短视频平台&#xff0c;让我们可以分享生活中的精彩瞬间&#xff0c;欣赏他人的创意作品。有时候&#xff0c;我们可能会遇到一些特别喜欢的视频&#xff0c;希望将其保存下来或与他人分享。本文将为您介绍抖音怎么录屏的全套攻略。通过本文的指导&#xff0…

A33 QT 主线例程 opengl

点击查看 HW33-050 HW33-070 规格书 HW33-050 HW33-070 支持 android 系统和 Linux QT。 HW33-XXX采用4 核Cortex-A7 ARM、Mali400MP2 GPU架构&#xff0c;主频 1.2GHz 的 CPU。内存 存储标配分别为1GB、8GB&#xff0c;内置显卡为Mali400MP2&#xff0c;支持 H.264 1080P …

segment-anything使用说明

文章目录 一. segment-anything介绍二. 官网Demo使用说明三. 安装教程四. python调用生成掩码教程五. python调用SAM分割后转labelme数据集 一. segment-anything介绍 Segment Anything Model&#xff08;SAM&#xff09;根据点或框等输入提示生成高质量的对象遮罩&#xff0c…