-------------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. hzau 1200 Choosy in Food

    1200: Choosy in Food Time Limit: 1 Sec  Memory Limit: 1280 MBSubmit: 32  Solved: 5[Submit][Status][W ...

  2. 面试题46:求1+2+...+n

    题目:求1+2+...+n,要求不能使用乘除法.for.while.if.else.swithc.case等关键字及条件判断语句(A?B:C). 解法一:利用构造函数求解 class Temp { p ...

  3. @angular/cli项目构建--http(2)

    客户端GET设置参数查询: search() { const params = new HttpParams() .set('userName', this.userName) .set('fullN ...

  4. spring学习-2

    Spring_属性配置细节 1.若字面值包含特殊字符,可以使用<[CDATA[]]>把字面值包裹起来 例:<value><![CDATA[<3333>^]]& ...

  5. UVA - 11916 Emoogle Grid (组合计数+离散对数)

    假如有这样一道题目:要给一个M行N列的网格涂上K种颜色,其中有B个格子不用涂色,其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色.给出M,N,K和B个格子的位置,求出涂色方案总数除以1 ...

  6. 转载:maven依赖范围

    其中依赖范围scope 用来控制依赖和编译,测试,运行的classpath(注意是与classpath)的关系. 主要的是三种依赖关系如下:1.compile: 默认编译依赖范围.对于编译,测试,运行 ...

  7. web.xml & web-fragment.xml (Servlet 2.3, 2.4, 2.5 + 3.0)模板

    转自:http://jlcon.iteye.com/blog/890964 web.xml v2.3 <?xml version="1.0" encoding="I ...

  8. position:sticky属性测试

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. unity3d___UGui中如何创建loading...进度条

    http://blog.sina.com.cn/s/blog_e82e8c390102wh2z.html 实现方法:通过Image组件中Image Type属性中Fill Amount,通过代码改变F ...

  10. VerilogHDL编译预处理

    编译预处理语句 编译预处理是VerilogHDL编译系统的一个组成部分,指编译系统会对一些特殊命令进行预处理,然后将预处理结果和源程序一起在进行通常的编译处理.以”`” (反引号)开始的某些标识符是编 ...