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 }

 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 }

 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 }

 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 }

 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 }

 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 }

 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 }

对于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 }

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

Socket聊天程序——初始设计

Socket聊天程序——服务端

Socket聊天程序——客户端

时间: 2024-11-05 06:00:24

Socket聊天程序——Common的相关文章

Socket聊天程序——客户端

写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细设计和Common模块记录一下,因为这个周末开始就要去忙其他东西了. 设计: 客户端设计主要分成两个部分,分别是socket通讯模块设计和UI相关设计. 客户端socket通讯设计: 这里的设计其实跟服务端的设计差不多,不同的是服务端是接收心跳包,而客户端是发送心跳包,由于客户端只与一个服务端进行通

Socket聊天程序——初始设计

写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了几个晚上的空闲时间敲了一个,目前仅支持单聊,群聊,文件传送这些功能.首先,贴出一个丑丑的程序图(UI是用java swing写的,这个早就忘光了,无奈看着JDK的API写了一个),如下图: 服务端设计: 服务端主要有两个操作,一是阻塞接收客户端的socket并做响应处理,二是检测客户端的心跳,如果客

聊天程序(基于Socket、Thread)

聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现了服务端跟多个客户端之间的聊天,可以群发消息,选择ip发消息,客户端向服务端发送文件. (例子为WinForm应用程序) Socket,端口,Tcp,UDP. 概念 1.Socket还被称作"套接字",应用程序通常通过套接字向网络发送请求或者应答网络请求.根据连接启动的方式以及本地套接字要

java Socket多线程聊天程序(适合初学者)

一个非常简单的java聊天程序,有客户端和服务器端,目前只有群聊功能,其他的所有功能都可以在这个基础上添加,现在我分享出来主要是为了保持一个最简单的java聊天程序便于初学者学习,界面也非常的简洁,只有两个文件,主要是用了socket,java多线程,知识点不是很多,很适合初学者 下面是服务器端代码 package tk.socket; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.Act

Socket网络编程--聊天程序(3)

上一小节,已经讲到可以每个人多说话,而且还没有限制,简单的来说,我们已经完成了聊天的功能了,那么接下来我们要实现什么功能呢?一个聊天程序至少应该支持一对多的通讯吧,接下来就实现多个客户端往服务器发送数据,和服务器向多个客户端发送数据. 多对一,单向,各个客户端都可以向服务器发送数据 close函数 #include <unistd.h> int close(int sockfd); //用于关闭所打开的Socket套接字 返回值:如果为0表示成功,-1表示失败 处理的办法是每一个客户端连接到服

Android IPC机制(五)用Socket实现跨进程聊天程序

相关文章: Android IPC机制(一)开启多进程 Android IPC机制(二)用Messenger进行进程间通信 Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用 Android IPC机制(四)用ContentProvider进行进程间通信 1.Socket简介 Socket也称作"套接字",是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信.它分为流式套接字和

socket实现的一个基本点对点聊天程序

多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据.为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口. 服务器监听是指服务端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态. 客户端请求是由客户端的套接字提出连接请求,要连接的目标是服务器端套接字.为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器套接字的地址和端口号,然后再向服务器端套接字提出连接请求.

Socket网络编程--聊天程序(6)

这一小节将增加一个用户的结构体,用于保存用户的用户名和密码,然后发给服务器,然后在服务器进行判断验证.这里就有一个问题,以前讲的就是发送字符串是使用char类型进行传输,然后在服务器进行用同样是字符串进行接收.然而作为一个结构体是不是也可以呢?如果有看send或recv的函数定义就知道第二个参数是void *类型,也就是说这两个函数对传入的类型其实是不做要求的,只是要你传输个地址,然后后面接一个大小就可以了.就是要send在这个地址取值,去大小为size个,然后传输.学过TCP/IP就知道,我们

Socket网络编程--聊天程序(4)

上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理.对于多用户连接时,服务器会受不了的,而且还很消耗资源.据说有个select函数可以用,好像还很NB的样子. 使用select多路转换处理聊天程序 下面摘取APUE 14.5小结 I/O多路转接 当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中循环中使用阻塞I/O: while((n = read(STDIN_FILENO, buf, BUFFSIZ))>0) if(writ