-------------siwuxie095

 
 

 
 

 
 

 
 

 
 

 
 

工程名:TestMyServerSocket

包名:com.siwuxie095.socket

类名:MyServerSocket.java(主类)、ServerListener.java、ChatSocket.java、ChatManager.java

 
 

 
 

工程结构目录如下:

 
 

 
 

 
 

 
 

 
 

MyServerSocket.java(主类):

 
 

package com.siwuxie095.socket;

 
 

/**

* 聊天服务器,不仅能向客户端发送数据,也能从客户端读取数据

*

* @author siwux

*

*/

 
 

public class MyServerSocket {

 

/**

* 这是主类(主线程),启动线程ServerListener进行监听,

* 当有Socket对象进行连接时,在线程ServerListener中

* 启动线程ChatSocket,同时将该ChatSocket线程添加到聊天

* 管理器的集合Vector中

*

* @param args

*/

 
 

public static
void main(String[] args) {

 

//运行线程ServerListener,使用匿名对象

new ServerListener().start();

}

 
 

}

 
 

 
 

 
 

ServerListener.java:

 
 

package com.siwuxie095.socket;

 
 

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

 
 

import javax.swing.JOptionPane;

 
 

//创建线程 ServerListener,将有阻塞的代码放到这个独立的线程中

//将新建立的ChatSocket线程添加到集合Vector中

public class ServerListener extends Thread {

 
 

// 复写run()

@SuppressWarnings("resource")

@Override

public
void run() {

try {

 
 

// 端口的范围:1~65535,通常都指定较大的数字,

// 这样和较小的或系统预留的端口分开

// 有异常抛出,用 try catch 捕获

ServerSocket serverSocket = new ServerSocket(12345);

 
 

 

// ServerSocket创建完成后需要侦听客户端的连接

// 调用accept()方法,这是一个阻塞的方法,

// 会阻塞当前的线程,对于有阻塞的代码,应该放到独立的线程中

//(ServerListener 就是一个独立的线程)

// 返回值是Socket类型,创建以接收返回值

// 当accept()被执行且socket被赋值,说明有客户端连接

//每当有一个客户端连接到ServerSocket,accept()都会返回一个新的Socket对象

//如果有多个客户端来连接当前的服务器ServerSocket,就会有多个Socket对象出现

//需要一个while循环来循环监听

while (true) {

 

Socket socket = serverSocket.accept();

 
 

// 建立连接时

// 弹出提示框:有客户端连接到本机的 12345 端口

JOptionPane.showMessageDialog(null, "有客户端连接到本机的 12345 端口");

 

//由于每一个socket要与一个独立的客户端进行通信

//所以要将socket传递给新的线程:ChatSocket(用于Socket通信)

//每一个socket都有一个独立的ChatSocket线程

//每一个ChatSocket线程之间是相互独立的,它们不能相互沟通数据

//新建一个类ChatManager,将这些新建的ChatSocket线程管理起来,

//实现它们之间的相互通信

//运行该线程

ChatSocket cs=new ChatSocket(socket);

cs.start();

 

//通过静态方法将cs添加到聊天管理器中

ChatManager.getChatManager().add(cs);

 

}

 

 
 

} catch (IOException e) {

e.printStackTrace();

}

 
 

}

 
 

}

 
 

 
 

 
 

ChatSocket.java:

 
 

package com.siwuxie095.socket;

 
 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.io.UnsupportedEncodingException;

import java.net.Socket;

 
 

/**

* run()循环执行的读取的工作,即当前的服务器会不断的从客户端读取内容

* 将读取到的内容发送到集合Vector中的所有客户端(除了自身)

*

* @author siwux

*

*/

 
 

//创建用于Socket通信的线程:ChatSocket

public class ChatSocket extends Thread {

 

Socket socket;

 

//创建构造方法,传入Socket对象

public ChatSocket(Socket socket) {

this.socket=socket;

}

 

public
void output(String out) {

 

try {

 
 

//对当前的Socket执行
数据输出相关功能的包装

//使用getOutputStream()获取输出流,通过输出流向外输出数据

//返回值是OutputStream类型,创建以接收返回值

OutputStream os=socket.getOutputStream();

 
 

//创建一个BufferedWriter作为数据的输出,传入匿名对象,指定编码,层层包装

BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(os,"UTF-8"));

 
 

//让BufferedWriter输出字符串

bw.write(out);

//因为带缓冲,所以需要强制输出,不然无法输出

bw.flush();

 
 

}catch (UnsupportedEncodingException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

 
 

}

 

//复写run()方法

@Override

public
void run() {

 

try {

 

//对Socket的输入流进行包装

//在指定InputStreamReader时,指定编码的字符集

//有异常抛出,用 try catch 捕获

BufferedReader br=new BufferedReader(

new InputStreamReader(

socket.getInputStream(),"UTF-8"));

 

String line=null;

//读取从客户端发送给服务器的数据

while ((line=br.readLine())!=null) {

//通过静态方法,将自己传入,同时传入line

ChatManager.getChatManager().publish(this, line);

}

 

//关闭流

br.close();

} catch (IOException e) {

e.printStackTrace();

}

 

 

 

}

}

 
 

 
 

 
 

ChatManager.java:

 
 

package com.siwuxie095.socket;

 
 

import java.util.Vector;

 
 

 
 

/**

* ChatManager 将不同的socket所新建的ChatSocket线程管理起来

* 由于一个聊天服务器只能有一个聊天的管理器:ChatManager

* 所以要把这个类作单例化处理

* 单例化的第一步就是让这个类的构造方法变成 private 类型

*

* @author siwux

*

*/

public class ChatManager {

 

//让构造方法变成private类型,完成单例化的第一步

private ChatManager(){}

 

//为当前类创建一个实例

private static final ChatManager cm=new ChatManager();

 

//创建方法 getChatManager(),返回ChatManager类型

public static ChatManager getChatManager() {

return cm;

}

 

 

 

//至此,完成了这个类(ChatManager)的单例化

//接下来就是对ChatSocket线程进行管理

 

 

//创建一个Vector,指定泛型为ChatSocket

Vector<ChatSocket> vector=new Vector<>();

 

//创建add()方法,为当前集合添加一个新的ChatSocket对象

//在创建ChatSocket时使用,即ServerListener.java中使用

public
void add(ChatSocket cs) {

//调用Vector的add()方法,传入cs即可

vector.add(cs);

}

 

 

//创建publish()方法,其中的某个ChatSocket线程可以调用publish()

//向其他的客户端(其他的ChatSocket线程)发送信息

//传入线程本身和需要发送的信息

public
void publish(ChatSocket cs,String msg) {

 

//因为要发送给集合Vector中的其他所有线程,要使用遍历

for (int i = 0; i < vector.size(); i++) {

//获取循环中的第 i 个对象

ChatSocket csx=vector.get(i);

 

//当前发送信息的线程就不用再接收这条信息,

//判断发送消息的对象是不是当前对象

if (!cs.equals(csx)) {

csx.output(msg);

}

}

}

 

 

 

 

 

 

 
 

}

 
 

 
 

运行后,终止按钮(Terminate)长亮,即 当前程序正在运行 且 没有停止

 
 

 
 

而且,此时也没有任何提示框,即当前程序被阻塞在
ServerListener.java 的:

Socket socket=serverSocket.accept();

 
 

 
 

 
 

打开
CMD 窗口,输入:telnet 127.0.0.1 12345

telnet localhost 12345

(即
本机地址+端口),回车。此时,会弹框提示:

 
 

 
 

 
 

 
 

点击确定

 
 

打开多个
CMD 窗口,重复操作,然后在其中一个 CMD 窗口任意输入,

其他窗口就会显示该输入

 
 

 
 

 
 

 
 

点击
终止按钮(Terminate),可结束运行

 
 

 
 

 
 

 
 

 
 

【made by siwuxie095】

使用ServerSocket建立聊天服务器(二)的更多相关文章

  1. Socket 基础解析使用ServerSocket建立聊天服务器

    很简单的教程哦! 1.socket 简介 Socket 又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求.ServerSocket 用于 ...

  2. 使用 ServerSocket 建立聊天服务器-1

    1.代码目录 2.ChatSocket.java --------------------------------------------------------------------------- ...

  3. 使用ServerSocket建立聊天服务器(一)

    -------------siwuxie095                             工程名:TestMyServerSocket 包名:com.siwuxie095.socket ...

  4. 使用 ServerSocket 建立聊天服务器-2

    1. 从serverListener中可以看出,每一个客户端创建新的请求之后,都会把它分配给一个独立的chatsocket ,但是每一个ChatSocket都是相互独立的,他们之间并不能沟通,所以要新 ...

  5. 使用Java建立聊天客户端

    ---------------siwuxie095                             关于 聊天服务器,详见本人博客的分类:来一杯Java, 里面的 使用ServerSocket ...

  6. openfire:基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件

    基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件 上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfir ...

  7. 基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件

    原文:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html 随笔-150  评论- ...

  8. socket实现聊天功能(二)

    socket实现聊天功能(二) WebSocket协议是建立在HTTP协议之上,因此创建websocket服务时需要调用http模块的createServer方法.将生成的server作为参数传入so ...

  9. 使用rabbitmq实现集群im聊天服务器消息的路由

    这个地址图文会更清晰:https://www.jianshu.com/p/537e87c64ac7 单机系统的时候,客户端和连接都有同一台服务器管理.   image.png 在本地维护一份userI ...

随机推荐

  1. HANA Architecture

    1 HANA 是基于内存计算的.行列都支持.使用列存储,列存储的特点是高压缩,查询快,节约空间, ---SAP HANA supports both, but is particularly opti ...

  2. ionic2——环境配置篇

    环境配置 安装nodeJS 配置cnpm 安装ionic2 安装cordova 安装java sdk 安装android sdk(在项目最后打包时app的时候会用到,前期是在浏览器环境测试开发暂时不需 ...

  3. APP登录的机制

    1.APP每次发送请求时,都会发送header给服务器,服务器去校验传过来的信息是否正确:校验成功后登录成功,若传入的信息不符合该用户的信息则服务器判断,传给APP登录失败 每次的请求都会传入上图中的 ...

  4. centos type.h 编译错误问题

    # ifndef __int8_t_defined # define __int8_t_defined __intN_t (, __QI__); __intN_t (, __HI__); __intN ...

  5. Linux运维工程师中级面试题

    1.解释top命令和vmstat命令 2.请写出iptables语句 3.mysql高可用方案有哪些?mysql备份方案有哪些?有什么缺点? 4.写出Apache 2.x的两种工作模式,以及各自的工作 ...

  6. NOI 模拟赛 #3

    打开题一看,咦,两道数数,一道猫式树题 感觉树题不可做呀,暴力走人 数数题数哪个呢?感觉置换比矩阵好一些 于是数了数第一题 100 + 0 + 15 = 115 T1 bishop 给若干个环,这些环 ...

  7. POJ - 2079:Triangle (旋转卡壳,求最大三角形)

    Given n distinct points on a plane, your task is to find the triangle that have the maximum area, wh ...

  8. swing之checkbox

    import java.awt.GridLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax ...

  9. java编程思想第九章接口

    9.1抽象类和抽象方法 为什么要有抽象类? 是希望通过通用接口操作一系列类. 那么抽象类的形式是什么样的呢? 声明类的使用使用abstract关键字,且在该类中应该具有抽象方法. 注:抽象方法被关键字 ...

  10. What makes an inferred latch? how To avoid creating inferred latches? when do you know you need latches?

    What makes an inferred latch?For combinatorial logic, the output of the circuit is a function of inp ...