java nio socket长连接_基于 java nio 长连接实现的聊天室

基于 java nio 长连接实现的聊天室,如果并发量大的话,可能会有线程问题。

服务端代码

package com.lp.io.socket;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Iterator;

import java.util.List;

public class LpNioServerSocket {

//线程安全

private static List channels = Collections.synchronizedList( new ArrayList() );

public static void main(String[] args) {

HandlerSelectionKey handler = new HandlerHandlerSelectionKeyImpl();

try {

//创建 ServerSocketChannel

ServerSocketChannel server = ServerSocketChannel.open();

server.configureBlocking(false);

server.bind(new InetSocketAddress("localhost", 12345));

//创建 Selector

Selector selector = Selector.open();

server.register(selector, SelectionKey.OP_ACCEPT);

//死循环,持续接收 客户端连接

while(true) {

//selector.select(); 是阻塞方法

int keys = selector.select();

if(keys > 0) {

Iterator it = selector.selectedKeys().iterator();

while(it.hasNext()) {

SelectionKey key = it.next();

it.remove();

//处理 SelectionKey

handler.handler(key, selector);

}

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* SelectionKey 处理接口

*

*/

public static interface HandlerSelectionKey {

public void handler(SelectionKey key, Selector selector) throws IOException;

}

/**

* SelectionKey 接口 实现类

*

*/

public static class HandlerHandlerSelectionKeyImpl implements HandlerSelectionKey {

@Override

public void handler(SelectionKey key, Selector selector) throws IOException {

int keyState = selectionKeyState(key);

switch (keyState) {

case SelectionKey.OP_ACCEPT:

ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();

accept(serverSocketChannel, selector);

break;

case SelectionKey.OP_READ:

SocketChannel readSocketChannel = (SocketChannel) key.channel();

read(readSocketChannel, selector);

break;

}

}

/**

* 获取 SelectionKey 是什么事件

* @param key

* @return

*/

private int selectionKeyState(SelectionKey key) {

if(key.isAcceptable()) {

return SelectionKey.OP_ACCEPT;

} else if(key.isReadable()) {

return SelectionKey.OP_READ;

}

return -1;

}

/**

* 接口客户端请求

* @param serverSocketChannel

* @param selector

* @throws IOException

*/

private void accept(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {

SocketChannel socketChannel = serverSocketChannel.accept();

socketChannel.configureBlocking(false);

channels.add(socketChannel);

//将 channel 注册到 Selector

socketChannel.register(selector, SelectionKey.OP_READ);

}

/**

* 读取客户端发送过来的信息

* @param socketChannel

* @param selector

* @throws IOException

*/

private void read(SocketChannel socketChannel, Selector selector) throws IOException {

ByteBuffer readBuffer = ByteBuffer.allocate(8192);

int readBytes = socketChannel.read(readBuffer);

String msg = "";//客户端发送来的消息

if(readBytes > 0) {

msg = new String(readBuffer.array(), 0, readBytes);

System.out.println("客户端发送来的消息");

System.out.println(msg);

}

write(socketChannel, msg);

}

/**

* 响应客户端请求

* @param socketChannel

* @param selector

* @throws IOException

*/

private void write(SocketChannel socketChannel, String msg) throws IOException {

msg = "游客" + socketChannel.hashCode()+ "\r\n " + msg;

//响应消息

byte[] responseByte = msg.getBytes();

ByteBuffer writeBuffer = ByteBuffer.allocate(responseByte.length);

writeBuffer.put(responseByte);

writeBuffer.flip();

//响应客户端

for(int i=0; i

if(!socketChannel.equals(channels.get(i))) {

channels.get(i).write(writeBuffer);

}

}

}

}

}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

客户端代码

package com.lp.io.socket;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

public class LpSocketClient1 {

/**

* @param args

* @throws IOException

* @throws UnknownHostException

* @throws InterruptedException

*/

public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {

final Socket socket = new Socket("localhost", 12345);

Thread inT = new Thread(new Runnable() {

@Override

public void run() {

try {

while(true) {

InputStream inputStream = socket.getInputStream();

byte[] b = new byte[8192];

int readSize = inputStream.read(b);

System.out.println(new String(b,0,readSize));

}

} catch (IOException e) {

e.printStackTrace();

}

}

});

inT.start();

while(true) {

InputStreamReader stdin = new InputStreamReader(System.in);//键盘输入

BufferedReader bufin = new BufferedReader(stdin);

String str = bufin.readLine();

System.out.println(str);

OutputStream outStream = socket.getOutputStream();

outStream.write(str.getBytes());

outStream.flush();

}

}

}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

启动服务端代码,然后启动多个客户端。在某个客户端代码控制台输入英文(输入中文乱码),点击回车,可以看到其他客户端控制台有信息输出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值