写在前面:

  上一篇记录了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. vue.js 2.0开发(2)

    如果我们想实时的显示我们todos的长度这个业务逻辑可以这样: <h1>{{message}} ({{todos.length}})</h1> 直接展示todos的length ...

  2. Java分布式应用技术架构介绍

    分布式架构的演进 系统架构演化历程-初始阶段架构

  3. GUI之CCControlExtension

    Introduction CCControl is inspired by the UIControl API class from the UIKit library of CocoaTouch. ...

  4. 正则表达式、find、grep、awk、sed

    1.正则表达式    (1)正则表达式一般用来描述文本模式的特殊用法,由普通字符(例如字符a-z)以及特殊字符(称为元字符,如/.*.?等)组成.   (2)基本元字符集及其含义       ^ :只 ...

  5. Spring Boot的一个测试用例

    package tk.mybatis.springboot.mapper; import org.junit.Assert; import org.junit.Test; import org.jun ...

  6. What day is it

    Description Today is Saturday, 17th Nov,2007. Now, if i tell you a date, can you tell me what day it ...

  7. 机器学习算法 - 最近邻规则分类KNN

    上节介绍了机器学习的决策树算法,它属于分类算法,本节我们介绍机器学习的另外一种分类算法:最近邻规则分类KNN,书名为k-近邻算法. 它的工作原理是:将预测的目标数据分别跟样本进行比较,得到一组距离的数 ...

  8. winfrom 图片等比例压缩

    效果图: 核心代码: /// <summary> /// 等比例缩放图片 /// </summary> /// <param name="bitmap" ...

  9. 19.3.20 解决pycharm快捷键无法使用问题和熟悉git与码云操作流程

    problem:由于Vim插件导致快捷键无法使用: answer:settings→Plugins→搜索到ideaVim→取消选中→apply→重启pycharm: git:创建仓库→生成公钥(ssh ...

  10. Orchard详解--第八篇 拓展模块及引用的预处理

    从上一篇可以看出Orchard在处理拓展模块时主要有两个组件,一个是Folder另一个是Loader,前者用于搜索后者用于加载. 其中Folder一共有三个:Module Folder.Core Fo ...