网络编程套接字

article/2025/7/4 23:52:23

目录

1.Socket套接字

1.1TCP和UDP的区别

2.UDP api的使用

2.1DatagramSocket

2.2DatagramPacket

 3.UDP数据报套接字编程

3.1UdpEchoServer服务器

 3.2UdpEchoClient客户端

3.3客户端和服务器相互配合的完整流程

4.TCP api的使用 

4.1ServerSocket

4.2Socket

4.TCP数据报套接字编程

4.1TcpEchoServer服务器

 4.2TcpEchoClient客户端


1.Socket套接字

操作系统给应用程序(传输层给应用层)提供的API起了个名字就叫socket api

socket本身含义是插槽,类似于电脑主板上的插槽接口

Java中提供了两套API,UDP一套,TCP一套

1.1TCP和UDP的区别

TCP有连接,可靠传输,面向字节流,全双工

UDP无连接,不可靠传输,面向数据报,全双工

  1. 有连接/无连接
    此处谈到的为抽象的连接,通信双方如果保存了通信对端的信息(IP+端口),就相当于是"有连接",如果不保存对端信息就是"无连接"
  2. 可靠传输/不可靠传输
    此处的可靠指的是“尽可能”,不可靠就是完全不考虑数据是否能够到达对方

    TCP内置了一些机制,能够保证可靠传输
    ①感知对方是不是收到了
    ②重传机制,在对方没收到时进行重试
    UDP则没有可靠性机制,完全不管发出去的数据是否顺利到达对方

    可靠传输更为复杂,TCP协议的设计就要比UDP复杂很多,也会损失一些传输数据的效率
  3. 面向字节流/数据报
    TCP是面向字节流的,TCP的传输过程就和文件流/水流是一样的特点.

    UDP面向数据报
    传输数据的基本单位,不是字节了,而是"UDP数据报"
    一次发送/接受,必须发送/接受完整的UDP数据报
  4. 全双工/半双工
    全双工:一个通信链路,可以发送数据也可以接收数据(双向通信)
    半双工:一个通信链路,只能发送/只能接收(单向通信)

2.UDP api的使用

通过代码直接操作网卡,不好操作(网卡有很多种不同的型号,之间提供的api都会有差别)
操作系统就把网卡概念封装成socket.应用程序员不必关注硬件的差异和细节,统一去操作socket对象,就能间接的操作网卡.

socket就像遥控器一样,

从socket里读数据就相当于接受网卡传来的网络信号(数据流向:网卡 → 内核→ Socket),

往socket里写数据相当于控制网卡发送网络信号(数据流向:Socket → 内核 → 网卡

Socket 与遥控器的类比逻辑
类比对象遥控器Socket
核心功能远程控制设备(如电视、空调)远程控制网络数据收发
操作抽象按下按钮(抽象操作)→ 遥控器内部电路处理 → 红外信号发射调用 Socket 接口(如 send()/recv())→ 操作系统内核处理 → 网卡硬件收发数据
用户感知无需关心红外信号的物理特性无需关心网卡驱动、TCP/IP 协议细节


2.1DatagramSocket

  • DatagramSocket表示一个socket对象,操作系统的概念socket就可以认为是操作系统中,广义的文件下,里面的一种文件类型就是网卡这种硬件设备抽象的表示形式
     

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

    void receive(DatagramPacket p)     

    接收数据时使用

    从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
    void send(DatagramPacket p)

    发送数据时使用
    从此套接字发送数据报包(不会阻塞等待,直接发
    送)
    void close()关闭此数据报套接字

    2.2DatagramPacket

  • DatagramPacket代表一个UDP数据报
    DatagramPacket构造方法
    DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
    DatagramPacket(byte[] buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的SocketAddress address)数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号
    DatagramPacket方法
    InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发
    送的数据报中,获取接收端主机IP地址
    int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
    byte[] getData()获取数据报中的数据

 3.UDP数据报套接字编程

写一个最简单的客户端服务器程序,不涉及到业务流程只是对于api的用法做演示
回显服务器"(echo server)
客户端发啥样的请求,服务器就返回啥样的响应
没有任何业务逻辑,进行任何计算或者处理

3.1UdpEchoServer服务器

  • DatagramSocket表示一个socket对象
    DatagramPacket进行UDP传输时的一个基本单位

  • 此处代码中,socket生命周期,应该是跟随整个进程的
    进程结束了,socket才需要关闭
    此时,就算代码中没有close,进程关闭,也就会释放文件描述符表里的所有内容,也就是相当于close了
  • 调用这个构造方法的过程中,jvm就会调用系统的socket api完成端口号和进程之间的关联动作

    对于一个系统来说,同一时刻,一个端口号,只能被一个进程绑定
    但是一个进程可以绑定多个端口号(通过创建多个socket对象来完成)
  • 对于服务器来说,主要的工作,就是不停的处理客户端发来的请求,由于客户端啥时候来请求,服务器也无法预测,服务器只能时刻准备好,随时有客户端来了就随时立即处理
  • receive是通过"输出型参数"获取到网卡上收到的数据
    receive是从网卡上读取数据,但是调用receive的时候,网卡上可不一定就有数据

    如果网卡上收到数据了,receive立即返回,获取到收到的数据
    如果网卡上没有收到数据,receive就会阻塞等待,一直等待到真正收到数据为止.
  • DatagramPacket自身需要存储数据,存储空间大小由外部定义
  • DatagramSocket这个对象中,不持有对方(客户端)的ip和端口的.
    进行send的时候,就需要在send的数据包里,把要发给谁这样的信息,写进去,才能够正确的把数据进行返回
  • 请求(request):客户端主动给服务器发起的数据
    响应(response):服务器给客户端返回的数据
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private DatagramSocket socket = null;//在构造函数中指定端口号,使服务器绑定到该端口public UdpEchoServer (int port) throws SocketException {socket = new DatagramSocket(port);}public String process (String request){return request;}//通过start启动服务器的核心流程public void start() throws IOException {System.out.println("服务器启动");while(true) {//通过死循环不停处理客户端请求//1.读取客户端的请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);//上述收到的数据是二进制byte[]的形式体现的,后续若需打印需转换为字符串String request = new String(requestPacket.getData(),0,requestPacket.getLength());//2.根据请求计算响应,由于此处是回显服务器,响应就是请求String response = process(request);//3.把响应写回到客户端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(),request,response);}}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

 3.2UdpEchoClient客户端

  • 客户端这边创建socket最好不要指定端口号,客户端是主动的一方,不需要服务器来找他,客户端就不需要指定端口号了(不指定不代表没有,客户端这边自动分配了一个端口)
    因为客户端是在用户的电脑上运行的,所以我们并不知道电脑上都有哪些程序都已经占用了哪些端口,因此让系统自动分配就能确保分配的是无人使用的空闲端口

    服务器程序运行在服务器主机上,服务器指定固定端口就不怕程序冲突
  • 客户端与服务器进行通信时要保存服务器的地址和端口
  • 构造数据报并发送请求给服务器,指定服务器的IP地址和端口

  • 127.0.0.1这个是特殊的IP,环回IP,这个IP就代表本机,如果客户端和服务器在同一个主机上,就使用这个IP
import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP;private int serverPort;public UdpEchoClient (String serverIP,int serverPort) throws SocketException {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) {//1.从控制台读取到用户的输入System.out.println("->");String request = scanner.next();//2.构造出一个UDP请求,发送给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(this.serverIP),this.serverPort);socket.send(requestPacket);//3.从服务器读取到响应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();}
}

3.3客户端和服务器相互配合的完整流程

  1. 服务器读取客户端的请求并解析,receive阻塞,等待服务器收到请求
  2. 客户端构造UDP请求发送给服务器,发送完毕的同时客户端继续往下走,在receive处阻塞,等待服务器的响应

  3. 服务器收到了请求,从receive返回,继续往下走,将收到的数据转换成字符串,因为是回显服务器所以响应就是请求,把响应写回到客户端

  4. 客户端收到了服务器返回的响应之后就会从上面的receive解除阻塞继续执行,将响应转为字符串之后进行打印

  5. 服务器send完毕后,打印日志,然后进入下一轮循环,继续在receive处进行阻塞 客户端打印完毕这里之后,也要进入下一次循环,下一次循环,就要继续从scanner中读取

    用户输入的内容了.

  •  服务器无连接



4.TCP api的使用 

4.1ServerSocket

ServerSocket 是创建TCP服务端Socket的API,专门给服务器使用的socket对象

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

TCP是有连接的,有连接就需要有一个“建立连接”的过程
建立连接的过程就类似于打电话,此处的accept就相当于"接电话"

由于客户端是"主动发起”的一方,服务器是"被动接受”的一方,所以客户端打电话,服务器接电话

4.2Socket

Socket是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回服务端的Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
即会给客户端使用也会给服务器使用

Socket构造方法
方法签名方法说明
Socket(String host, int port)

创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

构造这个对象,就是和服务器“打电话”“建立连接”

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

5.TCP数据报套接字编程

同一个协议下,一个端口只能被一个进程绑定,9090端口在UDP下被一个进程绑定了,还可以在TCP下被另一个进程绑定
不能绑定多个UDP或TCP

如图表示绑定的端口号已被占用,此时就需要找找,端口是被谁绑定了,找到对应的进程
决定是结束旧的进程,还是修改新进程的端口

 

5.1TcpEchoServer服务器

  • TCP是全双工通信,所以既可以读也可以写,inputStream outputStream
  • inputStream.read处理的数据类型是二进制字节,scanner处理的是文本字符串更方便读取
  • 写入响应的时候末尾加上\n,TCP是字节流的.读写方式存在无数种可能,就需要有办法区分出,从哪里到哪里是一个完整的请求数据,此处就可以引入分隔符来区分

    读取数据时就隐藏了条件,请求应以空白符(空格,回车,制表符等)结尾

    因此此处就约定,使用\n作为请求和响应的结尾标志
    后续客户端,也会使用scanner.next读取响应
  • 线程池的创建是为了复用线程,解决了客户端发一个请求之后就快速断开连接了
    ExecutorService service = Executors.newCachedThreadPool();

    客户端持续的发送请求处理响应,连接会保持很久~~

 服务器的两处阻塞

  • 等待客户端连上
    //客户端
    socket = new Socket(serverIP,port);//服务器
    Socket clientSocket = serverSocket.accept();
  • 等待客户端发送数据
    //客户端,把请求发送给服务器
    printWriter.println(request);//服务器
    if(!scanner.hasNext()) {//如果scanner无法读取数据,说明客户端关闭了连接,导致服务器这边读取到了“末尾”break;
    }

容易出现的三个bug

  1. 服务器发送了数据之后,并没有任何响应,此处的情况是客户端并没有真正把请求发送出去
    printWriter.println(request);

    printWriter这个类“自带缓冲区”,把请求先放到内存的缓冲区里,由于此处数据比较少,因此这样的数据就一直停留在缓冲区中无法进行发送
    引入缓冲区之后,进行写入数据的操作,不会立即触发1O,而是先放到内存缓冲
    区中,等到缓冲区里攒了一波之后,再统一进行发送


    因此我们需要引入flush操作“刷新缓冲区”
     

    printWriter.flush();
  2. 针对cilentSocket没有进行close操作
    像ServerSocket,DatagramSocket他们的生命周期都是跟随整个进程的,而此处的此cilentSocket是“连接级别”的数据,随着客户端断开连接了,这个socket也就不再使用了,即使是同一个客户端断开之后重新连接socket也是不同的,因此这样的socket需要主动关闭,否则就会造成文件资源泄露
     

    clientSocket.close();

  3. 只能为一个客户端提供服务,应该满足同时给多个客户端提供服务

    当第一个客户端连上服务器之后,服务器代码就会进入processConnect内部的while循环,此时第二个客户端尝试连接时,无法执行到第二次accept,所以第二个客户端发来的请求数据都积压在操作系统的接收缓冲区中
    此处无法处理多个客户端,本质上是服务器代码结构存在问题,采取了双重while循环的写法.就会导致,进入里层while的时候,外层while无法继续执行了,此时我们只需要改为一层循环分别进行执行即可,用多线程来实现,
    主线程是accept,每个客户端连接由独立线程处理,主线程继续接收下一个连接。

  4. public void start() throws IOException {System.out.println("启动服务器");//System.err.println("启动服务器");//线程池ExecutorService service = Executors.newCachedThreadPool();while(true) {Socket clientSocket = serverSocket.accept();service.submit(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});}}

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");System.err.println("启动服务器");//线程池ExecutorService service = Executors.newCachedThreadPool();while(true) {Socket clientSocket = serverSocket.accept();service.submit(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});}}//针对一个连接提供处理逻辑private void processConnection(Socket clientSocket) throws IOException {//先打印一下客户端的信息System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());//获取到 socket 中持有的流对象try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {//使用scanner包装一下inputStream就可以更方便的读取这里的请求数据了Scanner scanner = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);while(true) {//1.读取请求并解析if(!scanner.hasNext()) {//如果scanner无法读取数据,说明客户端关闭了连接,导致服务器这边读取到了“末尾”break;}String request = scanner.next();//2.根据请求计算响应String response = process(request);//3.把响应写回给客户端//此处可以按照字节数组直接来写,也可以有另外一种写法//outputStream.write(response.getBytes());printWriter.println(response);printWriter.flush();//4.打印日志System.out.printf("[%s:%d] req=%s; resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request, response);}} catch (IOException e) {e.printStackTrace();} finally {System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());clientSocket.close();}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

 5.2TcpEchoClient客户端

对象一new好就会和服务器建好连接,服务器accept如果建立连接失败就会在构造对象时抛出异常

public TcpEchoClient(String serverIp, int serverPort) throws IOException {socket = new Socket(serverIp, serverPort);}

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动");try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);Scanner scannerIn = new Scanner(System.in);PrintWriter printWriter = new PrintWriter(outputStream);while (true) {// 1. 从控制台读取数据System.out.print("-> ");String request = scannerIn.next();// 2. 把请求发送给服务器printWriter.println(request);printWriter.flush();// 3. 从服务器读取响应if (!scanner.hasNext()) {break;}String response = scanner.next();// 4. 打印响应结果System.out.println(response);}} catch (Exception e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}


http://www.hkcw.cn/article/yqYITvkfWS.shtml

相关文章

秋招Day12 - 计算机网络 - TCP

详细说一下TCP的三次握手机制 TCP的三次握手机制是为了在两个主机之间建立可靠的连接,这个机制确保两端的通信是同步的,并且在开始传输数据前,双方都做好了要通信的准备。 说说SYN的概念? SYN 是 TCP 协议中用来建立连接的一个标…

前端pointer-events属性

1.如图 2.用法 使用pointer-events来阻止元素成为鼠标事件目标不一定意味着元素上的事件侦听器永远不会触发。如果元素后代明确指定了pointer-events属性并允许其成为鼠标事件的目标,那么指向该元素的任何事件在事件传播过程中都将通过父元素,并以适当的…

golang连接sm3认证加密(app)

文章目录 环境文档用途详细信息 环境 系统平台:Linux x86-64 Red Hat Enterprise Linux 7 版本:4.5 文档用途 golang连接安全版sm3认证加密数据库,驱动程序详见附件。 详细信息 1.下载Linux golang安装包 go1.17.3.linux-amd64.tar.gz 1.1. 解压安…

PYTHON调用讯飞C/C++动态库实现离线语音合成并且实时播放

语音合成(Text-to-Speech, TTS)技术在现代应用中扮演着越来越重要的角色,从智能客服到有声读物,从导航系统到辅助工具,TTS技术无处不在。本文将详细介绍如何使用Python结合科大讯飞的离线SDK实现一个本地化的语音合成系统。 技术背景 离线语…

【Unity】模型渐变技术 BlendShapes变形

模型fbx拖拽到场景并赋予脚本上SkinnedMeshRenderer参数 按下空格即可演示渐变 可去到3DsMax 或 Blender等软件制作 这种带有BlendShapes的模型 (Sphere002)是另一个模型,3DsMax叫变形器。 可参考:【技术美术百人计划】美术 3.5 BlendShape基础_哔哩哔哩…

追觅高管批员工8点下班太早 引发加班争议

近日,社交媒体上流传一封追觅内部信。信中提到,许多深圳员工晚上不到20点就下班了,而总部那边22点后还有员工在办公室。管理者建议员工即使按时下班到家也应继续工作。信中还表示,行业内的普遍标准是员工创造的价值要达到公司雇佣成本的15倍以上,并以此质问员工是否达到了…

以防长:哈马斯要么接受要么被消灭 以军全面施压加沙

当地时间5月30日,以色列国防部长卡茨通过个人社交媒体账号发表声明称,在以军强大的军事压力下,巴勒斯坦伊斯兰抵抗运动(哈马斯)将被迫选择接受美方提出的加沙停火提案,或被以色列消灭。卡茨表示,当前以军正在加沙地带全力展开行动,打击并摧毁哈马斯据点,并要求当地居民…

朱雀玄武敕令称改名事件成政治考题 高考模拟题意外现身

前不久,“00后”小伙朱雀玄武敕令申请改名为“周天紫微大帝”的新闻引起广泛关注。5月30日,他透露近期正准备参加今年高考,并在网上搜寻到的模拟考试卷中看到了关于自己改名一事的考题。朱雀玄武敕令出生于2001年,父母为他起名“朱云飞”。2025年1月,他改名为“朱雀玄武敕…

5分钟学会网络服务搭建,飞凌i.MX9352 + Linux 6.1实战示例

在“万物互联”的技术浪潮下,网络服务已成为连接物理世界与数字世界的核心纽带,它不仅赋予了终端设备“开口说话”的能力,更构建了智能设备的开发范式。 本文就将以飞凌嵌入式OK-MX9352-C开发板(搭载了在工业物联网领域广泛应用的…

超级对话2:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之二

摘要:《人机协同文明升维行动框架》提出以HIAICI/W公式推动认知革命,构建三大落地场景:1)低成本认知增强神经接口实现300%学习效率提升;2)全球学科活动化闪电战快速转化知识体系;3)人…

AI Agent在测试设计中的应用

前言 随着AI和大模型(LLM)的诞生以及技术的成熟和普及,测试工程师不仅可以利用 AI 生成和优化测试用例,还能借助 LLM 提高测试覆盖率、减少测试设计的重复性工作,从而专注于更复杂的测试策略和质量保障。 在软件测试…

详细到用手撕transformer下半部分

之前我们讨论了如何实现 Transformer 的核心多头注意力机制,那么这期我们来完整地实现整个 Transformer 的编码器和解码器。 Transformer 架构最初由 Vaswani 等人在 2017 年的论文《Attention Is All You Need》中提出,专为序列到序列(seq2s…

Vue开发入门安装

Vue开发入门安装 版本选择剪不断,理还乱Node.js —— 类比为 Java JDKnpm —— 类比为 Maven 或 Gradlenvm —— 类比为 JDK 版本管理工具Vue.js —— 类比为 Spring Framework 或 JavaFX 下载配置下载node-v16.20.2-win-x86.zip设置环境变量打开位置,输…

leetcode刷题日记——二叉树的最近公共祖先

[ 题目描述 ]: [ 思路 ]: 两个节点的最近公共祖先具有以下特点如果祖先节点不是自身,那么两个节点一定在祖先节点的两边所以可以递归搜索树的左右子树,如果节点分布在两边,那么这个就是最近公共祖先,如果…

北京业之峰法式奶油风改造:92㎡两居打造温柔治愈之家

在当前居住空间设计日益注重实用性与美学融合的趋势下,北京业之峰近日完成一套法式奶油风住宅改造项目。整体设计在保留原始结构优势的基础上,以清新柔和的视觉风格和合理的空间动线布局,为业主提供了一个兼具温度与功能的理想居所。项目整体…

五星级酒店技能比赛主持稿串词

男:尊敬的各位领导~ 女:紫澜门国际酒店的兄弟姐妹们~ 合:大家——上午好~ 男:欢迎大家来到紫澜门国际酒店20XX年度——酒店竞技比赛的现场。 女:我是质检招聘部副主任XXX 男:我是工程部XXX 女:非常兴奋能兴奋能担负今天竞技比赛的主持人&…

DistilQwen-ThoughtX:变长思维链推理模型,超越DeepSeek蒸馏模型

作者:蔡文睿(清素)、汪诚愚(熊兮)、严俊冰(玖烛)、黄俊(临在) 前言 近年来,自然语言处理(NLP)领域以大语言模型(LLM&…

困在办公室二手烟中的职场人 防毒面具下的无奈抗争

早上8点,王海推开办公室的门,熟练地从衣柜里取出那套“工服”——这是他的“二手烟专用装备”。衣服早已浸透了焦油味,他迅速换上,等待同事们的到来。在这个四人办公室里,王海是唯一不抽烟的人。而他的三位同事,从清晨到傍晚,随时可能点燃一支烟,让狭小的空间瞬间烟雾弥…

《歌手》白举纲进步 遗憾止步舞台

《歌手2025》第三期竞演在湖南卫视和芒果TV落下帷幕。查理普斯作为“袭榜歌手”登场,终于实现了他推迟一年的中国行,并且成功袭榜,战胜了单依纯,而白举纲则被淘汰。节目开场时,查理普斯弹唱了《See you again》,网友纷纷感叹他的表现非常稳定。作为首位袭榜歌手,查理普斯…

武汉不扫兴的妈妈陪娃后备箱过夜 13元创造快乐回忆

一段能伴随孩子一生的快乐记忆,对极氪车主王大发来说,只需要13元。近日,她在社交媒体上分享了这段经历,讲述了一个“不扫兴的决定”如何为孩子创造了一段愉快的回忆,并让她更加思考成为有趣父母的意义。由于武汉暴雨导致小区停电,王大发一家三口决定驾车回外婆家过夜。途…