Socket聊天程序——Common

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Socket聊天程序——Common相关的知识,希望对你有一定的参考价值。

写在前面:

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

技术分享

功能说明:

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

具体实现:

  [SendHelper.java]

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

 1 public class SendHelper {
 2 
 3     private SendHelper() {
 4     }
 5 
 6     public synchronized static void send(Socket socket, BaseMessage message) {
 7         if (socket != null && !socket.isClosed()) {
 8             try {
 9                 PrintWriter out = new PrintWriter(socket.getOutputStream());
10                 LoggerUtil.trach(" [" + JSON.toJSON(message) + "] SEND AT " + new Date());
11                 out.println(JSON.toJSON(message));
12                 out.flush(); // ??
13                 Thread.sleep(ConstantValue.MESSAGE_PERIOD);
14             } catch (Exception ignore) {
15                 LoggerUtil.debug("Message send faild !" + ignore.getMessage(), ignore);
16             }
17         }
18     }
19 
20     public synchronized static void upload(Socket socket, File file) {
21         if (socket != null && !socket.isClosed()) {
22             InputStream is = null;
23             try {
24                 OutputStream os = socket.getOutputStream();
25                 is = new FileInputStream(file);
26                 byte[] buff = new byte[ConstantValue.BUFF_SIZE];
27                 int len = -1;
28                 while ((len = is.read(buff)) != -1) {
29                     os.write(buff, 0, len);
30                 }
31                 os.flush();
32                 Thread.sleep(ConstantValue.MESSAGE_PERIOD);
33             } catch (Exception ignore) {
34                 LoggerUtil.debug("File upload faild !" + ignore.getMessage(), ignore);
35             } finally {
36                 if (is != null) {
37                     try {
38                         is.close();
39                     } catch (Exception ignore) {
40                     }
41                     is = null;
42                 }
43             }
44         }
45     }
46 }

   [BaseMessage.java...]

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

 1 /**
 2  * BaseMessage
 3  * @author yaolin
 4  *
 5  */
 6 public class BaseMessage {
 7     
 8     protected String from;
 9     protected String to;
10     protected String owner;
11     protected int type;
12     
13     public String getFrom() {
14         return from;
15     }
16     public BaseMessage setFrom(String from) {
17         this.from = from;  // which tab will be select
18         return this;
19     }
20     public String getTo() {
21         return to;
22     }
23     public BaseMessage setTo(String to) {
24         this.to = to;
25         return this;
26     }
27     public String getOwner() {
28         return owner;
29     }
30     public BaseMessage setOwner(String owner) {
31         this.owner = owner; // display
32         return this;
33     }
34     public int getType() {
35         return type;
36     }
37     public BaseMessage setType(int type) {
38         this.type = type;
39         return this;
40     }
41     
42 }
技术分享
1 public class AliveMessage extends BaseMessage {
2 
3     private final int type = MessageType.ALIVE;
4 
5     public int getType() {
6         return type;
7     }
8 }
View Code
技术分享
 1 public class ChatMessage extends BaseMessage {
 2 
 3     private final int type = MessageType.CHAT;
 4     private String content;
 5 
 6     public int getType() {
 7         return type;
 8     }
 9 
10     public String getContent() {
11         return content;
12     }
13 
14     public ChatMessage setContent(String content) {
15         this.content = content;
16         return this;
17     }
18 }
View Code
技术分享
 1 public class FileMessage extends BaseMessage {
 2 
 3     private final int type = MessageType.FILE;
 4 
 5     private String name;
 6     private long size;
 7     private String ext;
 8 
 9     public String getName() {
10         return name;
11     }
12 
13     public FileMessage setName(String name) {
14         this.name = name;
15         return this;
16     }
17 
18     public long getSize() {
19         return size;
20     }
21 
22     public FileMessage setSize(long size) {
23         this.size = size;
24         return this;
25     }
26 
27     public String getExt() {
28         return ext;
29     }
30 
31     public FileMessage setExt(String ext) {
32         this.ext = ext;
33         return this;
34     }
35 
36     public int getType() {
37         return type;
38     }
39 }
View Code
技术分享
 1 public class LoginMessage extends BaseMessage{
 2 
 3     private final int type = MessageType.LOGIN;
 4     private String username;
 5     private String password;
 6     
 7     public int getType() {
 8         return type;
 9     }
10     public String getUsername() {
11         return username;
12     }
13     public LoginMessage setUsername(String username) {
14         this.username = username;
15         return this;
16     }
17     public String getPassword() {
18         return password;
19     }
20     public LoginMessage setPassword(String password) {
21         this.password = password;
22         return this;
23     }
24 }
View Code
技术分享
 1 public class LogoutMessage extends BaseMessage {
 2 
 3     private final int type = MessageType.LOGOUT;
 4     private String username;
 5     public String getUsername() {
 6         return username;
 7     }
 8     public LogoutMessage setUsername(String username) {
 9         this.username = username;
10         return this;
11     }
12     public int getType() {
13         return type;
14     }
15 }
View Code
技术分享
 1 public class RegisterMessage extends BaseMessage{
 2 
 3     private final int type = MessageType.REGISTER;
 4     private String username;
 5     private String password;
 6     private String confirm;
 7     
 8     public String getUsername() {
 9         return username;
10     }
11     public RegisterMessage setUsername(String username) {
12         this.username = username;
13         return this;
14     }
15     public String getPassword() {
16         return password;
17     }
18     public RegisterMessage setPassword(String password) {
19         this.password = password;
20         return this;
21     }
22     public String getConfirm() {
23         return confirm;
24     }
25     public RegisterMessage setConfirm(String confirm) {
26         this.confirm = confirm;
27         return this;
28     }
29     public int getType() {
30         return type;
31     }
32 }
View Code
技术分享
 1 public class ReturnMessage extends BaseMessage {
 2 
 3     private final int type = MessageType.RETURN;
 4     private boolean success;
 5     // success
 6     private String key;
 7     private Object content;
 8     // error
 9     private String message;
10     private String code;
11     
12     
13     public int getType() {
14         return type;
15     }
16     public boolean isSuccess() {
17         return success;
18     }
19     public ReturnMessage setSuccess(boolean success) {
20         this.success = success;
21         return this;
22     }
23     public String getKey() {
24         return key;
25     }
26     public ReturnMessage setKey(String key) {
27         this.key = key;
28         return this;
29     }
30     public Object getContent() {
31         return content;
32     }
33     public ReturnMessage setContent(Object content) {
34         this.content = content;
35         return this;
36     }
37     public String getMessage() {
38         return message;
39     }
40     public ReturnMessage setMessage(String message) {
41         this.message = message;
42         return this;
43     }
44     public String getCode() {
45         return code;
46     }
47     public ReturnMessage setCode(String code) {
48         this.code = code;
49         return this;
50     }
51 }
View Code

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

 1 public interface Key {
 2     /**
 3      * 登陆
 4      */
 5     String LOGIN = "LOGIN";
 6     /**
 7      * 注册
 8      */
 9     String REGISTER = "REGISTER";
10     /**
11      * Client 上线 / 离线 通知
12      */
13     String NOTIFY = "NOTIFY";
14     /**
15      * 拉去在线 Client 列表
16      */
17     String LISTUSER = "LISTUSER";
18     /**
19      * TIP 提示
20      */
21     String TIP = "TIP";
22 } 
 1 public class ClientListUserDTO {
 2 
 3     private Set<String> listUser;
 4 
 5     public Set<String> getListUser() {
 6         return listUser;
 7     }
 8     public void setListUser(Set<String> listUser) {
 9         this.listUser = listUser;
10     }
11 } 
 1 public class ClientNotifyDTO {
 2 
 3     private boolean flag; // true:online,false:offline
 4     private String username; // hostname
 5     
 6     public ClientNotifyDTO() {
 7     }
 8     public ClientNotifyDTO(boolean flag, String username) {
 9         this.flag = flag;
10         this.username = username;
11     }
12     public boolean isFlag() {
13         return flag;
14     }
15     public void setFlag(boolean flag) {
16         this.flag = flag;
17     }
18     public String getUsername() {
19         return username;
20     }
21     public void setUsername(String username) {
22         this.username = username;
23     }
24 } 

另外几个常量也给出:

 1 public interface ConstantValue {
 2     /**
 3      * 缓冲区大小
 4      */
 5     int BUFF_SIZE = 1024;
 6     /**
 7      * 调试模式
 8      */
 9     int DEBUG_LEVEL = 0;
10     /**
11      * 客户端接收文件的存储路径
12      */
13     String CLIENT_RECEIVE_DIR = "./file";
14     /**
15      * KEEPALIVE PERIOD‘second
16      */
17     int KEEP_ALIVE_PERIOD = 20;
18     /**
19      * 最大socket线程处理数
20      */
21     int MAX_POOL_SIZE = PropertiesUtil.getInt("server-thread-pool-size", 30);
22     /**
23      * <pre>
24      * 检测是否有新的数据时间间隔‘ms
25      * (server.SocketDispatch,client.ReceiveListener,SendHelper)
26      * 使用同一个Thread.sleep时间保证数据能正确接收到,同时降低CPU的使用率
27      * !!!!! -非常重要- !!!!!
28      * </pre>
29      */
30     int MESSAGE_PERIOD = 500;
31     /**
32      * 服务器IP地址
33      */
34     String SERVER_IP = PropertiesUtil.get("server-ip", "127.0.0.1");
35     /**
36      * 服务器名称,用户注册不能使用此用户名
37      */
38     String SERVER_NAME = "niloay";
39     /**
40      * 服务器端口
41      */
42     int SERVER_PORT = PropertiesUtil.getInt("server-port", 8888);
43     /**
44      * SOCKET超时时间‘second
45      */
46     int TIME_OUT = 120;
47     /**
48      * 群发标识TO:ALL,用户注册不能使用此用户名
49      */
50     String TO_ALL = "TO_ALL";
51 } 
技术分享
 1 public interface I18N {
 2 
 3     //---------------------------------
 4     // TEXT
 5     //---------------------------------
 6     /**
 7      * APP_NAME
 8      */
 9     String TEXT_APP_NAME = "NILOAY-CHAT v1.0.0";
10     /**
11      * 登陆
12      */
13     String TEXT_LOGIN = "登陆";
14     /**
15      * 注册
16      */
17     String TEXT_REGISTER = "注册";
18     /**
19      * 账号
20      */
21     String TEXT_USERNAME = "账号";
22     /**
23      * 密码
24      */
25     String TEXT_PASSWORD = "密码";
26     
27     //---------------------------------
28     // BTN
29     //---------------------------------
30     /**
31      * 注册
32      */
33     String BTN_REGISTER = "注册";
34     /**
35      * 登陆
36      */
37     String BTN_LOGIN = "登陆";
38     /**
39      * 退出
40      */
41     String BTN_EXIT = "退出";
42     /**
43      * 发送
44      */
45     String BTN_SEND = "发送";
46     /**
47      * 发送文件
48      */
49     String BTN_SEND_FILE = "发送文件";
50     
51     //---------------------------------
52     // INFO
53     //---------------------------------
54     /**
55      * 请填写注册账号和密码
56      */
57     String INFO_REGISTER_EMPTY_DATA = "请填写注册账号和密码";
58     /**
59      * 用户已存在
60      */
61     String INFO_REGISTER_CLIENT_EXIST = "用户已存在";
62     /**
63      * 注册成功
64      */
65     String INFO_REGISTER_OK = "注册成功";
66     /**
67      * 请输入登陆账号和密码
68      */
69     String INFO_LOGIN_EMPTY_DATA = "请输入登陆账号和密码";
70     /**
71      * 登陆账号或密码错误
72      */
73     String INFO_LOGIN_ERROR_DATA = "登陆账号或密码错误";
74     /**
75      * 暂不支持文件群发
76      */
77     String INFO_FILE_TO_ALL_ERROR = "暂不支持文件群发";
78     /**
79      * 文件发送成功
80      */
81     String INFO_FILE_SEND_SUCCESSFULLY = "文件发送成功";
82     /**
83      * 文件接收成功
84      */
85     String INFO_FILE_RECEIVE_SUCCESSFULLY = "文件接收成功";
86 }
View Code

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

Socket聊天程序——初始设计

Socket聊天程序——服务端

Socket聊天程序——客户端

以上是关于Socket聊天程序——Common的主要内容,如果未能解决你的问题,请参考以下文章

使用C/C++实现Socket聊天程序(代码+实验报告)

聊天应用程序 - Socket.IO/Angular/MongoDB - 聊天和聊天历史不显示

java TCP做聊天程序是应该一个聊天窗口一个线程还是一个Socket一个线程

用socket写一个简单的聊天程序

Python Socket 编程——聊天室演示样例程序

在已经在wampserver上运行的网站上运行socket.io聊天应用程序