当前位置: 首页 > news >正文

[小练习]100行不到使用Java Socket网络编程实现定向聊天

先写个TCP的:

一、效果展示


二、整体结构

文件名作用
Send.java客户端入口,连接 127.0.0.1:8888
Rece.java服务端入口,监听 8888 端口
Sen.java发送线程:把键盘输入写给对端
Rec.java接收线程:把对端消息打印出来

三、运行步骤

  1. 编译

    javac *.java
  2. 启动服务

    java Rece
  3. 启动客户端(另开终端

    java Send
  4. 任意一方输入 quit 即可退出。


四、核心代码

1. 服务端 Rece.javaU26/Test2/Rece.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test2/Rece.java

public class Rece {public static void main(String[] args) {try (ServerSocket ss = new ServerSocket(8888)) {Socket s = ss.accept();System.out.println("成功连接");new Sen(s).start();   // 发new Rec(s).start();   // 收// 等待两线程结束再关 Socketwhile (Sen.isAlive() || Rec.isAlive()) Thread.sleep(100);} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}

2. 客户端 Send.java

U26/Test2/Rece.java · 伏琪/java基础语法练习 - Gitee.comhttps://gitee.com/fuqiqiqi/test/blob/master/U26/Test2/Rece.java

public class Send {public static void main(String[] args) {try (Socket socket = new Socket("127.0.0.1", 8888)) {System.out.println("成功连接");Sen sen = new Sen(socket);Rec rec = new Rec(socket);sen.start();rec.start();sen.join();rec.join();} catch (Exception e) {e.printStackTrace();}}
}

3. 发送线程 Sen.java

U26/Test2/Sen.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test2/Sen.java

public class Sen extends Thread {private final Socket s;Sen(Socket s) { this.s = s; }@Overridepublic void run() {try (Scanner sc = new Scanner(System.in);OutputStream out = s.getOutputStream()) {while (sc.hasNextLine()) {String line = sc.nextLine();out.write((line + "\n").getBytes(StandardCharsets.UTF_8));if ("quit".equalsIgnoreCase(line)) break;}} catch (IOException ignored) {}}
}

4. 接收线程 Rec.java

U26/Test2/Rec.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test2/Rec.java

public class Rec extends Thread {private final Socket s;Rec(Socket s) { this.s = s; }@Overridepublic void run() {try (BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8))) {String line;while ((line = br.readLine()) != null) {System.out.printf("%40s%n", line);}} catch (IOException ignored) {}}
}

五、线程模型图

                                               


六、心得

在写输出时,接受的消息向右对齐格式化数据,应该用printf()而不是print()。

最难的点在于不知道在哪里关闭Socket,一开始写在了工具类里,发现另一个关不了,只能写在了主函数里,在将其两个线程都运行完后关闭。



再来个UDP的,比TCP多占用一个端口:

一、效果展示

二、整体结构(4 个文件)

文件作用
Send.java客户端入口:监听 8889 接收,发向 8888
Rece.java服务端入口:监听 8888 接收,发向 8889
Sen.java发送线程:把键盘输入打成 UDP 包
Rec.java接收线程:把 UDP 包右对齐打印

三、运行步骤

  1. 编译

    javac *.java
  2. 启动服务

    java Rece
  3. 启动客户端(另开终端

    java Send
  4. 任意一方输入 quit 即可优雅退出。


四、核心源码

1. 客户端 Send.java

U26/Test3/Send.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test3/Send.java

public class Send {public static void main(String[] args) throws Exception {int listen = 8889;   // 我收int target = 8888;   // 我发DatagramSocket recvSocket = new DatagramSocket(listen);DatagramSocket sendSocket = new DatagramSocket();Rec rec = new Rec(recvSocket, listen);Sen sen = new Sen(sendSocket, target);rec.start();sen.start();rec.join();sen.join();recvSocket.close();sendSocket.close();System.out.println("聊天结束");}
}

2. 服务端 Rece.java

U26/Test3/Rece.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test3/Rece.java

public class Rece {public static void main(String[] args) throws Exception {int listen = 8888;   // 我收int target = 8889;   // 我发DatagramSocket recvSocket = new DatagramSocket(listen);DatagramSocket sendSocket = new DatagramSocket();Rec rec = new Rec(recvSocket, listen);Sen sen = new Sen(sendSocket, target);rec.start();sen.start();rec.join();sen.join();recvSocket.close();sendSocket.close();System.out.println("聊天结束");}
}

3. 发送线程 Sen.java

U26/Test3/Sen.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test3/Sen.java

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class Sen extends Thread {private final DatagramSocket socket;private final int targetPort;public Sen(DatagramSocket socket, int targetPort) {this.socket = socket;this.targetPort = targetPort;}@Overridepublic void run() {try (Scanner sc = new Scanner(System.in)) {while (true) {String line = sc.nextLine();byte[] data = line.getBytes(StandardCharsets.UTF_8);DatagramPacket packet = new DatagramPacket(data, data.length,InetAddress.getByName("127.0.0.1"), targetPort);socket.send(packet);if ("quit".equalsIgnoreCase(line)) break;}} catch (IOException e) {e.printStackTrace();}}
}

4. 接收线程 Rec.java

U26/Test3/Rec.java · 伏琪/java基础语法练习 - 码云 - 开源中国https://gitee.com/fuqiqiqi/test/blob/master/U26/Test3/Rec.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;public class Rec extends Thread {private final DatagramSocket socket;private final int localPort;public Rec(DatagramSocket socket, int localPort) {this.socket = socket;this.localPort = localPort;}@Overridepublic void run() {byte[] buf = new byte[1024];DatagramPacket packet = new DatagramPacket(buf, buf.length);try {while (!isInterrupted()) {socket.receive(packet);String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);System.out.printf("%40s%n", msg);if ("quit".equalsIgnoreCase(msg)) break;}} catch (IOException ignored) {} finally {socket.close();}}
}

五、线程模型图

                                               

六,心得

        起初认为UDP只能有一个本地的来接收信息,所以我之前任务只能单向聊天,后来想到可以用不同端口监听消息,就可以实现多人聊天了。

        不清楚为什么在写工具类时类的Datagramet成员访问不到,设置public都不行,最后加了个this才访问到。

        接受消息时传入的Scoket可以不用传地址;

        因为不像TCP只有一个Scoket,当一个暂停时,一方只能收,一方只能听,因此传两个Scoket,可以都暂停。


        我是伏琪,关注订阅号伏琪了解更多。 

http://www.dtcms.com/a/350962.html

相关文章:

  • 从双重检查锁定的设计意图、锁的作用、第一次检查提升性能的原理三个角度,详细拆解单例模式的逻辑
  • 基于SpringBoot的网上点餐系统
  • OpenTenBase核心技术解密:突破OLTP与OLAP边界的分布式数据库革新
  • Flask模块如何使用
  • 浅谈技术顾问的转型困境
  • Web前端开发基础
  • windows 下 使用C++ 集成 zenoh
  • ArcGIS学习-9 ArcGIS查询操作
  • vLLM轻松通
  • ArcGIS学习-10 空间连接和矢量分析
  • 百度IOS客户端岗位--面试真题分析
  • 5G 三卡图传终端:应急救援管理的 “可视化指挥核心”
  • PostgreSQL诊断系列(3/6):性能瓶颈定位——缓冲池、I/O与临时文件
  • 【Linux系统】线程概念
  • 【R代码分析】甲烷排放绘制代码-参考论文
  • 【云原生】CentOS安装Kubernetes+Jenkins
  • RAW API 的 UDP 总结1
  • Android Glide常见问题解决方案:从图片加载到内存优化
  • [在实践中学习] 中间件理论和方法--Redis
  • 【JavaEE】了解volatile和wait、notify(三)
  • 08-引入AI编程插件(TRAE)编写单元测试并检查覆盖率
  • Cloudflare 推出 GenAI 安全工具,守护企业数据
  • 科普 | 5G支持的WWC架构是个啥(1)?
  • android 改机系列之-虚拟摄像头-替换相机预览画面
  • excel导出,多列合并表头
  • 运行node18报错
  • 【JVM】类加载器都有哪些?
  • ChromaDB向量数据库Python教程:从入门到实战完整指南(含游戏资源管理系统案例
  • Java大厂面试实战:从Spring Boot到微服务架构的全链路技术拆解
  • 计算机视觉:从 “看见” 到 “理解”,解锁机器感知世界的密码