the number t to cache
7 | * @param the param to create T, can be null if not need.
8 | * @Note if the T is not big. you may not need to cache it
9 | */
10 | public abstract class Cacher implements ICacher{
11 |
12 | private static final int DEFAULT_MAX_POOL_SIZE = 10;
13 |
14 | private Node node;
15 | private int mCurrentPoolSize;
16 | private final int mMaxPoolSize;
17 |
18 | public Cacher(int maxPoolSize) {
19 | this.node = new Node();
20 | this.mMaxPoolSize = maxPoolSize;
21 | }
22 | public Cacher(){
23 | this(DEFAULT_MAX_POOL_SIZE);
24 | }
25 |
26 | public int getMaxPoolSize() {
27 | return mMaxPoolSize;
28 | }
29 |
30 | public int getCurrentPoolSize(){
31 | return mCurrentPoolSize;
32 | }
33 | /** equal to prepare(null)*/
34 | public void prepare(){
35 | prepare(null);
36 | }
37 | @Override
38 | public void prepare(P p) {
39 | synchronized (this) {
40 | Node n = this.node ;
41 | int current = this.mCurrentPoolSize ;
42 | final int max = this.mMaxPoolSize ;
43 |
44 | while(current < max){
45 | if(n.t == null){
46 | n.t = create(p);
47 | }else{
48 | Node n1 = new Node();
49 | n1.next = n;
50 | n1.t = create(p);
51 | n = n1; //new node is the front
52 | }
53 | current++ ;
54 | }
55 | this.node = n;
56 | this.mCurrentPoolSize = current;
57 | }
58 | }
59 |
60 | /*** equals to obtain(null) */
61 | public T obtain(){
62 | return obtain(null);
63 | }
64 |
65 | @Override
66 | public T obtain(P p) {
67 | synchronized (this) {
68 | if(node.t!=null){
69 | Node tmp = this.node;
70 | T t = tmp.t;
71 | node = tmp.next;
72 | tmp.next = null;
73 | mCurrentPoolSize --;
74 | return t;
75 | }
76 | }
77 | return create(p);
78 | }
79 |
80 | public void recycle(T t){
81 | synchronized (this) {
82 | if (mCurrentPoolSize < mMaxPoolSize) {
83 | Node nodeNew = new Node();
84 | nodeNew.next = node ;
85 | nodeNew.t = t;
86 | this.node = nodeNew;
87 | mCurrentPoolSize ++ ;
88 | onRecycleSuccess(t);
89 | }
90 | }
91 | }
92 | public void clear(){
93 | synchronized (this) {
94 | Node node = this.node;
95 | while( node != null ){
96 | node.t = null;
97 | node = node.next;
98 | }
99 | this.node = new Node();
100 | mCurrentPoolSize = 0;
101 | }
102 | }
103 |
104 | /** when {@link #recycle(Object)} success ,this will be called */
105 | protected void onRecycleSuccess(T t){ };
106 |
107 | @SuppressWarnings("hiding")
108 | public class Node{
109 | T t;
110 | Node next;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/medlinker/socketclient/core/util/DefaultRetryPolicy.java:
--------------------------------------------------------------------------------
1 | package com.medlinker.socketclient.core.util;
2 |
3 | /**
4 | * 默认重试5次。
5 | * Created by jiantao on 2017/3/8.
6 | */
7 |
8 | public class DefaultRetryPolicy implements RetryPolicy {
9 |
10 | /**
11 | * The current retry count.
12 | */
13 | private int mCurrentRetryCount;
14 |
15 | /**
16 | * The maximum number of attempts.
17 | */
18 | private final int mMaxNumRetries;
19 |
20 | /**
21 | * The default number of retries
22 | */
23 | public static final int DEFAULT_MAX_RETRIES = 5;
24 |
25 |
26 | /**
27 | * Constructs a new retry policy using the default timeouts.
28 | */
29 | public DefaultRetryPolicy() {
30 | this(DEFAULT_MAX_RETRIES);
31 | }
32 |
33 | /**
34 | * Constructs a new retry policy.
35 | *
36 | * @param maxNumRetries The maximum number of retries.
37 | */
38 | public DefaultRetryPolicy( int maxNumRetries) {
39 | mMaxNumRetries = maxNumRetries;
40 | }
41 | @Override
42 | public int getCurrentRetryCount() {
43 | return mCurrentRetryCount;
44 | }
45 |
46 | @Override
47 | public void retry(Exception ex) throws Exception {
48 | mCurrentRetryCount++;
49 | if (!hasAttemptRemaining()) {
50 | throw ex;
51 | }
52 | }
53 |
54 | /**
55 | * 重置当前重试次数
56 | */
57 | @Override
58 | public void reset(){
59 | this.mCurrentRetryCount = 0;
60 | }
61 | /**
62 | * Returns true if this policy has attempts remaining, false otherwise.
63 | */
64 | protected boolean hasAttemptRemaining() {
65 | return mCurrentRetryCount <= mMaxNumRetries;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/medlinker/socketclient/core/util/ICacher.java:
--------------------------------------------------------------------------------
1 | package com.medlinker.socketclient.core.util;
2 |
3 | public interface ICacher {
4 |
5 | /** prepare for a number of T if you need*/
6 | void prepare(P p);
7 |
8 | /**obtain T from cache . if not exist , create(p) will be called*/
9 | T obtain(P p);
10 |
11 | /** clear the cache*/
12 | void clear();
13 |
14 | /**@hide when cacher havn't , create by this mMethod */
15 | T create(P p);
16 |
17 | /** recycle it */
18 | void recycle(T t);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/medlinker/socketclient/core/util/ImExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.medlinker.socketclient.core.util;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import com.qpdstudio.logger.util.LogUtil;
7 |
8 |
9 | import java.io.File;
10 | import java.io.FileOutputStream;
11 | import java.io.PrintWriter;
12 | import java.io.StringWriter;
13 | import java.io.Writer;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 | import java.util.Locale;
17 | import java.util.Properties;
18 |
19 | import com.medlinker.socketclient.core.ImServiceHelper;
20 |
21 | public class ImExceptionHandler implements Thread.UncaughtExceptionHandler {
22 | private static final String TAG = ImExceptionHandler.class.getSimpleName();
23 | /** 系统默认的UncaughtException处理类 */
24 | // private Thread.UncaughtExceptionHandler mDefaultHandler;
25 | /** ExceptionHandler实例 */
26 | private static ImExceptionHandler mInstance;
27 | /** 程序的Context对象 */
28 | private Context mContext;
29 |
30 | // 使用Properties来保存设备的信息和错误堆栈信息
31 | private Properties mCrashProperties = new Properties();
32 | private static final String VERSION_NAME = "version_name";
33 | private static final String VERSION_CODE = "version_code";
34 | private static final String STACK_TRACE = "stack_trace";
35 | /** 错误报告文件的扩展名 */
36 | private static final String CRASH_REPORTER_EXTENSION = ".cr";
37 |
38 | private ImExceptionHandler() {
39 | }
40 |
41 | public static synchronized ImExceptionHandler getInstance() {
42 | if (mInstance == null) {
43 | mInstance = new ImExceptionHandler();
44 | }
45 | return mInstance;
46 | }
47 |
48 | /**
49 | * 初始化,获取系统默认的异常处理器,设置ExceptionHandler为程序的默认处理器
50 | * @param context 应用上下文
51 | */
52 | public void initialize(Context context) {
53 | mContext = context.getApplicationContext();
54 | // mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
55 | Thread.setDefaultUncaughtExceptionHandler(this);
56 | }
57 |
58 | @Override
59 | public void uncaughtException(Thread thread, Throwable ex) {
60 | // crash统计打点
61 | if (ex != null) {
62 | ex.printStackTrace();
63 | // 保存错误报告文件
64 | saveCrashInfoToFile(ex);
65 | }
66 | try {
67 | Thread.sleep(1000);
68 | } catch (InterruptedException e) {
69 | e.printStackTrace();
70 | }
71 | LogUtil.i(TAG, "uncaughtException crash recovering");
72 | ImServiceHelper.getInstance(mContext).reConnect();
73 | }
74 |
75 | /**
76 | * 保存错误信息到文件中
77 | * @param ex 异常信息
78 | * @return 异常收集文件名称
79 | */
80 | private String saveCrashInfoToFile(Throwable ex) {
81 | Writer info = new StringWriter();
82 | PrintWriter printWriter = new PrintWriter(info);
83 | ex.printStackTrace(printWriter);
84 |
85 | Throwable cause = ex.getCause();
86 | while (cause != null) {
87 | cause.printStackTrace(printWriter);
88 | cause = cause.getCause();
89 | }
90 | String result = info.toString();
91 | printWriter.close();
92 | mCrashProperties.put(STACK_TRACE, result);
93 | try {
94 | long timestamp = System.currentTimeMillis();
95 | final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd___HH:mm:ss", Locale.CHINA);
96 | String fileName = "crash-" + FORMAT.format(new Date(timestamp)) + CRASH_REPORTER_EXTENSION;
97 | File cacheFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath().concat(File.separator).concat("medlinker/log/".concat(fileName)));
98 | FileOutputStream trace = new FileOutputStream(cacheFile);
99 | mCrashProperties.store(trace, "trace");
100 | trace.flush();
101 | trace.close();
102 | LogUtil.i(TAG, "crash log write success filepath = %s", cacheFile.getAbsolutePath());
103 | return fileName;
104 | } catch (Exception e) {
105 | e.printStackTrace();
106 | }
107 | return null;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/medlinker/socketclient/core/util/RetryPolicy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.medlinker.socketclient.core.util;
18 |
19 | /**
20 | * Retry policy for a request.
21 | * Created by jiantao on 2017/3/8.
22 | */
23 | public interface RetryPolicy {
24 |
25 | /**
26 | * Returns the current retry count .
27 | */
28 | public int getCurrentRetryCount();
29 |
30 | /**
31 | * Prepares for the next retry.
32 | * @param ex
33 | * @throws Exception
34 | */
35 | public void retry(Exception ex) throws Exception;
36 |
37 | /**
38 | * reset current retry count
39 | */
40 | public void reset();
41 | }
42 |
--------------------------------------------------------------------------------
/socketclient/src/main/java/com/medlinker/socketclient/core/util/RunnablePool.java:
--------------------------------------------------------------------------------
1 | package com.medlinker.socketclient.core.util;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 | import android.support.v4.app.Fragment;
6 |
7 | import com.qpdstudio.logger.Logger;
8 |
9 |
10 | import java.lang.ref.WeakReference;
11 |
12 | /**
13 | * the runnable pool help get a runnable from the pool.
14 | * Created by heaven7 on 2016/6/7.
15 | */
16 | public final class RunnablePool {
17 | private RunnablePool() {}
18 | private static Cacher sCacher;
19 |
20 | /** init the cacher ,this only can init once
21 | * @param maxPoolSize the max pool size */
22 | public static void initCacher(int maxPoolSize){
23 | if(sCacher!=null)
24 | return ;
25 | sCacher = new Cacher(maxPoolSize) {
26 | @Override
27 | public Runner create(Void aa) {
28 | return new Runner(){
29 | @Override
30 | public void run() {
31 | super.run();
32 | recycle(this);
33 | }
34 | };
35 | }
36 | };
37 | }
38 |
39 | /**
40 | * obtain a Runner from the pool. and the pool size is the default.
41 | * @param executor the really runnable execute
42 | * @param what what message to execute
43 | * @param params the mParams to execute
44 | * @return the Runner from cacher.
45 | */
46 | public static Runner obtain(IRunnbleExecutor executor, int what,Object...params){
47 | if(sCacher == null){
48 | initCacher(10);
49 | }
50 | final Runner runner = sCacher.obtain();
51 | runner.setExecutor(executor);
52 | runner.setWhat(what);
53 | runner.setParams(params);
54 | return runner;
55 | }
56 |
57 | /**
58 | * this is the runnable class help we reuse the runnable object.so it's high efficiency .
59 | * and after the {@link Runner#run()} is called. the Runner will atonmic be recycled to the cacher.
60 | */
61 | public static class Runner implements Runnable{
62 |
63 | private Object[] mParams;
64 | private IRunnbleExecutor mExecutor;
65 | private int what;
66 | private WeakReference mWeakExecutor;
67 |
68 | public void setParams(Object[] mParams) {
69 | this.mParams = mParams;
70 | }
71 | public void setExecutor(IRunnbleExecutor mExecutor) {
72 | if(mExecutor instanceof Fragment || mExecutor instanceof android.app.Fragment
73 | || mExecutor instanceof Activity){
74 | this.mWeakExecutor = new WeakReference<>(mExecutor);
75 | }else {
76 | this.mExecutor = mExecutor;
77 | }
78 | }
79 | public int getWhat() {
80 | return what;
81 | }
82 | public void setWhat(int what) {
83 | this.what = what;
84 | }
85 |
86 | public Object[] getParams() {
87 | return mParams;
88 | }
89 | public IRunnbleExecutor getExecutor() {
90 | return mWeakExecutor!=null ? mWeakExecutor.get(): mExecutor;
91 | }
92 |
93 | @Override
94 | public void run() {
95 | final IRunnbleExecutor executor = getExecutor();
96 | if(executor == null){
97 | Logger.w("RunnablePool_Runner","run", "mExecutor == null or is recycled(Fragment or Activity)");
98 | return;
99 | }
100 |
101 | boolean shouldExecute = true;
102 | if(executor instanceof Activity){
103 | if(((Activity) executor).isFinishing()){
104 | Logger.i("RunnablePool_Runner","run", "executor is Activity and isFinishing() = true. ");
105 | shouldExecute = false;
106 | }
107 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && ((Activity) executor).isDestroyed()){
108 | Logger.i("RunnablePool_Runner","run", "executor is Activity and isDestroyed() = true. ");
109 | shouldExecute = false;
110 | }
111 | }else if(executor instanceof Fragment){
112 | if(((Fragment) executor).isDetached() || ((Fragment) executor).isRemoving()){
113 | // ((Fragment) executor).isVisible()
114 | Logger.i("RunnablePool_Runner","run", "executor is Fragment and isDestroyed() || isRemoving() = true. ");
115 | shouldExecute = false;
116 | }
117 | }else if(executor instanceof android.app.Fragment){
118 | if(((android.app.Fragment) executor).isDetached() || ((android.app.Fragment) executor).isRemoving()){
119 | // ((Fragment) executor).isVisible()
120 | Logger.i("RunnablePool_Runner","run", "executor is android.app.Fragment and isDestroyed() || isRemoving() = true. ");
121 | shouldExecute = false;
122 | }
123 | }
124 | if(shouldExecute) {
125 | executor.execute(getWhat(), getParams());
126 | }
127 | afterRun();
128 | }
129 |
130 | protected void afterRun() {
131 | this.mWeakExecutor = null;
132 | this.mExecutor = null;
133 | this.mParams = null;
134 | }
135 | }
136 |
137 | /**
138 | * this is the runnable mExecutor
139 | */
140 | public interface IRunnbleExecutor{
141 |
142 | /**
143 | * execute the command impl
144 | */
145 | void execute(int what, Object... params);
146 |
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/socketclient/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SocketClient
3 |
4 |
--------------------------------------------------------------------------------
/socketclient/src/test/java/com/medlinker/socketclient/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.medlinker.socketclient;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/socketlib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/socketlib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 |
3 | dependencies {
4 | implementation fileTree(dir: 'libs', include: ['*.jar'])
5 | }
6 |
7 | sourceCompatibility = "1.7"
8 | targetCompatibility = "1.7"
9 |
--------------------------------------------------------------------------------
/socketlib/src/main/java/com/jiantao/socketlib/MyClass.java:
--------------------------------------------------------------------------------
1 | package com.jiantao.socketlib;
2 |
3 | public class MyClass {
4 | }
5 |
--------------------------------------------------------------------------------
/socketlib/src/main/java/com/jiantao/socketlib/client/SocketHelper.java:
--------------------------------------------------------------------------------
1 | package com.jiantao.socketlib.client;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.DataInputStream;
5 | import java.io.DataOutputStream;
6 | import java.io.IOException;
7 | import java.net.InetSocketAddress;
8 | import java.net.Socket;
9 | import java.net.SocketTimeoutException;
10 | import java.util.concurrent.Executor;
11 | import java.util.concurrent.Executors;
12 |
13 | /** @author Created by jiantaoyang on 2018/11/30. */
14 | public class SocketHelper {
15 |
16 | public static void main(String[] args) {
17 | SocketHelper helper = new SocketHelper();
18 | String host = "127.0.0.1";
19 | int port = 59724;
20 | helper.connectServer(host, port);
21 | }
22 |
23 | private static final String TAG = "SocketHelper";
24 | DataInputStream dataIS;
25 | DataOutputStream dataOS;
26 | BufferedOutputStream bufferedOutputStream;
27 |
28 | Executor executor;
29 | Socket mSocket;
30 |
31 | public SocketHelper() {
32 | executor = Executors.newFixedThreadPool(2);
33 | }
34 |
35 | public void connectServer(String host, int port) {
36 | try {
37 | mSocket = new Socket();
38 | mSocket.setKeepAlive(true);
39 | mSocket.setSoTimeout(2 * 3 * 60 * 1000);
40 | mSocket.setTcpNoDelay(true);
41 | mSocket.connect(new InetSocketAddress(host, port));
42 | if (mSocket.isConnected()) {
43 | dataIS = new DataInputStream(mSocket.getInputStream());
44 | dataOS = new DataOutputStream(mSocket.getOutputStream());
45 | bufferedOutputStream = new BufferedOutputStream(mSocket.getOutputStream());
46 |
47 | executor.execute(
48 | new Runnable() {
49 | @Override
50 | public void run() {
51 | // listening
52 | receiveData();
53 | }
54 | });
55 | // send a msg
56 | sendData();
57 | //sendDataWithDataOutputStream();
58 | }
59 | } catch (IOException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | public void close() {
65 | if (mSocket != null) {
66 | try {
67 | mSocket.close();
68 | } catch (IOException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | }
73 |
74 | private String msgStr =
75 | "djalkgjdaoiugaodkgakljdklajgdkljlJglkdjglLgjdal国家大力就搞定了金刚狼的韩国辣酱过来打几个打开了国际爱劳动工具阿卡丽伽伽个"
76 | + "都快放假埃里克的结果拉卡宫颈癌UI噢哟打暑假工康迪克了解阿里的结果拉gj打开房间爱老公奇偶奥的国际噶断开逻辑奥克兰的价格jdlagjalkdgjioudioajgkldjgilahgialjlg;djoiauyeojad"
77 | + "adgjkladgjiaougkjlgdilaujgaljmgiouyaopjgkladjgialyhgialjga"
78 | + "asdjklgjkalgjoiajgnajkghasdkgj"
79 | + "dlakjfoiaduajglkajpoj结构胶价格拉激怒我高压我偶尔鸡鸣狗盗卡了几个我欧元区破健康管理对面那看来韩国卡拉多几个垃圾狗jd.com";
80 |
81 | private void sendData() {
82 | try {
83 | long millis = System.currentTimeMillis();
84 | // 1s中发送多少条数据
85 | long count = 0;
86 | while (System.currentTimeMillis() < millis + 2000) {
87 | String data = msgStr.concat("millis").concat(String.valueOf(millis));
88 | byte[] bytes = data.getBytes();
89 | byte type = 1;
90 | int prefixLen = 3;
91 | int msgDataLen = bytes.length;
92 | byte[] msg = new byte[msgDataLen + prefixLen];
93 | // 消息类型
94 | msg[0] = type;
95 | msg[1] = (byte) ((msgDataLen >>> 8) & 0xFF);
96 | msg[2] = (byte) ((msgDataLen >>> 0) & 0xFF);
97 | System.arraycopy(bytes, 0, msg, prefixLen, msgDataLen);
98 | bufferedOutputStream.write(msg);
99 | count++;
100 | System.out.println(
101 | "send to server , new !!! msg.length = " + msg.length + "; count " + count);
102 | }
103 | } catch (final IOException e) {
104 | e.printStackTrace();
105 | }
106 | }
107 |
108 | private void sendDataWithDataOutputStream() {
109 | try {
110 | long millis = System.currentTimeMillis();
111 | // 1s中发送多少条数据
112 | long count = 0;
113 | while (System.currentTimeMillis() < millis + 2000) {
114 | String data = msgStr.concat("millis").concat(String.valueOf(millis));
115 | byte[] bytes = data.getBytes();
116 | byte type = 1;
117 | dataOS.writeByte(type);
118 | dataOS.writeChar(bytes.length);
119 | dataOS.write(bytes);
120 | dataOS.flush();
121 | count++;
122 | System.out.println(
123 | "send to server , DataOutputStream !!! msg.length = " + bytes.length + "; count " + count);
124 | }
125 | } catch (final IOException e) {
126 | e.printStackTrace();
127 | }
128 | }
129 |
130 | private void receiveData() {
131 | while (true) {
132 | try {
133 | // test 单条数据不超多4096字节
134 | // byte[] buffer = new byte[4096];
135 | int type = dataIS.readByte(); // 读取1位
136 | int length = dataIS.readChar(); // 读取2位标记第三段数据长度
137 | byte[] data = new byte[length];
138 | dataIS.readFully(data);
139 | System.out.println(
140 | " receiveData connected receiveData type = "
141 | + type
142 | + "; data = "
143 | + new String(data));
144 | } catch (SocketTimeoutException e) {
145 | e.printStackTrace();
146 | break;
147 | } catch (IOException e) {
148 | System.out.println(" receiveData IOException = " + e.getMessage());
149 | e.printStackTrace();
150 | break;
151 | }
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/socketlib/src/main/java/com/jiantao/socketlib/server/ServerSocketHelper.java:
--------------------------------------------------------------------------------
1 | package com.jiantao.socketlib.server;
2 |
3 | import java.io.IOException;
4 | import java.net.InetAddress;
5 | import java.net.ServerSocket;
6 | import java.net.Socket;
7 |
8 | public class ServerSocketHelper {
9 |
10 | public static void main(String[] args) {
11 | startServive("192.168.137.55");
12 | }
13 |
14 | static SocketHandler socketHandler;
15 | public static void startServive(String hostName) {
16 | ServerSocket serverSocket = null;
17 | try {
18 | InetAddress address = InetAddress.getByName(hostName);
19 | serverSocket = new ServerSocket(0, 10, address);
20 | // String hostAddress = address.getHostName();
21 | int port = serverSocket.getLocalPort();
22 | System.out.println("hostName = " + hostName + "; port = " + port);
23 | } catch (IOException e) {
24 | e.printStackTrace();
25 | serverSocket = null;
26 | }
27 | if (serverSocket == null) {
28 | System.out.println(" serverSocket init failed ");
29 | return;
30 | }
31 | while (true) {
32 | Socket socket = null;
33 | try {
34 | System.out.println(" serverSocket waiting accept ...");
35 | socket = serverSocket.accept();
36 | socketHandler = new SocketHandler(socket);
37 | Thread workThread = new Thread(socketHandler); //创建线程
38 | workThread.start(); //启动线程
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | break;
42 | }
43 | }
44 | }
45 |
46 | public static void closeLastHandler(){
47 | if (socketHandler != null) {
48 | socketHandler.close();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/socketlib/src/main/java/com/jiantao/socketlib/server/SocketHandler.java:
--------------------------------------------------------------------------------
1 | package com.jiantao.socketlib.server;
2 |
3 | import java.io.DataInputStream;
4 | import java.io.DataOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.net.Socket;
8 | import java.net.SocketTimeoutException;
9 | import java.nio.charset.Charset;
10 |
11 | class SocketHandler implements Runnable{
12 | private Socket socket;
13 | private DataOutputStream dataOutputStream;
14 | public SocketHandler(Socket socket){
15 | try {
16 | this.socket=socket;
17 | dataOutputStream = new DataOutputStream(socket.getOutputStream());
18 | } catch (IOException e) {
19 | e.printStackTrace();
20 | }
21 | }
22 |
23 | public void run(){
24 | try{
25 | System.out.println("新连接:"+socket.getInetAddress()+":"+socket.getPort());
26 | //Thread.sleep(5000);
27 | startHeartbeat();
28 | receiveMessage(socket.getInputStream());
29 |
30 | }catch(Exception e){e.printStackTrace();}finally{
31 | try{
32 | System.out.println("关闭连接:"+socket.getInetAddress()+":"+socket.getPort());
33 | if(socket!=null)socket.close();
34 | }catch(IOException e){
35 | e.printStackTrace();
36 | }
37 | }
38 | }
39 |
40 | private void startHeartbeat() {
41 | // 新开线程处理心跳
42 | new Thread(new Runnable() {
43 | @Override
44 | public void run() {
45 | while(isConnected()){
46 | try {
47 | Thread.sleep(5000);
48 | } catch (InterruptedException e) {
49 | e.printStackTrace();
50 | }
51 | byte[] heartbeat = " server 发动心跳包 ".getBytes();
52 | sendMessage(heartbeat);
53 | }
54 | }
55 | }).start();
56 | }
57 |
58 | private void sendMessage(byte[] bytes) {
59 | System.out.println("server >>> 发送到客服端消息: \" "+new String(bytes)+"\"");
60 | if(dataOutputStream != null){
61 | try {
62 | byte type = 1;
63 | dataOutputStream.writeByte(type);
64 | dataOutputStream.writeChar(bytes.length);
65 | dataOutputStream.write(bytes);
66 | dataOutputStream.flush();
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 |
72 | }
73 |
74 | private void receiveMessage(InputStream inputStream) {
75 | final DataInputStream dataInputStream = new DataInputStream(inputStream);
76 | while(isConnected()){
77 | // try {
78 | // Thread.sleep(1000);
79 | // } catch (InterruptedException e) {
80 | // e.printStackTrace();
81 | // }
82 | try {
83 | // 数据结构:第一位为数据类型,紧接着后两位为数据payload长度,后面为payload
84 | int type = dataInputStream.readByte();//读取1位
85 | int length = dataInputStream.readChar();//读取2位标记第三段数据长度
86 | byte[] data = new byte[length];
87 | dataInputStream.readFully(data);
88 | System.out.println("server <<< 收到客户端消息: \""+ new String(data, Charset.defaultCharset())+"\"");
89 |
90 | } catch (SocketTimeoutException e) {
91 | e.printStackTrace();
92 | break;
93 | } catch (IOException e) {
94 | e.printStackTrace();
95 | break;
96 | }
97 | }
98 | }
99 |
100 | private boolean isConnected() {
101 | return socket != null && socket.isConnected() && !socket.isClosed();
102 | }
103 |
104 | public void close(){
105 | if (socket != null) {
106 | try {
107 | socket.close();
108 | } catch (IOException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | }
113 | }
--------------------------------------------------------------------------------