文章目录

  • 前言
  • 一、Socket是什么?
  • 二、我们能用Socket做什么?
    • 1.网络聊天室的搭建
      • 1.1首先我们来整理思路:
      • 1.2服务端Server:
      • 1.3 客户端Client:
  • 总结

前言

—不少人初学java接触到的第一个就有挑战性的方面就是Socket编程,本文就对Socket编程中的聊天室进行解析

一、Socket是什么?

百度上是这么讲的:套接字就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口

二、我们能用Socket做什么?

1.网络聊天室的搭建

1.1首先我们来整理思路:

搭建一个聊天室需要服务端和客户端两套程序,用于进行信息的交互,其中服务端是只开启一个的,客户端是需要供多人同时使用的

1.2服务端Server:

一个java程序无非两部分构成,成员变量和方法,作为服务端我们首先需要
(1)一个私有成员变量ServerSocket用来存放服务端的Socket信息,ServerSocket与Socket不同,ServerSocket是专门用来等待客户端的连接的,一旦获得一个连接就创建一个Socket实例来与客户端进行通讯
(2)一个装PrintWriter类型的集合,用来记录需要转发每一条信息给每一个客户端的输出流,实现群聊功能

接下来是方法这些
1.构造方法

public Server(){try {/*** 实例化ServerSocket的同时需要指定打开的服务端口,客户端就是通过* 端口建立连接的* 如果改端口已经被其他程序占用了,那么这里就会抛出异常* java.net.BindException:address already in use*              绑定异常*/System.out.println("正在启动服务端...");server=new ServerSocket(8088);System.out.println("服务端启动成功!");} catch (IOException e) {e.printStackTrace();}}

2.启动方法start()
当服务端启动后便应该开始接收来自客户端的连接

public void start(){try {int ClientNum=0;//记录连接的客户端数量while(true){System.out.println("等待客户端连接中...");Socket socket = server.accept();//这里完成对socket的赋值System.out.println("一个客户端接入!");ClientNum++;Runnable handler=new ClientHandler(socket,ClientNum);//将每一个客户端的连接处理分发给一个线程Thread t=new Thread(handler);t.start();//这个是线程的启动方法,并不是本方法,不要混淆}} catch (IOException e) {e.printStackTrace();}}

3.处理线程
首先在线程方法中我们需要获取本次连接的Socket,通过Socket获取输入流以及创建一个输出流,对信息进行接收、解码、阅读、写信息、编码、发送的工作

private class ClientHandler implements Runnable{private Socket socket;private String host;//客户端地址信息/**外部需要传进来一个值,通过写构造器来将这个值传入方法中的成员变量,就可以直接用了*/public ClientHandler(Socket socket,int ClientNum){this.socket=socket;//通过socket获取远端计算机的地址信息host=socket.getInetAddress().getHostAddress()+"#"+ClientNum;//因为我在实验时手头只有一台电脑,为了区分客户端便为其加上了序号}public void run(){//继承Runnable即为线程处理类型方法,都需要重写run方法PrintWriter pw=null;try {//通过Socket方法获取一个字节输入流,可以读取来自远端的信息InputStream in=socket.getInputStream();InputStreamReader isr=new InputStreamReader(in, StandardCharsets.UTF_8);BufferedReader br=new BufferedReader(isr);/** 输出流 给客户端发信息*/OutputStream out=socket.getOutputStream();//字节流读取OutputStreamWriter osw=new OutputStreamWriter(out,StandardCharsets.UTF_8);BufferedWriter bw=new BufferedWriter(osw);pw=new PrintWriter(bw,true);//将该客户端的输出流存入共享数组allOut中,并不是字符聊天内容/*** 抢谁锁谁没错(临界资源),但避免对锁的东西在同步块中操作(更改),* 在此处就不能锁allOut数组* 在这里因为该同步块中有对该数组的扩容操作,会导致allOut对象发生变化*/synchronized (Server.this) {//内部类想访问外部类,外部类点this,或者Server.class//1、对allOut进行扩容allout.add(pw);//allOut = Arrays.copyOf(allOut,allOut.length+1);//存在并发安全问题,当然是对于大量级来说的//2、将pw存入共享数组的最后一个位置//allOut[allOut.length-1]=pw;//这儿就是跑一遍,把每个客户端的端口输出流放进去就好了}sendMessage(host+"上线了,当前在线人数:"+ allout.size());System.out.println(host+"上线了,当前在线人数:"+ allout.size());//给服务器端看的String line =br.readLine();System.out.println(host+"说:"+line);//将消息回复给客户端while (true){long time0=System.currentTimeMillis();line =br.readLine();long time1=System.currentTimeMillis();if(time1-time0<=500){sendMessage("你好快啊~歇一歇吧");continue;}if(line.equalsIgnoreCase("exit")){System.out.println("客户端"+host+"主动选择退出!!");break;}//服务端显示System.out.println(host+":"+line);//客户端显示sendMessage(host+"说:"+line);//抽方法出去}} catch (IOException e) {e.printStackTrace();}finally{//将当前客户端的输出流从allOut数组中删除synchronized (Server.class) {//缩数组也需要注意上锁allout.remove(pw);}sendMessage(host+"下线了,当前在线人数:"+ allout.size());System.out.println(host+"下线了,当前在线人数:"+ allout.size());//给服务器端看的try {socket.close();} catch (IOException e) {e.printStackTrace();}}}/** 广播消息给所有客户端*/private void sendMessage(String message){synchronized (Server.class) {//避免处理数组时影响遍历for(PrintWriter p:allout){p.println(message);}}

到此服务端的流程就算处理完毕了,当然不要忘记写main方法,在main方法里边实例化Server并调用server.start()即可

1.3 客户端Client:

一个客户端需要什么?它仅仅需要一个私有的socket变量即可
首先我们来写构造方法:

public  Client(){try {//实例化Socket时需要传入两个参数//下面两个参数就是远端计算机的地址和远端计算机开放的端口System.out.println("正在连接服务端...");socket =new Socket("localhost",8088);//127.0.0.1,这里的“localhost”字段是可以指定为你能够成功连接的电脑的ip的System.out.println("连接成功!");} catch (IOException e) {e.printStackTrace();}}

然后想,客户端要做的事情有两件,发送信息和接收信息
和服务端不同,服务端每接收到一条信息就直接转发,接收和转发是连在一起的,二者可以说是一个整体,一个线程足以搞定,服务端本身的线程只需要等待客户端连接即可。而客户端则不同,收发信息两者需要互不干扰,但客户端本身只需要考虑自己,不需要等待别的客户端接入的事务,因此不需要将两件事都建立线程,在这里我们将接收信息作为一条线程分离出去
这样,我们的start方法里边一部分代码用来分配线程,一部分用来对发送事件直接处理

public void start(){try {//启动一个线程来读取服务端发送的消息ServerHandler handler=new ServerHandler();Thread t=new Thread(handler);//将读取服务器消息的线程设置为守护线程//这样当我们停止给服务端发信息后(即主线程结束,进程没有其他用户线程活着)//守护线程就将被杀死//t.setDaemon(true);t.start();/*** 通过Socket的方法:* OutputStream getOutputStream()* 获取的字节输出流会通过网络发送给远端建立好连接的客户端*/OutputStream out=socket.getOutputStream();//字节输出流OutputStreamWriter osw=new OutputStreamWriter(out, StandardCharsets.UTF_8);BufferedWriter bw=new BufferedWriter(osw);PrintWriter pw=new PrintWriter(bw,true);//发的时候才需要flush,防止发不过去pw.println("你好服务端!");Scanner scanner=new Scanner(System.in);String line=null;while (true){line =scanner.nextLine();pw.println(line);if(line.equalsIgnoreCase("exit")){System.out.println("##客户端退出");break;}}} catch (IOException e) {e.printStackTrace();}finally {try {socket.close();//与远端计算机断开连接,进行tcp挥手} catch (IOException e) {e.printStackTrace();}}}

接收信息的线程

private class ServerHandler implements Runnable{@Overridepublic void run() {//线程的run方法不允许throws,所以里边的异常只能try-catch//读取服务器回的消息try {InputStream in=socket.getInputStream();//字节流InputStreamReader isr=new InputStreamReader(in);//转换为字符流BufferedReader br=new BufferedReader(isr);//加缓冲器String line;while((line=br.readLine())!=null){System.out.println(line);}} catch (IOException e) {//这里不输出异常错误信息了,当远端计算机断开时会出现异常,可以不输出错误信息}}}

到这里Client的流程也处理完毕,同样main方法中服务的起调记得加

总结

本文对Socket编程的聊天室进行了分析,并未涉及协议相关内容,属于Socket入门级程序,难点有java IO流转换,日后会对其进行解析,另外本聊天室并未实现私聊功能,下期上新

Socket编程之聊天室相关推荐

  1. java socket编程聊天室_Java Socket通信之聊天室功能

    Java Socket通信之聊天室功能 发布时间:2020-10-17 14:36:00 来源:脚本之家 阅读:73 作者:LY_624 本文实例为大家分享了Java Socket聊天室功能的具体代码 ...

  2. python socket 网络聊天室_Python基于Socket实现简单聊天室

    本文实例为大家分享了Python基于Socket实现简单聊天室,供大家参考,具体内容如下 服务端 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Ti ...

  3. 使用Socket实现通信聊天室

    使用Socket实现通信聊天室 通信聊天室是一个比较酷的项目. 建立通信聊天室之前我们会想到这些问题: ①聊天室得要有一个发送窗口和一个接受窗口,如何在这两个窗口建立联系? ②如何发送信息并且接受信息 ...

  4. windows网络编程 --网络聊天室(2)

    文章目录 IOCP模型 常用IOCP函数 基于IOCP的网络聊天室 服务器端 客户端 IOCP模型 IOCP :输入输出完成端口. 是支持多个同时发生的异步I/O操作的应用程序编程接口,IOCP特别适 ...

  5. 【C++】基于socket的多线程聊天室(控制台版)

    以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...

  6. Linux下socket多人聊天室

    目录 前言 一.聊天室的实验内容 二.逐个功能的简单分析 三.系统功能模块分解图 1.服务端功能模块图 2.客户端功能模块图 3.守护进程功能模块图 四.功能模块流程图 1.服务端流程图 2.客户端流 ...

  7. C#基于Socket的简单聊天室实践

    序:实现一个基于Socket的简易的聊天室,实现的思路如下: 程序的结构:多个客户端+一个服务端,客户端都是向服务端发送消息,然后服务端转发给所有的客户端,这样形成一个简单的聊天室功能. 实现的细节: ...

  8. android关于socket编程,以聊天为例【转】http://hi.baidu.com/yaoyuanhuajx/item/9b93d7565f315ba9acc857d7...

    一步一步android(15):关于socket编程[以聊天为例] Android手机的应用,除了它的手机功能之外,另外一个吸引人的地方在于它的开放性,这一点iphone无法比拟,至少iphone太多 ...

  9. 网络编程项目(聊天室项目)

    一.实现目标 一个在Linux下可以使用的聊天软件,要求至少实现如下功能: 1. 采用Client/Server架构 2. Client A 登陆聊天服务器前,需要注册自己的ID和密码 3. 注册成功 ...

  10. socket.io php 聊天室,WebSocket学习(一)——基于socket.io实现简单多人聊天室

    前言 什么是Websocket呢? 我们都知道在Http协议中,客户端与服务器端的通信是靠客户端发起请求,然后服务器端收到请求再进行回应,这个过程中,客户端是主动的,服务器端是被动的.Websocke ...

最新文章

  1. PHP memcache实现消息队列实例
  2. 推荐30个用于微服务的顶级工具
  3. 23种设计模式C++源码与UML实现--原型模式
  4. jdbc连接mysql数据库过程_jdbc连接数据库的步骤
  5. Pentium 4处理器架构/微架构/流水线 (11) - NetBurst执行核详解 - Load/Store操作/存储转发
  6. Pandas 处理 dummy variable
  7. 查看apache版本_Apache Pulsar 2.6.1 版本正式发布:2.6.0 加强版,新增 OAuth2 支持
  8. php coder 乱码,MySQL 乱码 与 字符集
  9. 《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之22---BDS的分发流程...
  10. c语言中函数的递归调用,用C语言函数调用与递归解决问题
  11. Tapestry 5 资料
  12. CryptoJS加密使用
  13. 机械臂运动空间的计算_深圳全气动式工业助力机械手定做
  14. java四舍五入保留两位小数方法整理
  15. 就是要弄懂你之—— 同步 异步 阻塞 非阻塞
  16. 既风骚又哲理的10句话,不服不行
  17. vue 全局刷新与局部刷新
  18. XXX处有未经处理的异常: 0xC0000374: 堆已损坏,处有未经处理的异常: 0xC0000005: 读取位置 0x4F774B16 时发生访问冲突。
  19. A. Unusual Competitions
  20. 安卓应用开发小程序!字节跳动+京东+360+网易面试题整理,聪明人已经收藏了!

热门文章

  1. linux 桌面对比,七大顶级Linux桌面比较
  2. Visual Studio更换默认浏览器
  3. 眼睛却可以睁开,口干胸闷,不论自己…
  4. 开源OA办公平台教程:手机APP指纹认证的配置
  5. 日语“不要”有几种说法。
  6. 【今日头条】米兜Java全部资料被曝光
  7. Python excel数据处理之公式---openpyxl
  8. c语言厘米换算分米程序设计,厘米和分米换算(米和厘米换算)
  9. Wiki使用技巧汇总
  10. oracle 取农历函数,完善SQL农历转换函数