Socket聊天程序——Common
写在前面:
上一篇记录了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聊天程序——Common的更多相关文章
- Socket聊天程序——客户端
写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...
- Socket聊天程序——服务端
写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- 聊天程序(基于Socket、Thread)
聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现 ...
- 聊天程序——基于Socket、Thread (二)
聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现 ...
- Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程
SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...
- Node.js + Web Socket 打造即时聊天程序嗨聊
前端一直是一块充满惊喜的土地,不仅是那些富有创造性的页面,还有那些惊赞的效果及不断推出的新技术.像node.js这样的后端开拓者直接将前端人员的能力扩大到了后端.瞬间就有了一统天下的感觉,来往穿梭于前 ...
- 简单的聊天程序,主要用到的是Socket
服务端: import java.io.*; import java.net.*; import java.util.*; public class ChatServer { boolean stat ...
- Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程
设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...
随机推荐
- 关于Unity3D自定义编辑器的学习
被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做). 刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...
- UWP 律师查询 MVVM
APP简介 律师查询是基于聚合数据的律师查询接口做的,这个接口目前处于停用状态,但是,由于我是之前申请的,所以,还可以用,应该是无法再申请了. 效果图 开发 一.HttpHelper 既然是请求接口的 ...
- css3中perspective
perspective 属性定义 3D 元素距视图的距离,以像素计.该属性允许改变 3D 元素查看 3D 元素的视图.当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本 ...
- category中重写方法?
问:可以在category中重写方法吗? 答:代码上可以实现 在category中重写方法,但在实际开发中,不建议这样做.如果确实需要重写原有方法也建议使用子类进行重写. category是为了更方便 ...
- ASP.NET Core应用针对静态文件请求的处理[2]: 条件请求与区间请求
通过调用ApplicationBuilder的扩展方法UseStaticFiles注册的StaticFileMiddleware中间件帮助我们处理针对文件的请求.对于StaticFileMiddlew ...
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- 如何将VCSA添加到微软域控环境,并且实现微软域账号登陆vCenter
v:* { } o:* { } w:* { } .shape { } p.msonormal,li.msonormal,div.msonormal { margin: 0cm; margin-bott ...
- pdo的使用
PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据. PDO随 ...
- 我这么玩Web Api(一):帮助页面或用户手册(Microsoft and Swashbuckle Help Page)
前言 你需要为客户编写Api调用手册?你需要测试你的Api接口?你需要和前端进行接口对接?那么这篇文章应该可以帮到你.本文将介绍创建Web Api 帮助文档页面的两种方式,Microsoft Help ...
- Oracle使用触发器和mysql中使用触发器的比较——学习笔记
一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志, ...