- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解基于java的Socket聊天程序——服务端(附demo)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
写在前面:
昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图:
功能说明:
服务端主要有两个操作,一是阻塞接收客户端的socket并做响应处理,二是检测客户端的心跳,如果客户端一段时间内没有发送心跳则移除该客户端,由Server创建ServerSocket,然后启动两个线程池去处理这两件事(newFixedThreadPool,newScheduledThreadPool),对应的处理类分别是SocketDispatcher、SocketSchedule,其中SocketDispatcher根据socket不同的请求分发给不同SocketHandler去处理,而SocketWrapper则是对socket加了一层外壳包装,用lastAliveTime记录socket最新的交互时间,SocketHolder存储当前跟服务端交互的socket集合.
具体实现:
[Server.java] 。
Server是服务端的入口,由Server的start()方法启动ServerSocket,然后阻塞接收客户端的请求,交由SocketDispatcher去分发,SocketDispatcher由newFixedThread类型的线程池启动,当连接数超过最大数据时将被队列处理,使用scheduleAtFixedRate启动SocketSchedule定时循环去监听客户端的心跳包,这两个类型都实现了Runnable接口,下面给出服务端的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
package
yaolin.chat.server;
import
java.io.IOException;
import
java.net.ServerSocket;
import
java.util.Date;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.ScheduledExecutorService;
import
java.util.concurrent.TimeUnit;
import
yaolin.chat.common.ConstantValue;
import
yaolin.chat.util.LoggerUtil;
/**
* 服务器
* @author yaolin
*/
public
class
Server {
private
final
ServerSocket server;
private
final
ExecutorService pool;
public
Server()
throws
IOException {
server =
new
ServerSocket(ConstantValue.SERVER_PORT);
pool = Executors.newFixedThreadPool(ConstantValue.MAX_POOL_SIZE);
}
public
void
start() {
try
{
ScheduledExecutorService schedule = Executors.newScheduledThreadPool(
1
);
// Watch dog. Exception??
schedule.scheduleAtFixedRate(
new
SocketSchedule(),
10
, ConstantValue.TIME_OUT, TimeUnit.SECONDS);
while
(
true
) {
pool.execute(
new
SocketDispatcher(server.accept()));
LoggerUtil.info(
"ACCEPT A CLIENT AT "
+
new
Date());
}
}
catch
(IOException e) {
pool.shutdown();
}
}
public
static
void
main(String[] args) {
try
{
new
Server().start();
}
catch
(IOException e) {
LoggerUtil.error(
"Server start failed! -> "
+ e.getMessage(), e);
}
}
}
|
[SocketDispatcher.java] 。
Server只是服务端的入口,并指挥中心,SocketDispatcher才是服务端的指挥中心,对客户端不同的消息类型请求进行分发,让不同的SocketHandler去处理对应的消息请求,这里服务端和客户端的消息交互都是用JSON数据,所有消息类都继承BaseMessage,所以将接收到数据转换成BaseMessage类型,再判断其类型,(数据类型模块属于common模块),这里需要提一下的是当消息类型是文件类型的时候会睡眠配置执行的间隔时间,这样FileHandler才能有时间对文件流进行读取和重新发送给指定的客户端,而不会立即进入下一次循环对消息类型的判断(可能这里设计有点问题,不过暂时先这样做),下面给出SocketDispatcher的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
/**
* SocketDispatcher
*
* @author yaolin
*/
public
class
SocketDispatcher
implements
Runnable {
private
final
Socket socket;
public
SocketDispatcher(Socket socket) {
this
.socket = socket;
}
@Override
public
void
run() {
if
(socket !=
null
) {
while
(!socket.isClosed()) {
try
{
InputStream is = socket.getInputStream();
String line =
null
;
StringBuffer sb =
null
;
if
(is.available() >
0
) {
BufferedReader bufr =
new
BufferedReader(
new
InputStreamReader(is));
sb =
new
StringBuffer();
while
(is.available() >
0
&& (line = bufr.readLine()) !=
null
) {
sb.append(line);
}
LoggerUtil.trach(
"RECEIVE ["
+ sb.toString() +
"] AT "
+
new
Date());
BaseMessage message = JSON.parseObject(sb.toString(), BaseMessage.
class
);
switch
(message.getType()) {
case
MessageType.ALIVE:
HandlerFactory.getHandler(MessageType.ALIVE).handle(socket, sb.toString());
break
;
case
MessageType.CHAT:
HandlerFactory.getHandler(MessageType.CHAT).handle(socket, sb.toString());
break
;
case
MessageType.FILE:
HandlerFactory.getHandler(MessageType.FILE).handle(socket, sb.toString());
LoggerUtil.trach(
"SEVER:PAUSE TO RECEIVE FILE"
);
Thread.sleep(ConstantValue.MESSAGE_PERIOD);
break
;
case
MessageType.LOGIN:
HandlerFactory.getHandler(MessageType.LOGIN).handle(socket, sb.toString());
break
;
case
MessageType.LOGOUT:
break
;
case
MessageType.REGISTER:
HandlerFactory.getHandler(MessageType.REGISTER).handle(socket, sb.toString());
break
;
}
}
else
{
Thread.sleep(ConstantValue.MESSAGE_PERIOD);
}
}
catch
(Exception e) {
// catch all handler exception
LoggerUtil.error(
"SocketDispatcher Error!"
+ e.getMessage(), e);
}
}
}
}
}
|
[SocketSchedule.java] 。
跟Server有直接关系的另一个类(组件)是SocketSchedule,SocketSchedule主要负责检测客户端的最新一次跟服务端的交互时间是否超过系统配置允许最大的时间,如果超过了,则将该客户端socket从服务端移除,否则更新客户端的最新一次跟服务端的交互时间。下面是具体的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* Remove socket from SocketHolder if lastAliveTime > TIME_OUT
* @author yaolin
*
*/
public
class
SocketSchedule
implements
Runnable {
@Override
public
void
run() {
for
(String key : SocketHolder.keySet()) {
SocketWrapper wrapper = SocketHolder.get(key);
if
(wrapper !=
null
&& wrapper.getLastAliveTime() !=
null
) {
if
(((
new
Date().getTime() - wrapper.getLastAliveTime().getTime()) /
1000
) > ConstantValue.TIME_OUT) {
// remove socket if timeout
SocketHolder.remove(key);
}
}
}
}
}
|
[SocketHolder.java、SocketWrapper.java] 。
从上面的代码可以看出,SocketSchedule#run()只是简单的对时间进行一次判断,真正有意义的其实是SocketHolder和SocketWrapper,SocketWrapper则是对socket加了一层外壳包装,SocketHolder的存储了当前有效时间内所有跟服务端有交互的客户端,SocketHolder以客户端的唯一标识(这里使用用户名),作为KEY,客户端所在的socket作为VALUE的键值对形式存储,其中SocketHolder#flushClientStatus()的处理逻辑是用于通知其他客户端当前客户端的上线/离线状态,下面给出这两个类的具体实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/**
* Wrap Socket, SocketSchedule remove socket if lastAliveTime > TIME_OUT
* @author yaolin
*
*/
public
class
SocketWrapper {
private
Socket socket;
private
Date lastAliveTime;
// full constructor
public
SocketWrapper(Socket socket, Date lastAliveTime) {
this
.socket = socket;
this
.lastAliveTime = lastAliveTime;
}
public
Socket getSocket() {
return
socket;
}
public
void
setSocket(Socket socket) {
this
.socket = socket;
}
public
Date getLastAliveTime() {
return
lastAliveTime;
}
public
void
setLastAliveTime(Date lastAliveTime) {
this
.lastAliveTime = lastAliveTime;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
/**
* SocketHolder
* @author yaolin
*/
public
class
SocketHolder {
private
static
ConcurrentMap<String, SocketWrapper> listSocketWrap =
new
ConcurrentHashMap<String, SocketWrapper>();
public
static
Set<String> keySet() {
return
listSocketWrap.keySet();
}
public
static
SocketWrapper get(String key) {
return
listSocketWrap.get(key);
}
public
static
void
put(String key, SocketWrapper value) {
listSocketWrap.put(key, value);
flushClientStatus(key,
true
);
}
public
static
SocketWrapper remove(String key) {
flushClientStatus(key,
false
);
return
listSocketWrap.remove(key);
}
public
static
void
clear() {
listSocketWrap.clear();
}
/**
* <pre>content:{username:"",flag:false}</pre>
* @param flag true:put,false:remove;
*/
private
static
void
flushClientStatus(String key,
boolean
flag) {
ClientNotifyDTO dto =
new
ClientNotifyDTO(flag, key);
ReturnMessage rm =
new
ReturnMessage().setKey(Key.NOTIFY).setSuccess(
true
).setContent(dto);
rm.setFrom(ConstantValue.SERVER_NAME);
for
(String toKey : listSocketWrap.keySet()) {
if
(!toKey.equals(key)) {
// not send to self
rm.setTo(toKey);
SocketWrapper wrap = listSocketWrap.get(toKey);
if
(wrap !=
null
) {
SendHelper.send(wrap.getSocket(), rm);
}
}
}
}
}
|
[SocketHandler.java、HandlerFactory.java、OtherHandlerImpl.java] 。
SocketDispatcher让不同的SocketHandler去处理对应的消息请求,SocketHandler的设计其实就是一套简单的工厂组件吧(其中ReturnHandler暂时由SendHelper实现信息传送,暂时没有用到,已经@Deprecated ,这里还是给出),完整类图如下:
下面给出这一块的代码,为了缩小篇幅,将所有Handler实现的代码收起来.
1
2
3
4
5
6
7
8
9
10
|
/**
* SocketHandler
* @author yaolin
*/
public
interface
SocketHandler {
/**
* Handle Client Socket
*/
public
Object handle(Socket client,Object data);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* SocketHandlerFactory
* @author yaolin
*/
public
class
HandlerFactory {
// can not create instance
private
HandlerFactory(){}
public
static
SocketHandler getHandler(
int
type) {
switch
(type) {
case
MessageType.ALIVE:
// usually use
return
new
AliveHandler();
case
MessageType.CHAT:
return
new
ChatHandler();
case
MessageType.LOGIN:
return
new
LoginHandler();
// case MessageType.RETURN:
// return new ReturnHandler();
case
MessageType.LOGOUT:
return
new
LogoutHandler();
case
MessageType.REGISTER:
return
new
RegisterHandler();
case
MessageType.FILE:
return
new
FileHandler();
}
return
null
;
// NullPointException
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* AliveSocketHandler
* @author yaolin
*/
public
class
AliveHandler
implements
SocketHandler {
/**
* @return null
*/
@Override
public
Object handle(Socket client, Object data) {
if
(data !=
null
) {
BaseMessage message = JSON.parseObject(data.toString(), BaseMessage.
class
);
if
(StringUtil.isNotEmpty(message.getFrom())) {
SocketWrapper wrapper = SocketHolder.get(message.getFrom());
if
(wrapper !=
null
) {
wrapper.setLastAliveTime(
new
Date());
// KEEP SOCKET ...
SocketHolder.put(message.getFrom(), wrapper);
}
}
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/**
* ChatHandler
*
* @author yaolin
*/
public
class
ChatHandler
implements
SocketHandler {
@Override
public
Object handle(Socket client, Object data) {
if
(data !=
null
) {
ChatMessage message = JSON.parseObject(data.toString(), ChatMessage.
class
);
if
(StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
// exist & send
if
(SocketHolder.keySet().contains(message.getFrom())) {
String owner = message.getFrom();
message.setOwner(owner);
// owner will be display
if
(ConstantValue.TO_ALL.equals(message.getTo())) {
// one-to-all
// TO_ALL TAB will be select;
message.setFrom(ConstantValue.TO_ALL);
for
(String key : SocketHolder.keySet()) {
// also send to self
SocketWrapper wrapper = SocketHolder.get(key);
if
(wrapper !=
null
) {
SendHelper.send(wrapper.getSocket(), message);
}
}
}
else
{
// one-to-one
SocketWrapper wrapper = SocketHolder.get(message.getTo());
if
(wrapper !=
null
) {
// owner = from
SendHelper.send(wrapper.getSocket(), message);
// also send to self
// TO TAB will be select;
message.setFrom(message.getTo()).setTo(owner);
SendHelper.send(client, message);
}
}
}
}
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public
class
FileHandler
implements
SocketHandler {
@Override
public
Object handle(Socket client, Object data) {
if
(client !=
null
) {
FileMessage message = JSON.parseObject(data.toString(), FileMessage.
class
);
if
(StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
// exist & send
if
(SocketHolder.keySet().contains(message.getFrom())) {
if
(!ConstantValue.TO_ALL.equals(message.getTo())) {
// one-to-all
SocketWrapper wrapper = SocketHolder.get(message.getTo());
if
(wrapper !=
null
) {
SendHelper.send(wrapper.getSocket(), message);
try
{
if
(client !=
null
&& wrapper.getSocket() !=
null
&& message.getSize() >
0
) {
InputStream is = client.getInputStream();
OutputStream os = wrapper.getSocket().getOutputStream();
int
total =
0
;
while
(!client.isClosed() && !wrapper.getSocket().isClosed()) {
if
(is.available() >
0
) {
byte
[] buff =
new
byte
[ConstantValue.BUFF_SIZE];
int
len = -
1
;
while
(is.available() >
0
&& (len = is.read(buff)) != -
1
) {
os.write(buff,
0
, len);
total += len;
LoggerUtil.debug(
"SEND BUFF ["
+ len +
"]"
);
}
os.flush();
if
(total >= message.getSize()) {
LoggerUtil.info(
"SEND BUFF [OK]"
);
break
;
}
}
}
// AFTER SEND FILE
// SEND SUCCESSFULLY
ReturnMessage result =
new
ReturnMessage().setKey(Key.TIP)
.setSuccess(
true
)
.setContent(I18N.INFO_FILE_SEND_SUCCESSFULLY);
result.setFrom(message.getTo()).setTo(message.getFrom())
.setOwner(ConstantValue.SERVER_NAME);
SendHelper.send(client, result);
// RECEIVE SUCCESSFULLY
result.setContent(I18N.INFO_FILE_RECEIVE_SUCCESSFULLY)
.setFrom(message.getFrom())
.setTo(message.getTo());
SendHelper.send(wrapper.getSocket(), result);
}
}
catch
(Exception e) {
LoggerUtil.error(
"Handle file failed !"
+ e.getMessage(), e);
}
}
}
}
}
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
/**
* LoginHandler
*
* @author yaolin
*
*/
public
class
LoginHandler
implements
SocketHandler {
private
UsrService usrService =
new
UsrService();
@Override
public
Object handle(Socket client, Object data) {
ReturnMessage result =
new
ReturnMessage();
result.setSuccess(
false
);
if
(data !=
null
) {
LoginMessage message = JSON.parseObject(data.toString(), LoginMessage.
class
);
if
(StringUtil.isNotEmpty(message.getUsername()) && StringUtil.isNotEmpty(message.getPassword())) {
if
(usrService.login(message.getUsername(), message.getPassword()) !=
null
) {
result.setSuccess(
true
);
}
else
{
result.setMessage(I18N.INFO_LOGIN_ERROR_DATA);
}
result.setFrom(ConstantValue.SERVER_NAME).setTo(message.getUsername());
}
else
{
result.setMessage(I18N.INFO_LOGIN_EMPTY_DATA);
}
// AFTER LOGIN
result.setKey(Key.LOGIN);
if
(result.isSuccess()) {
// HOLD SOCKET
SocketHolder.put(result.getTo(),
new
SocketWrapper(client,
new
Date()));
}
SendHelper.send(client, result);
if
(result.isSuccess()) {
// SEND LIST USER
ClientListUserDTO dto =
new
ClientListUserDTO();
dto.setListUser(SocketHolder.keySet());
result.setContent(dto).setKey(Key.LISTUSER);
SendHelper.send(client, result);
}
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
LogoutHandler
implements
SocketHandler {
@Override
public
Object handle(Socket client, Object data) {
if
(data !=
null
) {
LogoutMessage message = JSON.parseObject(data.toString(), LogoutMessage.
class
);
if
(message !=
null
&& StringUtil.isNotEmpty(message.getFrom())) {
SocketWrapper wrapper = SocketHolder.get(message.getFrom());
Socket socket = wrapper.getSocket();
if
(socket !=
null
) {
try
{
socket.close();
socket =
null
;
}
catch
(Exception ignore) {
}
}
SocketHolder.remove(message.getFrom());
}
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
class
RegisterHandler
implements
SocketHandler {
private
UsrService usrService =
new
UsrService();
@Override
public
Object handle(Socket client, Object data) {
ReturnMessage result =
new
ReturnMessage();
result.setSuccess(
false
).setFrom(ConstantValue.SERVER_NAME);
if
(data !=
null
) {
RegisterMessage message = JSON.parseObject(data.toString(), RegisterMessage.
class
);
if
(StringUtil.isNotEmpty(message.getUsername()) && StringUtil.isNotEmpty(message.getPassword())) {
if
(usrService.register(message.getUsername(), message.getPassword()) !=
null
) {
result.setSuccess(
true
).setContent(I18N.INFO_REGISTER_OK);
}
else
{
result.setMessage(I18N.INFO_REGISTER_CLIENT_EXIST);
}
}
else
{
result.setMessage(I18N.INFO_REGISTER_EMPTY_DATA);
}
if
(StringUtil.isNotEmpty(message.getUsername())) {
result.setTo(message.getUsername());
}
// AFTER REGISTER
result.setKey(Key.REGISTER);
SendHelper.send(client, result);
}
return
null
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/**
* Use SendHelper to send ReturnMessage,
* @see yaolin.chat.server.SocketDispatcher#run()
* @author yaolin
*/
@Deprecated
public
class
ReturnHandler
implements
SocketHandler {
/**
* @param data ReturnMessage
*/
@Override
public
Object handle(Socket client, Object data) {
if
(data !=
null
) {
ReturnMessage message = (ReturnMessage) data;
if
(StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
SocketWrapper wrap = SocketHolder.get(message.getTo());
if
(wrap !=
null
) {
SendHelper.send(wrap.getSocket(), message);
}
}
}
return
null
;
}
}
|
用户业务:
服务端除了socket之外,还有一点点具体的业务,那就是用户的注册、登陆等,这里简单的列出Usr和UsrService这两个类,这些业务暂时没有怎么实现,我并不打算在这个程序中引入ORM框架,所以自己写一套DBUtil(待改善),在这里也一并贴出来.
这里只进行了简单的校验,没有持久化存储到DB中,下面是Usr和UsrService:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public
class
Usr {
private
long
id;
private
String username;
private
String password;
public
long
getId() {
return
id;
}
public
void
setId(
long
id) {
this
.id = id;
}
public
String getUsername() {
return
username;
}
public
void
setUsername(String username) {
this
.username = username;
}
public
String getPassword() {
return
password;
}
public
void
setPassword(String password) {
this
.password = password;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/**
* // TODO
* @see yaolin.chat.server.usr.repository.UsrRepository
* @author yaolin
*
*/
public
class
UsrService {
// TODO db
private
static
Map<String,Usr> db =
new
HashMap<String,Usr>();
public
Usr register(String username, String password) {
if
(StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
return
null
;
}
if
(db.containsKey(username)) {
return
null
;
// exist;
}
Usr usr =
new
Usr();
usr.setUsername(username);
usr.setPassword(MD5Util.getMD5Code(password));
db.put(username, usr);
return
usr;
}
public
Usr login(String username, String password) {
if
(StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
return
null
;
}
if
(db.containsKey(username)) {
Usr usr = db.get(username);
if
(MD5Util.getMD5Code(password).equals(usr.getPassword())) {
return
usr;
}
}
return
null
;
}
}
|
下面是DBUtil工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
/**
* DBUtils // TODO 有待调整&优化!!
* @author yaolin
*/
public
class
DBUtil {
// make connection used repeatedly
private
static
final
List<Connection> cache =
new
LinkedList<Connection>();
private
static
String url;
private
static
String driver;
private
static
String user;
private
static
String password;
private
static
Boolean debug;
static
{
InputStream is = DBUtil.
class
.getResourceAsStream(
"/db.properties"
);
try
{
Properties p =
new
Properties();
p.load(is);
url = p.getProperty(
"url"
);
driver = p.getProperty(
"driver"
);
user = p.getProperty(
"user"
);
password = p.getProperty(
"password"
);
// just for debug
try
{
debug = Boolean.valueOf(p.getProperty(
"debug"
));
}
catch
(Exception ignore) {
debug =
false
;
}
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
finally
{
if
(is !=
null
) {
try
{
is.close();
is =
null
;
}
catch
(Exception ignore) {
}
}
}
}
public
synchronized
static
Connection getConnection() {
if
(cache.isEmpty()) {
cache.add(makeConnection());
}
Connection conn =
null
;
int
i =
0
;
try
{
do
{
conn = cache.remove(i);
}
while
(conn !=
null
&& conn.isClosed() && i < cache.size());
}
catch
(Exception ignore) {
}
try
{
if
(conn ==
null
|| conn.isClosed()) {
cache.add(makeConnection());
conn = cache.remove(
0
);
}
return
conn;
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
public
synchronized
static
void
close(Connection connection) {
try
{
if
(connection !=
null
&& !connection.isClosed()) {
if
(debug)
debug(
"release connection!"
);
cache.add(connection);
}
}
catch
(SQLException ignore) {
}
}
public
static
Object query(String sql, ResultSetMapper mapper, Object... args) {
if
(debug)
debug(sql);
Connection conn = getConnection();
PreparedStatement ps =
null
;
ResultSet rs =
null
;
Object result =
null
;
try
{
ps = conn.prepareStatement(sql);
int
i =
1
;
for
(Object object : args) {
ps.setObject(i++, object);
}
rs = ps.executeQuery();
result = mapper.mapper(rs);
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
finally
{
try
{
if
(rs !=
null
) {
rs.close();
rs =
null
;
}
if
(ps !=
null
) {
ps.close();
ps =
null
;
}
}
catch
(Exception ignore) {
}
}
close(conn);
return
result;
}
public
static
int
modify(String sql, Object... args) {
if
(debug)
debug(sql);
Connection conn = getConnection();
PreparedStatement ps =
null
;
int
row =
0
;
try
{
ps = conn.prepareStatement(sql);
int
i =
1
;
for
(Object object : args) {
ps.setObject(i++, object);
}
row = ps.executeUpdate();
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
finally
{
try
{
if
(ps !=
null
) {
ps.close();
ps =
null
;
}
}
catch
(Exception ignore) {
}
}
close(conn);
return
row;
}
public
static
int
[] batch(List<String> sqls) {
if
(debug)
debug(sqls.toString());
Connection conn = getConnection();
Statement stmt =
null
;
int
[] row;
try
{
stmt = conn.createStatement();
for
(String sql : sqls) {
stmt.addBatch(sql);
}
row = stmt.executeBatch();
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
finally
{
try
{
if
(stmt !=
null
) {
stmt.close();
stmt =
null
;
}
}
catch
(Exception ignore) {
}
}
close(conn);
return
row;
}
public
static
int
[] batch(String sql, PreparedStatementSetter setter) {
if
(debug)
debug(sql);
Connection conn = getConnection();
PreparedStatement ps =
null
;
int
[] row;
try
{
ps = conn.prepareStatement(sql);
setter.setter(ps);
row = ps.executeBatch();
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
finally
{
try
{
if
(ps !=
null
) {
ps.close();
ps =
null
;
}
}
catch
(Exception ignore) {
}
}
close(conn);
return
row;
}
private
static
Connection makeConnection() {
try
{
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url, user, password);
if
(debug)
debug(
"create connection!"
);
return
conn;
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
private
static
void
debug(String sqls) {
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
System.out.println(sdf.format(
new
Date())
+
" DEBUG "
+ Thread.currentThread().getId()
+
" --- ["
+ Thread.currentThread().getName() +
"] "
+
"excute sqls : "
+ sqls);
}
}
|
1
2
3
4
5
6
7
|
/**
* PreparedStatementSetter
* @author yaolin
*/
public
interface
PreparedStatementSetter {
public
void
setter(PreparedStatement ps);
}
|
1
2
3
4
5
6
7
|
/**
* ResultSetMapper
* @author yaolin
*/
public
interface
ResultSetMapper {
public
Object mapper(ResultSet rs);
}
|
源码下载:demo 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/niloay/p/socket-chatserver.html 。
最后此篇关于详解基于java的Socket聊天程序——服务端(附demo)的文章就讲到这里了,如果你想了解更多关于详解基于java的Socket聊天程序——服务端(附demo)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
基于 socket.io 的官方网站 http://socket.io/#how-to-use , 我找不到任何术语。socket.emit 、 socket.on 和 socket.send 之间有
我正在使用 lua-socket 3.0rc1.3(Ubuntu Trusty 附带)和 lua 5.1。我正在尝试监听 unix 域套接字,我能找到的唯一示例代码是 this -- send std
这两者有什么区别? 我注意到如果我在一个工作程序中从 socket.emit 更改为 socket.send ,服务器无法接收到消息,虽然我不明白为什么。 我还注意到,在我的程序中,如果我从 sock
使用套接字在两台服务器之间发送数据是个好主意,还是应该使用 MQ 之类的东西来移动数据。 我的问题:套接字是否可靠,如果我只需要一次/有保证的数据传输? 还有其他解决方案吗? 谢谢。 最佳答案 套接字
引自 this socket tutorial : Sockets come in two primary flavors. An active socket is connected to a
我已经安装了在端口81上运行的流服务器“Lighttpd”(light-tpd)。 我有一个C程序,它使用套接字api创建的服务器套接字在端口80上监听http请求。 我希望从客户端收到端口80上的请
这是我正在尝试做的事情: 当有新消息可用时,服务器会将消息发送给已连接的客户端。另一方面,客户端在连接时尝试使用send()向服务器发送消息,然后使用recv()接收消息,此后,客户端调用close(
如何将消息发送到动态 session 室,以及当服务器收到该消息时,如何将该消息发送到其他成员所在的同一个 session 室? table_id是房间,它将动态设置。 客户: var table_i
这是我尝试但不起作用的方法。我可以将传入的消息从WebSocket连接转发到NetSocket,但是只有NetSocket收到的第一个消息才到达WebSocket后面的客户端。 const WebSo
我正在实现使用boost将xml发送到客户端的服务器。我面临的问题是缓冲区不会立即发送并累积到一个点,然后发送整个内容。这在我的客户端造成了一个问题,当它解析xml时,它可能具有不完整的xml标记(不
尝试使用Nginx代理Gunicorn套接字。 /etc/systemd/system/gunicorn.service文件 [Unit] Description=gunicorn daemon Af
我正在使用Lua套接字和TCP制作像聊天客户端和服务器这样的IRC。我要弄清楚的主要事情是如何使客户端和服务器监听消息并同时发送它们。由于在服务器上执行socket:accept()时,它将暂停程序,
我看了一下ZMQ PUSH/PULL套接字,尽管我非常喜欢简单性(特别是与我现在正在通过UDP套接字在系统中实现的自定义碎片/ack相比),但我还是希望有自定义负载平衡功能,而不是幼稚的回合-robi
我正在编写一个应用程序,其中有多个 socket.io 自定义事件,并且所有工作正常,除了这个: socket.on("incomingImg", function(data) {
在我的应用程序中,我向服务器发送了两条小消息(类似 memcached 的服务)。在类似 Python 的伪代码中,这看起来像: sock.send("add some-key 0") ignored
很抱歉再次发布此问题,但大多数相关帖子都没有回答我的问题。我在使用 socket.io 的多个连接时遇到问题我没有使用“socket.socket.connect”方法,但我从第一次连接中得到了反馈。
我尝试使用 socket.io 客户端连接到非 socket.io websocket 服务器。但我做不到。我正在尝试像这样连接到套接字服务器: var socket = io.connect('ws
我遇到了一个奇怪的问题。在我非常基本的服务器中,我有: server.listen(8001); io.listen(server); var sockets = io.sockets; 不幸的是,套
我正在使用带套接字 io 的sailsjs。帆的版本是 0.10.5。我有以下套接字客户端进行测试: var socketIOClient = require('socket.io-client');
这个问题在这里已经有了答案: What is the fundamental difference between WebSockets and pure TCP? (4 个答案) 关闭 4 年前。
我是一名优秀的程序员,十分优秀!