写在前面:
上一篇记录了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架构软件开发时会采用. 本篇 ...
随机推荐
-
Autofac 的属性注入方式
介绍 该篇文章通过一个简单的 ASP.NET MVC 项目进行介绍如何使用 autofac 及 autofac 的 MVC 模块进行依赖注入.注入方式通过构造函数.在编写 aufofac 的依赖注入代 ...
-
DDoS攻防战(二):CC攻击工具实现与防御理论
我们将要实现一个进行应用层DDoS攻击的工具,综合考虑,CC攻击方式是最佳选择,并用bash shell脚本来快速实现并验证这一工具,并在最后,讨论如何防御来自应用层的DDoS攻击. 第一步:获取大量 ...
-
JTextField限制输入长度的完美解决方案(转)
关于JTextField限制输入字符长度的问题,因为没提供现成的api,所以我们得自己动手,来实现这个功能,网上也有很多这样的资料,大多是在JTextField的Document的insertStri ...
-
x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
-
HDU6397
HDU6397用小于n的m个数组成k,求方案数mod 998244353如果没有n的限制,直接用隔板法求就可以因为m个数中可以为0,所以不妨先都放上一个1,转化成不能为0的m个数来凑k+m,即C(k+ ...
-
python入门(二):isinstance、内置函数、常用运算等
1. isinstance(变量名,类型) #判断什么类型 ps: 只支持输入两个参数,输入3个参数会报错 >>> isin ...
-
(转)Unity3D研究院之将场景导出XML或JSON或二进制并且解析还原场景
自:http://www.xuanyusong.com/archives/1919 导出Unity场景的所有游戏对象信息,一种是XML一种是JSON.本篇文章我们把游戏场景中游戏对象的.旋转.缩放.平 ...
-
python学习笔记(9)--Python UnicodeEncodeError: &#39;gbk&#39; codec can&#39;t encode character 解决方法
Python UnicodeEncodeError: 'gbk' codec can't encode character 解决方法 这篇文章主要介绍了Python UnicodeEncodeErro ...
-
Spring入门第二课:Spring配置Bean的细节
1.配置bean的作用域: 通过配置scope属性可以bean的作用域,参数有 prototype.request.session.singleton. 1)singleton为单例,IoC容器只会创 ...
-
break、continue与return的区别
1. break break语句的使用场合主要是switch语句和循环结构.在循环结构中使用break语句,如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句.如果在多重嵌套循 ...