java-网络编程-(socket)-聊天室的编写 -01

socket 是java中的一插口,要实现网络通信的话,需要连接插口和插口,而数据的传输使用了流的思想,读数据操作运用了输入流,而写数据运用了输出流,

聊天对话的实现

一个类作为服务端对象,用于接受客户端写出的输出流,

一个类作为客户端对象,用于输到的服务端的进行读取的输入流.

client客户端的类

私有一个成员变量 Socket插口

构造方法会优先比普通方法先调用,这边可以先定义一下客户端新建一个实例对象初始化的行为

public class Client {/*java.net.Socket 套接字Socket封装了TCP协议的通讯细节,使用它可以和远端计算机建立网络链接,并基于两条流(一条输入,一条输出)的读写与对方进行数据交换。*/private Socket socket;/*** 构造器,用于初始化客户端*/public Client(){try {System.out.println("正在链接服务端...");/*Socket实例化时就是与服务端建立链接的过程,此时需要传入两个参数参数1:服务端的IP地址,用于找到服务端的计算机参数2:服务端口,用于找到服务端程序如何查看IP地址:windows:窗口键+R 打开控制台输入ipconfig查看以太网适配器-以太网,找到ipv4查看自己的IP地址mac:打开[终端]程序输入/sbin/ifconfig查看自己的IP地址*/
//            socket = new Socket("127.0.0.1",8088);//127.0.0.1和localhost都是表示本机socket = new Socket("localhost",8088);System.out.println("与服务端成功链接!");} catch (IOException e) {e.printStackTrace();}}}

主要点 Socket 需要传递两个参数 ip地址(服务端)  服务端占用的端口

ip地址 查看 

  如何查看IP地址:
                windows:窗口键+R 打开控制台
                        输入ipconfig
                        查看以太网适配器-以太网,找到ipv4查看自己的IP地址

                mac:打开[终端]程序
                    输入/sbin/ifconfig查看自己的IP地址
             */

socket端口查看

Windows系统:

  1. 按住Windows键+R,唤出运行对话框。
  2. 在对话框里输入“cmd”,然后点确定,就会出现cmd窗口。
  3. 在cmd窗口中输入命令“netstat -an”,然后回车,就能看见当前连接的列表,其中冒号后面跟着的数字就是端口号

 这边定义一个运行方法

public void start(){/*Socket提供的方法:OutputStream getOutputStream()通过Socket获取一个字节输出流,通过向该流写出字节,就可以发送给远端链接的计算机的Socket了*/try {OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);BufferedWriter bw = new BufferedWriter(osw);PrintWriter pw = new PrintWriter(bw, true);pw.write(12);}catch (IOException e) {e.printStackTrace();} finally {try {//socket的close方法会进行四次挥手//并且也会关闭通过socket获取的输入流和输出流socket.close();} catch (IOException e) {e.printStackTrace();}}}

finally是无论程序执行过程中是否发生异常都会执行,并且在强制退出方法也会执行,使用return中断下方的代码,强制退出该方法也会执行finally,

选择拔插口是不选择关闭文件流是为了告诉服务端 ,客户端想要中断输出,是为了保证传输的可靠性

三次握手主要用于建立TCP连接。这个过程包括三个步骤:

  1. 客户端发送一个带有SYN(synchronize)标志的数据包给服务端,并进入SYN_SEND状态,等待服务器确认。
  2. 服务端收到SYN包后,确认客户的SYN(ACK=客户端序列号+1),同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN_RECV状态。
  3. 客户端收到服务器的SYN+ACK包后,向服务器发送确认包ACK(ACK=服务器序列号+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手后,客户端与服务器端开始传送数据。

四次挥手则用于断开TCP连接。这个过程同样包含四个步骤:

  1. 客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT1状态。
  2. 服务端收到连接释放报文,发出确认报文,ACK=1,ack=序号+1,并且带上自己的序列号,服务端就进入了CLOSE_WAIT状态。此时TCP连接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接受。
  3. 若服务端也没有数据要发送了,就通知客户端,发送一个FIN,即释放数据报文,之后服务端进入LAST_ACK状态,等待客户端的确认。
  4. 客户端收到服务端的释放数据报文后,必须发出确认,ACK=1,ack=序号+1,而自己的序列号是seq=序号+1,此时,客户端就进入了TIME_WAIT状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

四次挥手中,服务器发送完ACK之后,释放了服务器端到客户端的数据传送,但是客户端到服务器端的这个方向数据传送还没有释放,所以客户端最后还要发送一次确认。

总的来说,三次握手和四次挥手确保了TCP连接的建立和断开过程中的数据同步和可靠性,是TCP/IP协议中非常重要的部分。

 最后运行

public static void main(String[] args) {//实际开发中不会在main方法中写业务逻辑,main方法是静态方法会有很多不便Client client = new Client();//调用构造器初始化客户端client.start();//调用start方法使客户端开始工作
}

服务端的类

 服务端构造方法定义一个启动服务端使用初始化行为,私有化的服务端插口

public class Server {/*java.net.ServerSocket运行在服务端的ServerSocket相当于时客户中心的"总机",上面有若干的插座(Socket)客户端的插座就是与总机建立链接,然后总机这边分配一个插座与之建立链接,来保持双方通讯的。ServerSocket有两个主要工作1:创建时向系统申请服务端口,以便客户端可以通过端口找到2:监听该端口,一旦一个客户端链接,便创建一个Socket,通过它与客户端通讯*/private ServerSocket serverSocket;public Server(){try {System.out.println("正在启动服务端");/*实例化ServerSocket时需要指定向系统申请的服务端口,如果该端口已经被系统的其他应用程序占据,则这里会抛出异常java.net.BindException: Address already in use: bind()*/serverSocket = new ServerSocket(8088);System.out.println("服务端启动完毕");} catch (IOException e) {throw new RuntimeException(e);}}

ServerSocket 的参数是一个服务端占用的端口 

服务端运行的方法

public void start(){try {System.out.println("等待客户端链接...");/*ServerSocket的重要方法:Socket accept()该方法是一个阻塞方法,调用该方法后程序会"卡住",直到一个客户端使用Socket与服务端建立链接为止,此时accept方法会立即返回一个Socket通过返回的Socket就可以与链接的客户端双向通讯了。*/Socket socket = serverSocket.accept();System.out.println("一个客户端链接了!");InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,StandardCharsets.UTF_8);BufferedReader br = new BufferedReader(isr);String message;while ((message = br.readLine()) != null) {//张三[192.168.2.5]说:XXXXSystem.out.println(nickname+"[" + ip + "]说:" + message);} catch (IOException e) {e.printStackTrace();}}

服务端运行程序

public static void main(String[] args) {Server server = new Server();server.start();
}

 整理

客户端

ublic class Client {/*java.net.Socket 套接字Socket封装了TCP协议的通讯细节,使用它可以和远端计算机建立网络链接,并基于两条流(一条输入,一条输出)的读写与对方进行数据交换。*/private Socket socket;/*** 构造器,用于初始化客户端*/public Client(){try {System.out.println("正在链接服务端...");/*Socket实例化时就是与服务端建立链接的过程,此时需要传入两个参数参数1:服务端的IP地址,用于找到服务端的计算机参数2:服务端口,用于找到服务端程序如何查看IP地址:windows:窗口键+R 打开控制台输入ipconfig查看以太网适配器-以太网,找到ipv4查看自己的IP地址mac:打开[终端]程序输入/sbin/ifconfig查看自己的IP地址*/
//            socket = new Socket("127.0.0.1",8088);//127.0.0.1和localhost都是表示本机socket = new Socket("localhost",8088);System.out.println("与服务端成功链接!");} catch (IOException e) {e.printStackTrace();}}/*** 用于客户端开始工作的方法*/public void start(){/*Socket提供的方法:OutputStream getOutputStream()通过Socket获取一个字节输出流,通过向该流写出字节,就可以发送给远端链接的计算机的Socket了*/try {OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);BufferedWriter bw = new BufferedWriter(osw);PrintWriter pw = new PrintWriter(bw, true);pw.write(01)} catch (IOException e) {e.printStackTrace();} finally {try {//socket的close方法会进行四次挥手//并且也会关闭通过socket获取的输入流和输出流socket.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) {//实际开发中不会在main方法中写业务逻辑,main方法是静态方法会有很多不便Client client = new Client();//调用构造器初始化客户端client.start();//调用start方法使客户端开始工作}

服务端

public class Server {/*java.net.ServerSocket运行在服务端的ServerSocket相当于时客户中心的"总机",上面有若干的插座(Socket)客户端的插座就是与总机建立链接,然后总机这边分配一个插座与之建立链接,来保持双方通讯的。ServerSocket有两个主要工作1:创建时向系统申请服务端口,以便客户端可以通过端口找到2:监听该端口,一旦一个客户端链接,便创建一个Socket,通过它与客户端通讯*/private ServerSocket serverSocket;public Server(){try {System.out.println("正在启动服务端");/*实例化ServerSocket时需要指定向系统申请的服务端口,如果该端口已经被系统的其他应用程序占据,则这里会抛出异常java.net.BindException: Address already in use: bind()*/serverSocket = new ServerSocket(8088);System.out.println("服务端启动完毕");} catch (IOException e) {throw new RuntimeException(e);}}public void start(){try {System.out.println("等待客户端链接...");/*ServerSocket的重要方法:Socket accept()该方法是一个阻塞方法,调用该方法后程序会"卡住",直到一个客户端使用Socket与服务端建立链接为止,此时accept方法会立即返回一个Socket通过返回的Socket就可以与链接的客户端双向通讯了。*/Socket socket = serverSocket.accept();System.out.println("一个客户端链接了!");InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,StandardCharsets.UTF_8);BufferedReader br = new BufferedReader(isr);String message;while ((message = br.readLine()) != null) {//张三[192.168.2.5]说:XXXXSystem.out.println(nickname+"[" + ip + "]说:" + message);} catch (IOException e) {System.out.println(e);}}

问题 分析 

问题 这个客户端只能固定写死输出的数据,不能根据用户输入的内容传递到服务端,使服务端读取数据

这个问题,需要解决的话客户端需要用的Scanner,替换之前单调输出 pw.write()

 Scanner scanner = new Scanner(System.in);while(true) {String line = scanner.nextLine();if("exit".equalsIgnoreCase(line)){break;}pw.println(line);}

需要提醒的是,Scanner中 nextline 是根据换行符鉴定用户是否输入一行内容,而PrintWriter是可以根据换行符刷新更新数据的,PrintWriter pw = new PrintWriter(bw, true);这边写了true是表示字符串输出流可以根据鉴定用户是否换行来刷新数据,记得 一定要使用printIn 或者 print(+"\n").

问题 假如多个客户端需要连接一个服务端怎么办

可以循环新建一个接受用户的插口

public void start(){while(true){try {System.out.println("等待客户端链接...");/*ServerSocket的重要方法:Socket accept()该方法是一个阻塞方法,调用该方法后程序会"卡住",直到一个客户端使用Socket与服务端建立链接为止,此时accept方法会立即返回一个Socket通过返回的Socket就可以与链接的客户端双向通讯了。*/Socket socket = serverSocket.accept();System.out.println("一个客户端链接了!");InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,StandardCharsets.UTF_8);BufferedReader br = new BufferedReader(isr);String message;while ((message = br.readLine()) != null) {//张三[192.168.2.5]说:XXXXSystem.out.println(nickname+"[" + ip + "]说:" + message);}} catch (IOException e) {e.printStackTrace();}}

问题 多个客户端连接一个服务器,同时不同客户端给服务端发送消息,服务端只能接受第一个人发生来的消息

原因分析 第一 服务端start方法使用两个循环,内存循环除非执行完,才能执行外层循环,而内层循环的Scanner是获取用户的输入,而内层需要结束需要根据用户的输入和字符串比较才能得到的结果.

我们需要引入一个新的概念 线程 线程是将我们程序用一条线的方式按照顺序依次执行.

这个我打算整理完,再说,我也是一个刚学的新手😂😂

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

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

相关文章

css隐藏溢出隐藏的滚动条

msOverflowStyle: none: 这个属性用于在 Internet Explorer 浏览器中定义滚动条的样式。将其设置为 none 可以隐藏滚动条。 scrollbarWidth: none: 这个属性用于定义滚动条的宽度。将其设置为 none 可以隐藏滚动条。这个属性在一些新的浏览器中被支持,如 Firefox。…

巧克力(蓝桥杯)

文章目录 巧克力题目描述解题分析贪心 巧克力 题目描述 小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。 一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的…

基于《2023腾讯云容器和函数计算技术实践精选集》—探索腾讯云TKE的Docker容器、Serverless和微服务优势

重剑无锋,大巧不工。 ——金庸 腾讯云TKE,全称Tencent Kubernetes Engine,是一种完全托管式的容器服务。它可以帮助用户快速、高效地部署和管理Kubernetes集群,并提供一系列与之相关的云服务,如负载均衡、云硬盘、对象…

OSPF---开放式最短路径优先协议

1. OSPF描述 OSPF协议是一种链路状态协议。每个路由器负责发现、维护与邻居的关系,并将已知的邻居列表和链路费用LSU报文描述,通过可靠的泛洪与自治系统AS内的其他路由器周期性交互,学习到整个自治系统的网络拓扑结构;并通过自治系统边界的路…

掼蛋游戏规则

1、牌型:单牌、对牌、三张牌、三带二、顺子、同花顺、钢板(例: 222333、444555)、炸弹(4涨以上相同的牌)、三连对 2、牌大小:大王,小王,级牌,A,…

从学习海底捞到学习巴奴,中国餐饮带洋快餐重归“产品主义”

俗话说“民以食为天”,吃饭一向是国人的头等大事,餐饮业也是经济的强劲助推力。新世纪以来,餐饮业不断讲述着热辣滚烫的商业故事。 2006年,拥有“必胜客”、“肯德基”等品牌的餐饮巨头百胜集团,组织两百多名区域经理…

太阳能光伏发电应用场景有哪些?

随着全球能源结构的转型和环保意识的提升,太阳能光伏发电作为一种清洁、可再生的能源形式,其应用场景正日益广泛。下面,我们将详细探讨太阳能光伏发电的主要应用场景。 首先,工业领域是太阳能光伏发电的重要应用领域。工业厂房通常…

EasyCVR视频汇聚平台海康Ehome2.0与5.0设备接入时的配置区别

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Nessus【部署 01】Linux环境部署漏洞扫描工具Nessus最新版详细过程分享(下载+安装+注册+激活)

Nessus最新版详细部署过程分享 1. 获取激活码2.主程序下载安装启动2.1 下载2.2安装2.3 启动 3.许可证及插件3.1 许可证获取3.2 插件安装 4.安装总结 Nessus官方网站: https://www.tenable.com/products/nessus/nessus-essentials 及介绍: 国际数据公司&…

AMBE-2000

这份文件是关于AMBE-2000™ Vocoder Chip的用户手册,由Digital Voice Systems, Inc. (DVSI) 提供。以下是手册的核心内容概要: 产品介绍: 产品介绍部分详细描述了AMBE-2000™ Vocoder Chip的主要特点和优势,以及它的应用领域。以下…

编程语言 MoonBit 本周有超多重磅更新等你来探索:expect 测试添加 inspect 函数,还有……

MoonBit 更新 1. expect 测试添加 inspect 函数 expect 测试添加针对 Show 接口的 inspect 函数,签名如下: pub fn inspect(obj: Show,~content: String "",~loc: SourceLoc _,~args_loc: ArgsLoc _ ) -> Result[Unit, String]⚠️ 此…

什么是软件缺陷(bug)?

什么是软件缺陷(bug)? 定义1:软件缺陷是计算机系统或程序中存在的任何一种破坏正常运行能力的问题或错误,或隐藏的功能缺陷或瑕疵。缺陷会导致软件产品在某种程度上不能满足用户的需求。 定义2:从产品内部…

ConfigMap和Secret配置Pod环境变量与热更新

目录 环境变量注入 卷挂载 最佳实践 在云原生应用开发和部署过程中,ConfigMap 和 Secret 是非常重要的资源对象,用于存储和管理应用程序的配置信息和敏感数据。然而,当我们更新 ConfigMap 或 Secret 的内容时,对于已经运行的 P…

C++函数重载引用

函数重载 自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男…

Mybatis(3) web项目

web项目 1、准备2、分析3、 MyBatis对象作用域以及事务问题4、问题 实现一个转账系统 1、准备 ①准备一个web模块 在这里使用了maven archetype,选择web 之后会生成 一个web模块,但是不同的版本可能不同,在这里我就没有java和resources目录&…

KUKA机器人更改时间和HMI最小化设置

在使用 KUKA 机器人时,示教器上左边有个“表”的图标,点一下就会显示时间。但一般不准,想要更改时间可以通过HMI最小化后进行更改设置。更改时间需要将示教器界面最小化,也就是进入Windows 界面。通过以下步骤可以进行设置&#x…

ThreadLocal的基本使用

一、ThreadLocal的介绍 ThreadLocal 是 Java 中的一个类,它提供了线程局部变量的功能。线程局部变量是指每个线程拥有自己独立的变量副本,这些变量在不同的线程中互不影响。ThreadLocal 提供了一种在多线程环境下,每个线程都可以独立访问自己…

多叉树题目:N 叉树的最大深度

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:N 叉树的最大深度 出处:559. N 叉树的最大深度 难度 3 级 题目描述 要求 给定一个 N 叉树&#xf…

navicat12版本重置试用期时间

一、步骤 关闭NavicatWin R,输入regedit回车删除HKEY_CURRENT_USER\Software\PremiumSoft\Data删除HKEY_CURRENT_USER\Software\Classes\CLSID 二、这注册表直接删了,没什么安全问题 删了方便,只能这么说HKEY_CURRENT_USER\Software\Prem…

正弦实时数据库的应用(1)-数字孪生

前面说过实时数据库比较合适应用在数字孪生系统上,本篇就来对比一下数字孪生系统各种数据存储的应用方案的优缺点,几种典型的数据存储方式如下所示: 方案一:RedisMySQL/MongoDB方案二:MongoDB方案三:时序数…