写在前面:

  上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块——Common模块记录一下。Common的设计如下:

功能说明:

Common模块主要是数据交互,这里使用JSON数据进行交互,common模块定义了各类交互信息,SendHelper实现的socket信息的传送,I18N是语言话,ConstantValue是系统中的配置以及常量(这里常量都是用接口,这个可能不太好),对于ReturnMessage拥有一系列的DTO作为其content属性。

具体实现:

  [SendHelper.java]

SendHelper负责发送socket数据,不管是服务端还是客户端,都由SendHelper来发送数据,SendHelper的具体实现如下:

 public class SendHelper {

     private SendHelper() {
} public synchronized static void send(Socket socket, BaseMessage message) {
if (socket != null && !socket.isClosed()) {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream());
LoggerUtil.trach(" [" + JSON.toJSON(message) + "] SEND AT " + new Date());
out.println(JSON.toJSON(message));
out.flush(); // ??
Thread.sleep(ConstantValue.MESSAGE_PERIOD);
} catch (Exception ignore) {
LoggerUtil.debug("Message send faild !" + ignore.getMessage(), ignore);
}
}
} public synchronized static void upload(Socket socket, File file) {
if (socket != null && !socket.isClosed()) {
InputStream is = null;
try {
OutputStream os = socket.getOutputStream();
is = new FileInputStream(file);
byte[] buff = new byte[ConstantValue.BUFF_SIZE];
int len = -1;
while ((len = is.read(buff)) != -1) {
os.write(buff, 0, len);
}
os.flush();
Thread.sleep(ConstantValue.MESSAGE_PERIOD);
} catch (Exception ignore) {
LoggerUtil.debug("File upload faild !" + ignore.getMessage(), ignore);
} finally {
if (is != null) {
try {
is.close();
} catch (Exception ignore) {
}
is = null;
}
}
}
}
}

  [BaseMessage.java...]

这里使用JSON数据进行交互,所有的消息数据传输对象对应的类都继承BaseMessage,BaseMessage的设计以及其他Message的设计如下(这里为了缩小篇幅,将其他Messaged类的代码收起来):

 /**
* BaseMessage
* @author yaolin
*
*/
public class BaseMessage { protected String from;
protected String to;
protected String owner;
protected int type; public String getFrom() {
return from;
}
public BaseMessage setFrom(String from) {
this.from = from; // which tab will be select
return this;
}
public String getTo() {
return to;
}
public BaseMessage setTo(String to) {
this.to = to;
return this;
}
public String getOwner() {
return owner;
}
public BaseMessage setOwner(String owner) {
this.owner = owner; // display
return this;
}
public int getType() {
return type;
}
public BaseMessage setType(int type) {
this.type = type;
return this;
} }
 public class AliveMessage extends BaseMessage {

     private final int type = MessageType.ALIVE;

     public int getType() {
return type;
}
}
 public class ChatMessage extends BaseMessage {

     private final int type = MessageType.CHAT;
private String content; public int getType() {
return type;
} public String getContent() {
return content;
} public ChatMessage setContent(String content) {
this.content = content;
return this;
}
}
 public class FileMessage extends BaseMessage {

     private final int type = MessageType.FILE;

     private String name;
private long size;
private String ext; public String getName() {
return name;
} public FileMessage setName(String name) {
this.name = name;
return this;
} public long getSize() {
return size;
} public FileMessage setSize(long size) {
this.size = size;
return this;
} public String getExt() {
return ext;
} public FileMessage setExt(String ext) {
this.ext = ext;
return this;
} public int getType() {
return type;
}
}
 public class LoginMessage extends BaseMessage{

     private final int type = MessageType.LOGIN;
private String username;
private String password; public int getType() {
return type;
}
public String getUsername() {
return username;
}
public LoginMessage setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public LoginMessage setPassword(String password) {
this.password = password;
return this;
}
}
 public class LogoutMessage extends BaseMessage {

     private final int type = MessageType.LOGOUT;
private String username;
public String getUsername() {
return username;
}
public LogoutMessage setUsername(String username) {
this.username = username;
return this;
}
public int getType() {
return type;
}
}
 public class RegisterMessage extends BaseMessage{

     private final int type = MessageType.REGISTER;
private String username;
private String password;
private String confirm; public String getUsername() {
return username;
}
public RegisterMessage setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public RegisterMessage setPassword(String password) {
this.password = password;
return this;
}
public String getConfirm() {
return confirm;
}
public RegisterMessage setConfirm(String confirm) {
this.confirm = confirm;
return this;
}
public int getType() {
return type;
}
}
 public class ReturnMessage extends BaseMessage {

     private final int type = MessageType.RETURN;
private boolean success;
// success
private String key;
private Object content;
// error
private String message;
private String code; public int getType() {
return type;
}
public boolean isSuccess() {
return success;
}
public ReturnMessage setSuccess(boolean success) {
this.success = success;
return this;
}
public String getKey() {
return key;
}
public ReturnMessage setKey(String key) {
this.key = key;
return this;
}
public Object getContent() {
return content;
}
public ReturnMessage setContent(Object content) {
this.content = content;
return this;
}
public String getMessage() {
return message;
}
public ReturnMessage setMessage(String message) {
this.message = message;
return this;
}
public String getCode() {
return code;
}
public ReturnMessage setCode(String code) {
this.code = code;
return this;
}
}

对于ReturnMessage,其他Content属性可以是各种DTO,目前有两个,由KEY指定是那种DTO:

 public interface Key {
/**
* 登陆
*/
String LOGIN = "LOGIN";
/**
* 注册
*/
String REGISTER = "REGISTER";
/**
* Client 上线 / 离线 通知
*/
String NOTIFY = "NOTIFY";
/**
* 拉去在线 Client 列表
*/
String LISTUSER = "LISTUSER";
/**
* TIP 提示
*/
String TIP = "TIP";
 public class ClientListUserDTO {

     private Set<String> listUser;

     public Set<String> getListUser() {
return listUser;
}
public void setListUser(Set<String> listUser) {
this.listUser = listUser;
}
 public class ClientNotifyDTO {

     private boolean flag; // true:online,false:offline
private String username; // hostname public ClientNotifyDTO() {
}
public ClientNotifyDTO(boolean flag, String username) {
this.flag = flag;
this.username = username;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}

另外几个常量也给出:

 public interface ConstantValue {
/**
* 缓冲区大小
*/
int BUFF_SIZE = 1024;
/**
* 调试模式
*/
int DEBUG_LEVEL = 0;
/**
* 客户端接收文件的存储路径
*/
String CLIENT_RECEIVE_DIR = "./file";
/**
* KEEPALIVE PERIOD'second
*/
int KEEP_ALIVE_PERIOD = 20;
/**
* 最大socket线程处理数
*/
int MAX_POOL_SIZE = PropertiesUtil.getInt("server-thread-pool-size", 30);
/**
* <pre>
* 检测是否有新的数据时间间隔'ms
* (server.SocketDispatch,client.ReceiveListener,SendHelper)
* 使用同一个Thread.sleep时间保证数据能正确接收到,同时降低CPU的使用率
* !!!!! -非常重要- !!!!!
* </pre>
*/
int MESSAGE_PERIOD = 500;
/**
* 服务器IP地址
*/
String SERVER_IP = PropertiesUtil.get("server-ip", "127.0.0.1");
/**
* 服务器名称,用户注册不能使用此用户名
*/
String SERVER_NAME = "niloay";
/**
* 服务器端口
*/
int SERVER_PORT = PropertiesUtil.getInt("server-port", 8888);
/**
* SOCKET超时时间'second
*/
int TIME_OUT = 120;
/**
* 群发标识TO:ALL,用户注册不能使用此用户名
*/
String TO_ALL = "TO_ALL";
 public interface I18N {

     //---------------------------------
// TEXT
//---------------------------------
/**
* APP_NAME
*/
String TEXT_APP_NAME = "NILOAY-CHAT v1.0.0";
/**
* 登陆
*/
String TEXT_LOGIN = "登陆";
/**
* 注册
*/
String TEXT_REGISTER = "注册";
/**
* 账号
*/
String TEXT_USERNAME = "账号";
/**
* 密码
*/
String TEXT_PASSWORD = "密码"; //---------------------------------
// BTN
//---------------------------------
/**
* 注册
*/
String BTN_REGISTER = "注册";
/**
* 登陆
*/
String BTN_LOGIN = "登陆";
/**
* 退出
*/
String BTN_EXIT = "退出";
/**
* 发送
*/
String BTN_SEND = "发送";
/**
* 发送文件
*/
String BTN_SEND_FILE = "发送文件"; //---------------------------------
// INFO
//---------------------------------
/**
* 请填写注册账号和密码
*/
String INFO_REGISTER_EMPTY_DATA = "请填写注册账号和密码";
/**
* 用户已存在
*/
String INFO_REGISTER_CLIENT_EXIST = "用户已存在";
/**
* 注册成功
*/
String INFO_REGISTER_OK = "注册成功";
/**
* 请输入登陆账号和密码
*/
String INFO_LOGIN_EMPTY_DATA = "请输入登陆账号和密码";
/**
* 登陆账号或密码错误
*/
String INFO_LOGIN_ERROR_DATA = "登陆账号或密码错误";
/**
* 暂不支持文件群发
*/
String INFO_FILE_TO_ALL_ERROR = "暂不支持文件群发";
/**
* 文件发送成功
*/
String INFO_FILE_SEND_SUCCESSFULLY = "文件发送成功";
/**
* 文件接收成功
*/
String INFO_FILE_RECEIVE_SUCCESSFULLY = "文件接收成功";
}

关于socket聊天程序的实现,详见:

Socket聊天程序——初始设计

Socket聊天程序——服务端

Socket聊天程序——客户端

Socket聊天程序——Common的更多相关文章

  1. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

  2. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  3. Socket聊天程序——初始设计

    写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...

  4. 聊天程序(基于Socket、Thread)

    聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现 ...

  5. 聊天程序——基于Socket、Thread (二)

    聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现 ...

  6. Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程

    SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...

  7. Node.js + Web Socket 打造即时聊天程序嗨聊

    前端一直是一块充满惊喜的土地,不仅是那些富有创造性的页面,还有那些惊赞的效果及不断推出的新技术.像node.js这样的后端开拓者直接将前端人员的能力扩大到了后端.瞬间就有了一统天下的感觉,来往穿梭于前 ...

  8. 简单的聊天程序,主要用到的是Socket

    服务端: import java.io.*; import java.net.*; import java.util.*; public class ChatServer { boolean stat ...

  9. Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...

随机推荐

  1. 页面嵌入dom与被嵌入iframe的攻防

    1.情景一:自己的页面被引入(嵌入)至别人的页面iframe中 if(window.self != window.top){ //url是自己页面的url window.top.location.hr ...

  2. ASP.NET Core 之 Identity 入门(三)

    前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ...

  3. ASP.NET Aries 入门开发教程2:配置出一个简单的列表页面

    前言: 朋友们都期待我稳定地工作,但创业公司若要躺下,也非意念可控. 若人生注定了风雨飘摇,那就雨中前行了. 最机开始看聊新的工作机会,欢迎推荐,创业公司也可! 同时,趁着自由时间,抓紧把这系列教程给 ...

  4. 浏览器中用JavaScript获取剪切板中的文件

    本文转自我的个人网站  , 原文地址:http://www.zoucz.com/blog/2016/01/29/get-file-from-clipboard/  ,欢迎前往交流讨论 在网页上编辑内容 ...

  5. [原] KVM 虚拟化原理探究(5)— 网络IO虚拟化

    KVM 虚拟化原理探究(5)- 网络IO虚拟化 标签(空格分隔): KVM IO 虚拟化简介 前面的文章介绍了KVM的启动过程,CPU虚拟化,内存虚拟化原理.作为一个完整的风诺依曼计算机系统,必然有输 ...

  6. 通过自定义特性,使用EF6拦截器完成创建人、创建时间、更新人、更新时间的统一赋值(使用数据库服务器时间赋值,接上一篇)

    目录: 前言 设计(完成扩展) 实现效果 扩展设计方案 扩展后代码结构 集思广益(问题) 前言: 在上一篇文章我写了如何重建IDbCommandTreeInterceptor来实现创建人.创建时间.更 ...

  7. Java 程序优化 (读书笔记)

    --From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10第一版) 1. java性能调优概述 1.1 性能概述 程序性能: 执行速度,内存分配,启动时间, 负载承受能力. 性能 ...

  8. Linux监控工具介绍系列——vmstat

      说来惭愧,玩Linux这么久了,居然没有玩转vmstat这个命令,对很多指标的具体意义都有点模糊不清,花了点时间好好学习.整理一下这个命令的相关资料.因为这个命令确实比较重要,而且频繁用到. 命令 ...

  9. Win10命令提示符(cmd)怎么复制粘贴

    在Win10系统里右键开始菜单,选择弹出菜单里的命令提示符,如下图所示: 然后复制要粘贴的文字,例如: echo hovertree.com 把上面的文字复制后,点击命令提示符窗口,然后在命令提示符窗 ...

  10. 录像时调用MediaRecorder的start()时发生start failed: -19错误

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...