我是靠谱客的博主 灵巧发箍,这篇文章主要介绍Java的Socket实现长连接以及数据的发送和接收,现在分享给大家,希望可以做个参考。

既然是长连接就免不了心跳检测,这里使用了一种比较简单的做法:服务端对当前线程计时,重要的话说三遍,服务端、服务端、服务端!如果超时没有收到任何数据就关闭该线程对应的Socket。代码复制粘贴即可运行。

发送时:将String转byte[]

接收时:将byte[]转String

效果图

客户端代码

复制代码
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
import java.io.*; import java.net.Socket; import java.util.Scanner; public class SocketClient { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 8888); //得到一个输出流,用于向服务器发送数据 OutputStream outputStream = socket.getOutputStream(); System.out.println("请输入16进制数据:"); Scanner sc = new Scanner(System.in); while (true) { String data = sc.nextLine(); if ("exit".equals(data)) { return; } byte[] byteArray = HexStrToByteArray(data); outputStream.write(byteArray); //刷新缓冲 outputStream.flush(); //得到一个输入流,用于接收服务器响应的数据 InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1]; // 一次读取一个byte String info = ""; while (true) { if (inputStream.available() > 0) { inputStream.read(bytes); String hexStr = ByteArrayToHexStr(bytes); info += HexStrToStr(hexStr); //已经读完 if (inputStream.available() == 0) { System.out.println("收到来自服务端的信息:" + info); break; } } } } } catch (IOException e) { e.printStackTrace(); } } /** * 16进制Str转byte[] * * @param hexStr * @return */ public static byte[] HexStrToByteArray(String hexStr) { if (hexStr == null) { return null; } if (hexStr.length() == 0) { return new byte[0]; } byte[] byteArray = new byte[hexStr.length() / 2]; for (int i = 0; i < byteArray.length; i++) { String subStr = hexStr.substring(2 * i, 2 * i + 2); byteArray[i] = ((byte) Integer.parseInt(subStr, 16)); } return byteArray; } /** * byte[]转16进制Str * * @param byteArray */ public static String ByteArrayToHexStr(byte[] byteArray) { if (byteArray == null) { return null; } char[] hexArray = "0123456789ABCDEF".toCharArray(); char[] hexChars = new char[byteArray.length * 2]; for (int i = 0; i < byteArray.length; i++) { int temp = byteArray[i] & 0xFF; hexChars[i * 2] = hexArray[temp >>> 4]; hexChars[i * 2 + 1] = hexArray[temp & 0x0F]; } return new String(hexChars); } /** * 16进制的Str转Str * * @param hexStr * @return */ public static String HexStrToStr(String hexStr) { //能被16整除,肯定可以被2整除 byte[] array = new byte[hexStr.length() / 2]; try { for (int i = 0; i < array.length; i++) { array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16)); } hexStr = new String(array, "UTF-8"); } catch (Exception e) { e.printStackTrace(); return ""; } return hexStr; } }

服务端代码

使用InputStream对象的available()方法判断客户端的内容是否发送完毕

复制代码
1
dataInputStream.available()

官方解释:返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。用我的大白话就是:返回剩余未读长度

复制代码
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
import java.io.*; import java.net.Socket; /** * 长连接 */ public class ServerThread extends Thread { //16进制数字字符集 public static final String HEXSTRING = "0123456789ABCDEF"; //心跳超时时间 private static final int TIMEOUT = 60 * 1000; private Socket m_socket; //接收到数据的最新时间 private long m_lastReceiveTime = System.currentTimeMillis(); //该线程是否正在运行 private boolean m_isRuning = false; public ServerThread(Socket socket) { this.m_socket = socket; } @Override public void start() { if (m_isRuning) { System.out.println(">>>线程" + this.getId() + "启动失败,该线程正在执行"); return; } else { m_isRuning = true; super.start(); } } @Override public void run() { //字节输入流 InputStream inputStream = null; //字节输出流 OutputStream outputStream = null; try { inputStream = m_socket.getInputStream(); outputStream = m_socket.getOutputStream(); String info = ""; //按byte读 byte[] bytes = new byte[1]; while (m_isRuning) { //检测心跳 if (System.currentTimeMillis() - m_lastReceiveTime > TIMEOUT) { m_isRuning = false; //跳出,执行finally块 break; } //返回下次调用可以不受阻塞地从此流读取或跳过的估计字节数,如果等于0则表示已经读完 if (inputStream.available() > 0) { //重置接收到数据的最新时间 m_lastReceiveTime = System.currentTimeMillis(); inputStream.read(bytes); String tempStr = ByteArrayToHexStr(bytes) ; info += tempStr; //已经读完 if (inputStream.available() == 0) { System.out.println(">>>线程" + this.getId() + "收到:" + info); String responseStr = "Hello"; //响应内容 String hexStr = StrToHexStr(responseStr); hexStr = hexStr.replaceAll("0[x|X]|,",""); byte[] byteArray = HexStrToByteArray(hexStr); outputStream.write(byteArray); outputStream.flush(); //重置,不然每次收到的数据都会累加起来 info = ""; System.out.println(">>>线程" + this.getId() + "回应:" + responseStr); } } } } catch (Exception e) { e.printStackTrace(); } //关闭资源 finally { System.out.println(">>>线程" + this.getId() + "的连接已断开n"); try { if (outputStream != null) outputStream.close(); if (inputStream != null) inputStream.close(); if (m_socket != null) m_socket.close(); m_isRuning = false; } catch (IOException e) { e.printStackTrace(); } } } /** * byte[]转16进制Str * * @param byteArray */ public static String ByteArrayToHexStr(byte[] byteArray) { if (byteArray == null) { return null; } char[] hexArray = HEXSTRING.toCharArray(); char[] hexChars = new char[byteArray.length * 2]; for (int i = 0; i < byteArray.length; i++) { int temp = byteArray[i] & 0xFF; hexChars[i * 2] = hexArray[temp >>> 4]; hexChars[i * 2 + 1] = hexArray[temp & 0x0F]; } return new String(hexChars); } /** * Str转16进制Str * * @param str * @return */ public static String StrToHexStr(String str) { //根据默认编码获取字节数组 byte[] bytes = str.getBytes(); StringBuilder stringBuilder = new StringBuilder(bytes.length * 2); //将字节数组中每个字节拆解成2位16进制整数 for (int i = 0; i < bytes.length; i++) { stringBuilder.append("0x"); stringBuilder.append(HEXSTRING.charAt((bytes[i] & 0xf0) >> 4)); stringBuilder.append(HEXSTRING.charAt((bytes[i] & 0x0f) >> 0)); //去掉末尾的逗号 if (i != bytes.length - 1) { stringBuilder.append(","); } } return stringBuilder.toString(); } /** * 16进制Str转byte[] * * @param hexStr 不带空格、不带0x、不带逗号的16进制Str,如:06EEF7F1 * @return */ public static byte[] HexStrToByteArray(String hexStr) { byte[] byteArray = new byte[hexStr.length() / 2]; for (int i = 0; i < byteArray.length; i++) { String subStr = hexStr.substring(2 * i, 2 * i + 2); byteArray[i] = ((byte) Integer.parseInt(subStr, 16)); } return byteArray; } }

开启服务端

复制代码
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
import java.net.ServerSocket; import java.net.Socket; public class MySocketServer { public static void main(String[] args) { try { System.out.println(">>>服务启动,等待终端的连接n"); ServerSocket server = new ServerSocket(8888); int count = 0; while (true) { //开启监听 Socket socket = server.accept(); count++; System.out.println(">>>开启第" + count + "次长连接..."); ServerThread thread = new ServerThread(socket); thread.start(); } } catch (Exception e) { e.printStackTrace(); } } }

最后

以上就是灵巧发箍最近收集整理的关于Java的Socket实现长连接以及数据的发送和接收的全部内容,更多相关Java内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部