2016-09-09 6 views
1

누군가가 okhttp3 okhttp-ws 라이브러리를 사용하여 특정 Authorization 헤더가있는 wss : // 주소에 연결하는 방법을 보여줄 수 있습니까?간단한 okhttp3 websocket 연결을 만드는 방법은 무엇입니까?

나는 WS 서버와 인증 문자열 토큰의 URL을 가지고있다.

나중에 해당 연결에 대한 요청을 보내고 WS 서버에서 곧 나오는 데이터를 수신하고 연결이 끊어지지 않아야합니다. 나는

답변

4

그래서 일반적으로이 샘플은 (너무 okhttp3으로) 항상에만 REST와 협력, WS 세계 나에게이 새로운있는 어려움이 당신이

https://github.com/square/okhttp/blob/d854e6d5ad93da4da9b5d5818ee752477e501b18/samples/guide/src/main/java/okhttp3/recipes/WebSocketEcho.java

을 필요한 대부분의하지만 당신은해야합니다 대신 URL에서 WS의 두 가지 변화

  1. 사용 WSS
  2. 전화 request.addHeader이 토큰

    ,536을 추가 할 수

    request.addHeader ("인증", "무기명"+ 토큰)

+0

은 여기으로 onOpen 방법을 볼 수 있지만, 그것은 기본적으로 호출되지 않습니다. 코드로 연결을 실제로 열려면 어떻게합니까? –

+1

실행 방법의 대기열에 의해 간접적으로 호출되었습니다. –

+1

예, 작동 중입니다. 어리석은 질문으로 인해 미안합니다. 연결을 열었습니다. –

1

나는이 오래된 질문 알아요,하지만 난에 웹 소켓을 사용하려고 okhttp3 때 원하는 선택의 여지가 그리고 그것은 도서관에 없었습니다. 그래서 추가 기능으로 WS 연결을 처리하는 클래스를 만듭니다. 나는 그것이 어떤 몸을 도울 것이라는 점을 희망한다. Gist link

import android.os.Handler; 
import android.os.Looper; 
import android.support.annotation.NonNull; 
import android.util.Log; 

import org.json.JSONException; 
import org.json.JSONObject; 

import java.net.ProtocolException; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.concurrent.TimeUnit; 

import okhttp3.OkHttpClient; 
import okhttp3.Request; 
import okhttp3.Response; 
import okhttp3.WebSocket; 
import okhttp3.WebSocketListener; 
import okhttp3.internal.ws.RealWebSocket; 
import okhttp3.logging.HttpLoggingInterceptor; 
import okio.ByteString; 

/** 
* Websocket class based on OkHttp3 with {event->data} message format to make your life easier. 
* 
* @author Ali Yusuf 
* @since 3/13/17 
*/ 

public class Socket { 

    private final static String TAG = Socket.class.getSimpleName(); 
    private final static String CLOSE_REASON = "End of session"; 
    private final static int MAX_COLLISION = 7; 

    public final static String EVENT_OPEN = "open"; 
    public final static String EVENT_RECONNECT_ATTEMPT = "reconnecting"; 
    public final static String EVENT_CLOSED = "closed"; 

    /** 
    * Main socket states 
    */ 
    public enum State { 
     CLOSED, CLOSING, CONNECT_ERROR, RECONNECT_ATTEMPT, RECONNECTING, OPENING, OPEN 
    } 

    private static HttpLoggingInterceptor logging = 
      new HttpLoggingInterceptor() 
        .setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.HEADERS : HttpLoggingInterceptor.Level.NONE); 

    private static OkHttpClient.Builder httpClient = 
      new OkHttpClient.Builder() 
        .addInterceptor(logging); 

    public static class Builder { 

     private Request.Builder request; 

     private Builder(Request.Builder request) { 
      this.request = request; 
     } 

     public static Builder with(@NonNull String url) { 
      // Silently replace web socket URLs with HTTP URLs. 
      if (!url.regionMatches(true, 0, "ws:", 0, 3) && !url.regionMatches(true, 0, "wss:", 0, 4)) 
       throw new IllegalArgumentException("web socket url must start with ws or wss, passed url is " + url); 

      return new Builder(new Request.Builder().url(url)); 
     } 

     public Builder setPingInterval(long interval, @NonNull TimeUnit unit){ 
      httpClient.pingInterval(interval, unit); 
      return this; 
     } 

     public Builder addHeader(@NonNull String name, @NonNull String value) { 
      request.addHeader(name, value); 
      return this; 
     } 

     public Socket build() { 
      return new Socket(request.build()); 
     } 
    } 

    /** 
    * Websocket state 
    */ 
    private static State state; 
    /** 
    * Websocket main request 
    */ 
    private static Request request; 
    /** 
    * Websocket connection 
    */ 
    private static RealWebSocket realWebSocket; 
    /** 
    * Reconnection post delayed handler 
    */ 
    private static Handler delayedReconnection; 
    /** 
    * Websocket events listeners 
    */ 
    private static Map<String,OnEventListener> eventListener; 
    /** 
    * Websocket events new message listeners 
    */ 
    private static Map<String,OnEventResponseListener> eventResponseListener; 
    /** 
    * Message list tobe send onEvent open {@link State#OPEN} connection state 
    */ 
    private static Map<String,String> onOpenMessageQueue = new HashMap<>(); 
    /** 
    * Websocket state change listener 
    */ 
    private static OnStateChangeListener onChangeStateListener; 
    /** 
    * Websocket new message listener 
    */ 
    private static OnMessageListener messageListener; 
    /** 
    * Number of reconnection attempts 
    */ 
    private static int reconnectionAttempts; 
    private static boolean skipOnFailure; 

    private Socket(Request request) { 
     Socket.request = request; 
     state = State.CLOSED; 
     eventListener = new HashMap<>(); 
     eventResponseListener = new HashMap<>(); 
     delayedReconnection = new Handler(Looper.getMainLooper()); 
     skipOnFailure = false; 
    } 

    /** 
    * Start socket connection if i's not already started 
    */ 
    public Socket connect() { 
     if (httpClient == null) { 
      throw new IllegalStateException("Make sure to use Socket.Builder before using Socket#connect."); 
     } 
     if (realWebSocket == null) { 
      realWebSocket = (RealWebSocket) httpClient.build().newWebSocket(request, webSocketListener); 
      changeState(State.OPENING); 
     } else if (state == State.CLOSED) { 
      realWebSocket.connect(httpClient.build()); 
      changeState(State.OPENING); 
     } 
     return this; 
    } 

    /** 
    * Set listener which fired every time message received with contained data. 
    * 
    * @param listener message on arrive listener 
    */ 
    public Socket onEvent(@NonNull String event, @NonNull OnEventListener listener){ 
     eventListener.put(event,listener); 
     return this; 
    } 

    /** 
    * Set listener which fired every time message received with contained data. 
    * 
    * @param listener message on arrive listener 
    */ 
    public Socket onEventResponse(@NonNull String event, @NonNull OnEventResponseListener listener){ 
     eventResponseListener.put(event,listener); 
     return this; 
    } 

    /** 
    * Send message in {event->data} format 
    * 
    * @param event event name that you want sent message to 
    * @param data message data in JSON format 
    * @return true if the message send/on socket send quest; false otherwise 
    */ 
    public boolean send(@NonNull String event, @NonNull String data){ 
     try { 
      JSONObject text = new JSONObject(); 
      text.put("event", event); 
      text.put("data", new JSONObject(data)); 
      Log.v(TAG,"Try to send data "+text.toString()); 
      return realWebSocket.send(text.toString()); 
     } catch (JSONException e) { 
      Log.e(TAG,"Try to send data with wrong JSON format, data: "+data); 
     } 
     return false; 
    } 

    /** 
    * Set state listener which fired every time {@link Socket#state} changed. 
    * 
    * @param listener state change listener 
    */ 
    public Socket setOnChangeStateListener(@NonNull OnStateChangeListener listener) { 
     onChangeStateListener = listener; 
     return this; 
    } 

    /** 
    * Message listener will be called in any message received even if it's not 
    * in a {event -> data} format. 
    * 
    * @param listener message listener 
    */ 
    public Socket setMessageListener(@NonNull OnMessageListener listener) { 
     messageListener = listener; 
     return this; 
    } 

    public void removeEventListener(@NonNull String event) { 
     eventListener.remove(event); 
     onOpenMessageQueue.remove(event); 
    } 

    /** 
    * Clear all socket listeners in one line 
    */ 
    public void clearListeners() { 
     eventListener.clear(); 
     messageListener = null; 
     onChangeStateListener = null; 
    } 

    /** 
    * Send normal close request to the host 
    */ 
    public void close() { 
     if (realWebSocket != null) { 
      realWebSocket.close(1000, CLOSE_REASON); 
     } 
    } 

    /** 
    * Send close request to the host 
    */ 
    public void close(int code, @NonNull String reason) { 
     if (realWebSocket != null) { 
      realWebSocket.close(code, reason); 
     } 
    } 

    /** 
    * Terminate the socket connection permanently 
    */ 
    public void terminate() { 
     skipOnFailure = true; // skip onFailure callback 
     if (realWebSocket != null) { 
      realWebSocket.cancel(); // close connection 
      realWebSocket = null; // clear socket object 
     } 
    } 

    /** 
    * Add message in a queue if the socket not open and send them 
    * if the socket opened 
    * 
    * @param event event name that you want sent message to 
    * @param data message data in JSON format 
    */ 
    public void sendOnOpen(@NonNull String event, @NonNull String data) { 
     if (state != State.OPEN) 
      onOpenMessageQueue.put(event,data); 
     else 
      send(event,data); 
    } 

    /** 
    * Retrieve current socket connection state {@link State} 
    */ 
    public State getState() { 
     return state; 
    } 

    /** 
    * Change current state and call listener method with new state 
    * {@link OnStateChangeListener#onChange(Socket, State)} 
    * @param newState new state 
    */ 
    private void changeState(State newState) { 
     state = newState; 
     if (onChangeStateListener != null) { 
      onChangeStateListener.onChange(Socket.this, state); 
     } 
    } 

    /** 
    * Try to reconnect to the websocket after delay time using <i>Exponential backoff</i> method. 
    * @see <a href="https://en.wikipedia.org/wiki/Exponential_backoff"></a> 
    */ 
    private void reconnect() { 
     if (state != State.CONNECT_ERROR) // connection not closed !! 
      return; 

     changeState(State.RECONNECT_ATTEMPT); 

     if (realWebSocket != null) { 
      // Cancel websocket connection 
      realWebSocket.cancel(); 
      // Clear websocket object 
      realWebSocket = null; 
     } 

     if (eventListener.get(EVENT_RECONNECT_ATTEMPT) != null) { 
      eventListener.get(EVENT_RECONNECT_ATTEMPT).onMessage(Socket.this, EVENT_RECONNECT_ATTEMPT); 
     } 

     // Calculate delay time 
     int collision = reconnectionAttempts > MAX_COLLISION ? MAX_COLLISION : reconnectionAttempts; 
     long delayTime = Math.round((Math.pow(2, collision)-1)/2) * 1000; 

     // Remove any pending posts of callbacks 
     delayedReconnection.removeCallbacksAndMessages(null); 
     // Start new post delay 
     delayedReconnection.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       changeState(State.RECONNECTING); 
       reconnectionAttempts++; // Increment connections attempts 
       connect(); // Establish new connection 
      } 
     }, delayTime); 
    } 

    private WebSocketListener webSocketListener = new WebSocketListener() { 
     @Override 
     public void onOpen(WebSocket webSocket, Response response) { 
      Log.v(TAG,"Socket has been opened successfully."); 
      // reset connections attempts counter 
      reconnectionAttempts = 0; 

      // fire open event listener 
      if (eventListener.get(EVENT_OPEN) != null) { 
       eventListener.get(EVENT_OPEN).onMessage(Socket.this, EVENT_OPEN); 
      } 

      // Send data in queue 
      for (String event : onOpenMessageQueue.keySet()) { 
       send(event, onOpenMessageQueue.get(event)); 
      } 
      // clear queue 
      onOpenMessageQueue.clear(); 

      changeState(State.OPEN); 
     } 

     /** 
     * Accept only Json data with format: 
     * <b> {"event":"event name","data":{some data ...}} </b> 
     */ 
     @Override 
     public void onMessage(WebSocket webSocket, String text) { 
      // print received message in log 
      Log.v(TAG, "New Message received "+text); 

      // call message listener 
      if (messageListener != null) 
       messageListener.onMessage(Socket.this, text); 

      try { 
       // Parse message text 
       JSONObject response = new JSONObject(text); 
       String event = response.getString("event"); 
       JSONObject data = response.getJSONObject("data"); 

       // call event listener with received data 
       if (eventResponseListener.get(event) != null) { 
        eventResponseListener.get(event).onMessage(Socket.this, event, data); 
       } 
       // call event listener 
       if (eventListener.get(event) != null) { 
        eventListener.get(event).onMessage(Socket.this, event); 
       } 
      } catch (JSONException e) { 
       // Message text not in JSON format or don't have {event}|{data} object 
       Log.e(TAG, "Unknown message format."); 
      } 
     } 

     @Override 
     public void onMessage(WebSocket webSocket, ByteString bytes) { 
      // TODO: some action 
     } 

     @Override 
     public void onClosing(WebSocket webSocket, int code, String reason) { 
      Log.v(TAG,"Close request from server with reason '"+reason+"'"); 
      changeState(State.CLOSING); 
      webSocket.close(1000,reason); 
     } 

     @Override 
     public void onClosed(WebSocket webSocket, int code, String reason) { 
      Log.v(TAG,"Socket connection closed with reason '"+reason+"'"); 
      changeState(State.CLOSED); 
      if (eventListener.get(EVENT_CLOSED) != null) { 
       eventListener.get(EVENT_CLOSED).onMessage(Socket.this, EVENT_CLOSED); 
      } 
     } 

     /** 
     * This method call if: 
     * - Fail to verify websocket GET request => Throwable {@link ProtocolException} 
     * - Can't establish websocket connection after upgrade GET request => response null, Throwable {@link Exception} 
     * - First GET request had been failed => response null, Throwable {@link java.io.IOException} 
     * - Fail to send Ping => response null, Throwable {@link java.io.IOException} 
     * - Fail to send data frame => response null, Throwable {@link java.io.IOException} 
     * - Fail to read data frame => response null, Throwable {@link java.io.IOException} 
     */ 
     @Override 
     public void onFailure(WebSocket webSocket, Throwable t, Response response) { 
      if (!skipOnFailure) { 
       skipOnFailure = false; // reset flag 
       Log.v(TAG, "Socket connection fail, try to reconnect. (" + reconnectionAttempts + ")"); 
       changeState(State.CONNECT_ERROR); 
       reconnect(); 
      } 
     } 
    }; 

    public abstract static class OnMessageListener { 
     public abstract void onMessage (String data); 

     /** 
     * Method called from socket to execute listener implemented in 
     * {@link #onMessage(String)} on main thread 
     * 
     * @param socket Socket that receive the message 
     * @param data Data string received 
     */ 
     private void onMessage (Socket socket, final String data) { 
      new Handler(Looper.getMainLooper()).post(new Runnable() { 
       @Override 
       public void run() { 
        onMessage(data); 
       } 
      }); 
     } 
    } 

    public abstract static class OnEventListener { 
     public abstract void onMessage (String event); 

     private void onMessage (Socket socket, final String event) { 
      new Handler(Looper.getMainLooper()).post(new Runnable() { 
       @Override 
       public void run() { 
        onMessage(event); 
       } 
      }); 
     } 
    } 

    public abstract static class OnEventResponseListener extends OnEventListener { 
     /** 
     * Method need to override in listener usage 
     */ 
     public abstract void onMessage (String event, String data); 

     /** 
     * Just override the inherited method 
     */ 
     @Override 
     public void onMessage(String event) {} 

     /** 
     * Method called from socket to execute listener implemented in 
     * {@link #onMessage(String, String)} on main thread 
     * 
     * @param socket Socket that receive the message 
     * @param event Message received event 
     * @param data Data received in the message 
     */ 
     private void onMessage (Socket socket, final String event, final JSONObject data) { 
      new Handler(Looper.getMainLooper()).post(new Runnable() { 
       @Override 
       public void run() { 
        onMessage(event, data.toString()); 
        onMessage(event); 
       } 
      }); 
     } 
    } 

    public abstract static class OnStateChangeListener { 
     /** 
     * Method need to override in listener usage 
     */ 
     public abstract void onChange (State status); 

     /** 
     * Method called from socket to execute listener implemented in 
     * {@link #onChange(State)} on main thread 
     * 
     * @param socket Socket that receive the message 
     * @param status new status 
     */ 
     private void onChange (Socket socket, final State status){ 
      new Handler(Looper.getMainLooper()).post(new Runnable() { 
       @Override 
       public void run() { 
        onChange(status); 
       } 
      }); 
     } 
    } 

} 

사용 예 :

Socket socket = Socket.Builder.with(WEBSOCKET_BASE_URL).build().connect(); 
socket.onEvent(Socket.EVENT_OPEN, socketOpenListener); 
socket.onEvent(Socket.EVENT_RECONNECT_ATTEMPT, .....); 
socket.onEvent(Socket.EVENT_CLOSED, .....); 
socket.onEventResponse("Some event", socketPairListener); 
socket.send("Some event", "{"some data":"in JSON format"}"); 
socket.sendOnOpen("Some event", "{"some data":"in JSON format"}"); 
관련 문제