多线程和网络编程实践——LittleTom

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档) 本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。 阅读详情

这两天写了一个小应用,实现基本的聊天功能。该应用既是客户端也是服务器,不要求某一方先发起连接请求。但同一时间仅能两个ip互相传输数据。用上了最近学的多线程和网络编程相关知识。先贴上初稿,还有问题,以后有空再琢磨琢磨。

两个类:LittleTom.class, TalkThread.class

1. LittleTom.java

import java.io.*;
import java.net.*;

public class LittleTom {
    private Wait waitThread = null;
    private Connect connectThread = null;
    private ServerSocket waitSocket;
    private Socket socket;
    private BufferedReader br = null;
    private int waitPort = 10001;
    private int connectPort = 10002;
    private boolean isConnecting = false;
    
    public LittleTom() {
        br = new BufferedReader(new InputStreamReader(System.in));
        
        waitThread = new Wait();
        connectThread = new Connect();
        
        waitThread.start();
        connectThread.start();
    }
    
   class Wait extends Thread {
       public void run(){
           waitConnect();
       }
       
       synchronized private void waitConnect() {
           try {
               waitSocket = new ServerSocket(waitPort);
               while(true) {                          
                   if(!isConnecting) {
                       Socket memberSocket = waitSocket.accept();
                       if(!isConnecting) {
                           isConnecting = true;
                           System.out.println(memberSocket.getInetAddress().getHostName() + " want to talk with you.");
                           new TalkThread(LittleTom.this, memberSocket);
                       } else {
                           System.out.println("Wait::You can only speak with one preson at the same time.");
                           continue;
                       }
                   } else {
                       wait();
                   }
               }
           } catch(Exception e) {
               e.printStackTrace();
           } finally {
               try {
                   if(waitSocket != null){
                       waitSocket.close();
                   }
                  
                   if(socket != null) {
                       socket.close();
                   }

                   br.close();
               } catch(Exception e) {
                   e.printStackTrace();
               }
           }
       }
   }
   
   class Connect extends Thread {
       public void run(){
           tryToConnect();
       }
       synchronized private void tryToConnect() {
           try{
               while(true) {
                   if(!isConnecting) {
                       System.out.println("Please input the IP that you want to talk with: ");
                       br = new BufferedReader(new InputStreamReader(System.in));
                       String input = br.readLine();
//                       String IP = "109.123.102.117";
                       if(!isConnecting) {
                           isConnecting = true;
                           System.out.println("Try to connecting...");
                           socket = new Socket(input, connectPort);
                           new TalkThread(LittleTom.this, socket); 
                           
                       } else {
                           System.out.println("Connect::You can only speak with one preson at the same time.");
                           continue;
                       }
                   } else {
                       wait();
                   }
               }
           } catch(Exception e) {
               System.out.println("connect fail.");
               e.printStackTrace();
           } finally {
               try {
                   if(waitSocket != null){
                       waitSocket.close();
                   }
                  
                   if(socket != null) {
                       socket.close();
                   }

                   br.close();
               } catch(Exception e) {
                   e.printStackTrace();
               }
           }
       }
   }
   

   public void resetConnection() {
        isConnecting = false;
        synchronized(waitThread) {
            waitThread.notify();
        }
        synchronized(connectThread) {
            connectThread.notify();
        }
    }
   
    public BufferedReader getSystemBuffer() {
        return br;
    }

    public static void main(String[] args) {
            LittleTom lt = new LittleTom();
    }
    
}

2. TalkThread.java

import java.io.*;
import java.net.*;


public class TalkThread {
    private LittleTom littleTom;
    private Socket memberSocket;
    private String peer;
    private InputStream is;
    private OutputStream os;
    
    private Thread receiveThrd = null;
    private Thread sendThrd = null;
   
    
    public TalkThread(LittleTom lt, Socket socket){
        try {
            this.littleTom = lt;
            this.memberSocket = socket;
            peer = memberSocket.getInetAddress().getHostName();
            is = memberSocket.getInputStream();
            os = memberSocket.getOutputStream(); 
            receiveThrd = new Thread() {
                public void run(){
                    receive();
                    sendThrd.stop();
                    close();
                    littleTom.resetConnection();
                }
            };

            sendThrd = new Thread() {
                public void run(){
                    send();
                    receiveThrd.stop();
                    close();
                    littleTom.resetConnection();
                }
            };
            
            receiveThrd.start();
            sendThrd.start();
        } catch(Exception e) {
            e.printStackTrace();
        } 
    }

    private void receive() {
        byte[] b = new byte[1024];
        String receiveMsg = null;
        try {
            do {
                int n = is.read(b);
                if(n<=0) {
                    continue;
                }
                receiveMsg = new String(b, 0, n); 
                System.out.println(peer + " say >>>> " + receiveMsg);
            } while(receiveMsg == null || !receiveMsg.equalsIgnoreCase("exit"));
        } catch(Exception e) {
            if(memberSocket.isClosed()){
                System.out.println("receive::socket is closed.");
            } else {
                e.printStackTrace();
            }
        }
    }
    
    private void send() {
//        byte[] b = new byte[1024];
        String input = null;
        try {
            do {
                input = littleTom.getSystemBuffer().readLine();
                if(input == null) {
                    continue;
                }
                System.out.println("I say >>>> " + input);
                os.write(input.getBytes());
            } while((input == null) || (!input.equalsIgnoreCase("exit")));
        } catch(Exception e) {
        	if(memberSocket.isClosed()){
                System.out.println("send::socket is closed.");
            } else {
                e.printStackTrace();
            }
        } 
    }
    
    public void close() {
        try {
            is.close();
            os.close();
            memberSocket.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}


    程序运行起来还有问题:

        1. 被动接受连接的一方,第一次用户输入的数据不能发送出去。原因是数据被tryToConnect读到,并被认为是用户输入的IP地址,所以尝试去连接。连接失败,打印"Connect::You can only speak with one preson at the same time.", 再次进入循环的时候,由于isConnecting==true,直接进入等待。然后后面用户的输入就能发送出去了。但是怎么修复这个bug啊?

        2. 连接只能进行一次。一方exit,然后再尝试去连就连不上了。但是程序并没有退出。求高手解答。

 

 


 

二进制部署的K8s集群,如何对到期证书更新 一年前搭建的k8s集群,突然不能够正常访问,出现502错误,首先怀疑容器没起来,先对问题进行排查,排查响应的容器有没有正常启动,状态一切正常,访问容器地址也可以正常访问,于是访问node port地址,发现无法正常访问,确定问题出现在svc中。 由于其他的应用、系统也无法提供正常的服务,应该是k8s的问题,非单个应用的原因。查看服务状态,kubectl describe svc xxx,endp... 阅读详情

相关推荐

HC32F460 SPI DMA 实现高效TFT屏幕刷新的实战解析

本文针对HC32F460 MCU驱动TFT屏幕时刷新卡顿的问题,深入解析了SPI DMA技术的实战应用。通过对比传统查询模式与DMA模式的性能数据,详细阐述了如何配置SPI与DMA资源、构建核心驱动框架,并提供了避坑指南与进阶优化思路,最终实现高效、流畅的屏幕刷新,显著降低CPU占用率。

weixin_29163797的博客 152

(TCP IP网络编程)实验七 多线程编程

一.实验目的 (1) 理解线程和进程的联系和区别; (2) 掌握Linux下和Windows下创建线程的方法; (3) 掌握Linux下和Windows下线程同步的方法; (4) 使用多线程机制实现Linux下和Windows下服务器编程。 二.实验内容 (1)Linux下的线程同步 (1.1)编程使用互斥量实现线程同步; (1.2)编程使用信号量实现线程同步,要求实现以下功能:“线程A从用户输入得到值后存入全局变量num,此时线程B将取走该值并累加。该过程共进行5次,完成后输出总和并退出程序”; (

weixin_44209522的博客 2489

Swift Package Manager (SPM) 创建并集成本地库

Swift Package Manager (SPM) 在macOS 项目中创建并集成的完整步骤

征战无悔人生 1425

实验六(6) 线程及网络编程实验 (笔记)

实验六(6) 线程及网络编程实验 (笔记) (一)线程实验 实验目的: 了解线程定义、工作特点;掌握线程的创建、同步和互斥、条件变量的应用等编程实现方法,分析程序的执行流程和理解代码含义。 实验内容: (1)线程创建 说明: int pthread_create(pthread_t *tid, const pthread_attr_t *tattr, void*(*start_routine)(...

ZH 754

Transformer模型详解(图解最完整版)

Transformer由论文提出,现在是谷歌云TPU推荐的参考模型。论文相关的Tensorflow的代码可以从GitHub获取,其作为Tensor2Tensor包的一部分。哈佛的NLP团队也实现了一个基于PyTorch的版本,并注释该论文。在本文中,我们将试图把模型简化一点,并逐一介绍里面的核心概念,希望让普通读者也能轻易理解。Transformer 与 RNN 不同,可以比较好地并行训练。

2501_91695094的博客 2703

在pycharm2021.2中学习opencv图像处理,基于python3.9.7、pycharm完成配置

在pycharm中学习opencv图像处理安装python下载python安装包开始安装安装pycharm社区版下载pycharm开始安装如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 安装python 使用pycharm学习opencv应该是最简单的了,对新手比较友好,

steveqobs 7710

实验七多线程编程_JAVA

实验目的: (1)了解进程和线程的概念 (2)了解多线程编程的特点 (3)利用Thread类和Runnable接创建多线程类 (4)掌握线程类的常用方法 (5)掌握多线程同步的方法 实验内容: 1、利用多线程类实现20个偶数和20个奇数的随机输出。 2、利用多线程编程实现多个窗口卖票的问题: (1)三个窗口同时各卖10张票; (2)三个窗口共同卖10张票。 3、编写多线程程序,实现生产者、消费者线程,并实现线程的同步: (1)生产者线程产生20个数,消费者线程输出生产者线程产生的这20个数。 (2)使用线程

baiqiaoxiang的博客 848

基于Dify构建银行智能客服:从意图识别到多RAG架构的实战解析

本文深入解析了如何利用Dify平台构建银行智能客服系统。从传统客服痛点出发,详细阐述了基于意图识别精准分类用户需求,并通过多RAG架构解决知识混淆问题,实现高效、准确的业务响应。文章重点介绍了结合工具调用实现业务流程自动化,并强调了数据本地化部署、内容安全过滤等银行级安全合规实践,为金融行业AI应用提供了实战指南。

yog99的博客 926

Java面向对象与多线程综合实验(六)之网络编程

本次代码沿用第三次中的User.java Administrator.java Operator.java Browser.java和Doc.java 和第五次中的DataProcessing.java 并且借用大部分了老师提供的Client.java和Server.java代码 WinMain.java 需要运行的主程序 import java.sql.SQLException; imp...

有机盐的博客 3564

【施磊】C++课程笔记目录

【C++编程】施磊老师C++笔记目录

GeniusAng的博客 4124

SAP-ABAP: BP主数据完全指南:从基础到高阶应用

SAP-ABAP: BP主数据完全指南:从基础到高阶应用

baidu_35680696的博客 1647

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 295

微信小程序 - 解决微信支付报错 requestPayment:fail no permission 原因分析及排查处理(支付失败出错,无法唤起支付弹框面板,微信支付API报错请求付款:失败无权限)

微信小程序,微信支付,支付报错,errMsg: "requestPayment:fail no permission",支付失败,支付权限没问题,微信小程序支付报错,检查了appid正确依旧不行,微信小程序支付异常,苹果ios手机,安卓手机,开发者工具模拟器,最新解决教程,小程序wx.requestPayment报错/无响应,小程序支付 requestPaym,微信小程序认证,真机运行,小程序微信支付提示错误,微信小程序里使用微信支付错误提示,微信小程序支付异常,微信支付弹框拉不起来,小程序支付api,都检

🏆 前端领域优质创作者 1万+

信创环境下PageOffice文档控件适配与实践

信创适配做到文档控件这一层,拼的已经不是"有没有国产版本",而是同一个功能在两类终端上是否真的等价。等价的标准很具体:同一次点击能得到同样的结果,同一份公文能得到同样的版式,同一个项目不需要维护两套代码。这背后是三件并不轻松的工作:服务端用一套接口同时支撑两类终端,客户端把两种系统与四种芯片的安装包分发清楚,文档内核层由产品侧跟着 WPS 的版本走。浏览器这一层的压力,则被收进了产品自己的窗口里——升级节奏由产品掌握,不再交给运气。

zi_wu_xian的专栏 326

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 351

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

第三篇 第 6 课

前置:第三篇第 1 课(stdx 引入),第二篇第 1 课(std.regex)。环境:仓颉 SDK 1.2.0。本文所有代码与输出均逐行实测。

weixin_41618057的博客 513

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 532

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 416

spdlog 同步日志库使用详解

spdlog是一个轻量级 C++ 日志库,支持同步日志、异步日志、多线程日志、日志文件轮转和自定义日志格式。对于嵌入式 Linux 应用开发,我建议先使用。它可以帮我们完成:日志级别过滤。时间戳和线程 ID 输出。日志格式化。终端和文件输出。多线程安全写入。日志文件按大小或时间轮转。我们不需要自己实现互斥锁、文件写入、日志格式化和轮转等底层功能。

zengjiajun2006的博客 1118

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367

JavaSE通关手册:数据类型与变量

代码无需额外处理,编译时编译器自动完成转换。

xys_678的博客 207

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 172

Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

【代码】Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

m0_64476639的博客 338

c++ explicit关键字详解

explicit。

拒绝AI文,努力在AI时代写出感动人心的好文章 151

TRingBuffer两端都能增删(快递站版)

TRingBuffer 是一个支持两端增删、下标访问且容量动态增长的环形双端队列。它通过无符号索引的永不归零设计,利用减法自动模运算实现空满判断与元素计数,避免了传统环形缓冲浪费格子的问题。内部以票号(索引)标记首尾,扩容时重排元素为连续存储,保证 O(1) 操作与高缓存效率。虽不线程安全,但其高效性使其成为游戏开发中事件队列、命令缓冲等场景的理想选择。

u013768914的博客 301

ubuntu安装hadoop系统

本文详细介绍了基于VMware克隆虚拟机搭建三节点Hadoop分布式集群的全过程:使用同一Ubuntu镜像克隆出master、worker1、worker2三台虚拟机,依次配置主机名、固定IP(如192.168.82.10/11/12)、SSH服务及免密登录,确保节点间网络互通。随后安装Java,下载配置Hadoop并分发至各节点,最终初始化启动集群,验证其存储与计算功能,实现高效的大数据环境部署。

qq_43592674的博客 349
上一篇: android layout_weight相关
下一篇: http请求
zhhx310
博客等级 码龄18年 2粉丝 12原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值