Springboot:搭建Socket服务器实现通信

1、什么是Socket?

本节内容参考:

TCP编程 - ShineLe - 博客园

Socket究竟是干什么的?_一人亦世界~*~的博客-CSDN博客

什么是Socket,为什么要用Socket_这个心歪了的博客-CSDN博客

TCP/IP五层标准网络架构分为:应用层、传输层、网络层、数据链路层、物理层;

各自功能及协议为:

  • 应用层:具体的应用通信协议,TFTP、HTTP、……

  • 传输层:提供端对端的接口,TCP、UDP

  • 网络层:为数据包选择路由,IP、ICMP、RIP、OSPF、BGP、IGMP

  • 数据链路层:传输带有物理地址的数据帧及错误检测,SLIP、PPP……

  • 物理层:以二进制数据流的形式在物理媒体上传输数据

Socket是Java提供的基于TCP/IP协议的对整个网络传输协议架构封装,它的作用只是使我们更方便地使用TCP/IP协议栈。它提供了针对传输层TCP或UDP编程的接口。

更详细的内容可以看之前所写的文章:TCP编程 - ShineLe - 博客园

2、使用Socket

本节内容参考:

SpringBoot+SOCKET服务端客户端_jacky 郑的博客

 

之前在TCP编程 - ShineLe - 博客园一文中,已经讲过如何编写Socket客户端和服务器,并在二者间利用Socket进行通信。

本节将介绍如何在Springboot中引入Socket。

整体包结构(其他层级如Dao、Service等这里就不展示了):

 

 

①Socket服务器类SocketServer.class(放在socket包中)

 

复制代码
package com.example.electronic.socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;

public class SocketServer {
    //解码buffer
    private Charset cs = Charset.forName("UTF-8");
    //接受数据缓冲区
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
    //发送数据缓冲区
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    //选择器/监听器
    private static Selector selector;
    
    Socket sock;

    public SocketServer(Socket sock){
        this.sock=sock;
    }
    //启动socket服务,开始监听
    public void startSocketServer(int port){
        try{
            //打开通信信道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            //获取Socket
            ServerSocket serverSocket = serverSocketChannel.socket();

            //打开监听器
            selector = Selector.open();
            //将通信信道注册到监听器
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            //监听器会一直监听,如果客户端有Request就会进入到相应的事件处理
            while(true){
                selector.select();//select方法会一直阻塞直到相关事情发生或超时
                Set<SelectionKey> selectionKeys=selector.selectedKeys();//监听到的事件
                for (SelectionKey key:selectionKeys){
                    handle(key);
                }
                selectionKeys.clear();//清理处理过的事件
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    //具体的事件处理方法
    private void handle(SelectionKey selectionKey)throws IOException {
        ServerSocketChannel serverSocketChannel = null;
        SocketChannel socketChannel = null;
        String requestMsg = "";
        int count = 0;
        if(selectionKey.isAcceptable()){
            //每有客户端连接,就注册通信信道为可读
            serverSocketChannel=(ServerSocketChannel)selectionKey.channel();
            socketChannel=serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector,SelectionKey.OP_READ);
        }else if(selectionKey.isReadable()){
            socketChannel=(SocketChannel)selectionKey.channel();
            rBuffer.clear();
            count=socketChannel.read(rBuffer);
            //读取数据
            if(count>0){
                rBuffer.flip();
                requestMsg=String.valueOf(cs.decode(rBuffer).array());
            }
            String responseMsg="已经收到客户端的消息:"+requestMsg;
            //返回数据
            sBuffer=ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length);
            sBuffer.put(responseMsg.getBytes("UTF-8"));
            sBuffer.flip();
            socketChannel.write(sBuffer);
            socketChannel.close();
        }
    }
}
复制代码

 

②发布WebSocket服务

在SpringBoot的启动类(main方法中)添加如下代码:

复制代码
    public static void main(String[] args) throws IOException {

        SpringApplication.run(ElectronicApplication.class, args);
        ServerSocket ss = new ServerSocket(9100);
        while(true){
            Socket sock=ss.accept();
            System.out.println("connected from "+sock.getRemoteSocketAddress());
            Thread t = new SocketServer(sock);
            t.start();
        }
    }
复制代码

相当于main方法同时启动了SpringBoot项目和Socket服务器。

 

③向Server发送消息

这里需要另外构造一个Client类(可以放在test中采用JUnit的方法进行测试,也可以自己构造一个新的Client的项目,这里采用第二种方法),专门用于发送消息:

复制代码
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Client {
    public static void main(String[]args) throws IOException {
        Socket sock = new Socket("localhost",9100);
        try(InputStream input = sock.getInputStream()){
            try(OutputStream output = sock.getOutputStream()){
                handle(input,output);
            }
        }
        sock.close();
        System.out.println("disconnected.");
    }
    private static void handle(InputStream input,OutputStream output) throws IOException{
        var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
        var reader = new BufferedReader(new InputStreamReader(input,StandardCharsets.UTF_8));
        Scanner scanner = new Scanner(System.in);
        System.out.println("[server] "+reader.readLine());
        while(true){
            System.out.print(">>> ");//打印提示
            String s = scanner.nextLine();//读取一行输入
            writer.write(s);
            writer.newLine();
            writer.flush();
            String resp = reader.readLine();
            System.out.println("<<< "+resp);
            if(resp.equals("bye")){
                break;
            }
        }
    }
}
复制代码

 

posted @   ShineLe  阅读(14501)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示