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架构软件开发时会采用. 本篇 ...
随机推荐
- HTML5 介绍
本篇主要介绍HTML5规范的内容和页面上的架构变动. 目录 1. HTML5介绍 1.1 介绍 1.2 内容 1.3 浏览器支持情况 2. 创建HTML5页面 2.1 <!DOCTYPE> ...
- html与html5
HTML 是一种在 Web 上使用的通用标记语言.HTML 允许你格式化文本,添加图片,创建链接.输入表单.框架和表格等等,并可将之存为文本文件,浏览器即可读取和显示.HTML 的关键是标签,其作用是 ...
- 学习ASP.NET Core,怎能不了解请求处理管道[1]: 中间件究竟是个什么东西?
ASP.NET Core管道虽然在结构组成上显得非常简单,但是在具体实现上却涉及到太多的对象,所以我们在 "通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流 ...
- SignalR SelfHost实时消息,集成到web中,实现服务器消息推送
先前用过两次SignalR,但是中途有段时间没弄了,今天重新弄,发现已经忘得差不多了,做个笔记! 首先创建一个控制台项目Nuget添加引用联机搜索:Microsoft.AspNet.SignalR.S ...
- C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1)
一看这个标题,是不去取名有点绕呢?或者是,还有些问题?报告LZ...你的标题取得有问题,是个病句!↖(^ω^)↗!!!先不要急,其实我今天带给大家的就是CoreCLR中的coreclr.其中它是在名字 ...
- 云瓣影音网站&&微信端(已开源)
随着该项目的发布到线上(小打小闹),即将又要开启另一段崭新的旅程.强迫自己停下来写写所学所得,个人认为总结和分享是一种很棒的学习方式.那让我们先来瞧瞧项目长的什么样.如果着急要源码的朋友,可以下拉到最 ...
- js刷新页面方法大全
如何实现刷新当前页面呢?借助js你将无所不能. 1,reload 方法,该方法强迫浏览器刷新当前页面.语法:location.reload([bForceGet]) 参数: bForceGet, ...
- 【干货分享】流程DEMO-采购预算编制
流程名: 采购预算编制 业务描述: 在月初由计财部进行预算编辑,提交审批后预算生效 流程相关文件: 流程包.xml WebService业务服务.xml WebService.asmx WebSe ...
- Win10连接远程桌面时提示“您的凭据不工作”
我遇到这个问题的时候查找网上都给出一堆高大上的解决办法, 然而我的错误实际上是用户名的问题, 很多人以为远程用户名就一定是锁屏状态下的登录名, 其实不是,跟自己设置有关,所以首先应该检查远程用户名是否 ...
- 2016年中国微信小程序专题研究报告
2016年12月29日,全球领先的移动互联网第三方数据挖掘和分析机构iiMedia Research(艾媒咨询)权威首发<2016年中国微信小程序专题研究报告>. 报告显示,82.6%手机 ...