2013-03-12 54 views
2

我想創建一個簡單的兩個協議客戶端和服務器的演示。但是,當我在網頁套接字的客戶端初始化指定兩個子協議我總是在服務器端此消息:多個子協議Websocket Javascript客戶端和Libwebsockets服務器不工作

[1363089953:1535] ERR: Req protocol SIGN_IN_OUT_REQUEST_PROTOCOL, GET_REQUEST_PROTOCOL not supported 

客戶端的JavaScript代碼:

var host = 'ws://10.0.96.32:9000'; 
var webSocket = {}; 
var websocketStatus = {}; 

$(function() { 

     function webSocketSupported() { 
      if(window.MozWebSocket) { 
       window.WebSocket = window.MozWebSocket; 
      } 
      return (window.webSocket != null); 
     } 

     if(!webSocketSupported) { 
      $(document).simpledialog2({ 
       mode: 'blank', 
       headerClose: true, 
       blankContent : 
         "<p>Websockets not supported by this browser. How about <a href='http://www.google.com/chrome'>Google Chrome</a>?</p>"+ 
         "<a rel='close' data-role='button' href='#'>Close</a>"   
      }); 
     } else { 

      $("#login_form").validate({ 
       rules:{ 
        username: {required: true, minlength: 2}, 
        password: {required: true, minlength: 4} 
       }, 
       messages:{ 
        username: {required: "Username is required", 
           minlength: "Username must be atleast 2 characters"}, 
        password: {required: "Password is required", 
           minlength: "Password must be atleast 4 characters"} 
       } 
      }); 

      /** Setting up WebSocket **/ 
      webSocket = new WebSocket(host, 'SIGN_IN_OUT_REQUEST_PROTOCOL', 'GET_REQUEST_PROTOCOL'); 
      webSocket.binaryType = "arraybuffer"; 
      webSocket.onopen = onopen; 
      webSocket.onmessage = onmessage; 
      webSocket.onclose = onclose; 
      webSocket.onerror = onerror;   
     } 
}); 

function onopen() { 
    $('#connectionStatus').text("Connected"); 
    $('#connectionStatus').buttonMarkup({theme: 'b'}); 
    $("#connectionStatus").data('icon', 'check'); 
    $("#connectionStatus .ui-icon").addClass("ui-icon-check").removeClass("ui-icon-alert"); 
    $('#login_info').append("Sub-protocol: "+webSocket.protocol+"\n"); 
} 

function onmessage(event) { 
    var data = new DataView(event.data); 
    if(data.getUint8(data.byteLength - 1) == 1) { 
     $('#login_info').append("Login Attempt Successful"); 
     $.mobile.loadPage("mobileApp.html"); 
     $.mobile.changePage("mobileApp.html") 
    } 
    else { 
     $('#login_info').append("Login Attempt Unsuccessful"); 
     $('#username').val(""); 
     $('#password').val(""); 
    } 
} 

function onclose() { 
    $('#connectionStatus').text("Connection Closed"); 
    $('#connectionStatus').buttonMarkup({theme: 'a'}); 
    $("#connectionStatus").data('icon', 'alert'); 
    $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert"); 
} 

function onerror() { 
    $('#connectionStatus').text("Connection Error"); 
    $('#connectionStatus').buttonMarkup({theme: 'a'}); 
    $("#connectionStatus").data('icon', 'alert'); 
    $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert"); 
} 

function initialize() { 
    $('#login_info').val(""); 
    $('#username').val(""); 
    $('#password').val(""); 
    $('#connectionStatus').text("Connection Closed"); 
    $('#connectionStatus').buttonMarkup({theme: 'a'}); 
    $("#connectionStatus").data('icon', 'alert'); 
    $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert"); 
} 

function sendLoginRequest(event) { 
    var i = 0; 
    event.preventDefault(); 
    if($("#login_form").valid()) { 
     var username = $("#username").val(); 
     var password = $("#password").val(); 
     var loginRequest = new Uint8Array(calculateBufferLength()); 
     loginRequest[i++] = 0x13; //User Accounts IP 
     loginRequest[i++] = 0x13; //Sign In/Sign Out Request 
     loginRequest[i++] = 0x07; //Sign In 
     loginRequest[i++] = username.length; 
     loginRequest[i++] = password.length; 

     //Pushing username 
     for(var j=0; j < username.length; j++) { 
      loginRequest[i++] = username.charCodeAt(j); 
     } 

     //Pushing password 
     for(var j=0; j < password.length; j++) { 
      loginRequest[i++] = password.charCodeAt(j); 
     } 

     webSocket.send(loginRequest.buffer); 
     $("#login_info").append("Login request sent with\nUsername: "+username+"\nPassword: "+password+"\n"); 
    } 
} 

function calculateBufferLength() { 
    var opIPLength = 1; 
    var modeLength = 1; 
    var subModeLength = 1; 
    var UserNamePasswordlengths = 2; 
    var userNameLength = $("#username").val().length; 
    var passwordLength = $("#password").val().length; 
    return (opIPLength + modeLength + subModeLength + UserNamePasswordlengths + userNameLength + passwordLength); 
} 

服務器C/C++代碼(Libwebsockets )

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <string> 
#include <vector> 
#include <libwebsockets.h> 

using namespace std; 

typedef enum { 
    USER_ACCOUNTS_IP_REQUEST, 
    MODE, 
    SUB_MODE, 
    USER_NAME_LENGTH, 
    PASSWORD_LENGTH 
}user_accounts_ip_request_t; 

typedef enum { 
    USER_ACCOUNTS_IP_RESPONSE, 
    RESPONSE_IP 
}user_accounts_ip_response_t; 

int Hex_to_Dec(unsigned char *array, int size); 
void sendLoginResponse(struct libwebsocket *wsi, void *in_buffer, size_t bufferlen, struct per_session_data__binary *out_buffer); 
void printSocketInfo(struct libwebsocket *wsi, struct libwebsocket_context *currentContext); 

struct per_session_data__binary 
{ 
    unsigned int len; 
    unsigned char buf[sizeof(LWS_SEND_BUFFER_PRE_PADDING) + 1024 + sizeof(LWS_SEND_BUFFER_POST_PADDING)]; 
}; 

static int callback_http(struct libwebsocket_context *currentContext, 
         struct libwebsocket *wsi, 
         enum libwebsocket_callback_reasons reason, void *user, 
         void *in, size_t len) 
{ 
    return 0; 
} 

static int callback_sign_in_out_request(struct libwebsocket_context *currentContext, 
            struct libwebsocket *wsi, 
            enum libwebsocket_callback_reasons reason, 
            void *user, void *in, size_t len) 
{ 
    struct per_session_data__binary *psb = (per_session_data__binary *)user; //////// 

    switch (reason) { 
     case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting 
      printf("connection established\n"); 
      break; 
     case LWS_CALLBACK_PROTOCOL_INIT: 
      printf("LWS_CALLBACK_PROTOCOL_INIT\n"); 
      break; 
     case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 
      printf("LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); 
      break; 
     case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: 
      printf("LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n"); 
      break; 
     case LWS_CALLBACK_RECEIVE: { 
      printf("Binary frame received decoding packet...\n"); 
      sendLoginResponse(wsi, in, len, psb); 
     } 
      break; 
     default: 
        break; 
    } 
     return 0; 
} 

static int callback_get_request(struct libwebsocket_context *currentContext, 
     struct libwebsocket *wsi, 
     enum libwebsocket_callback_reasons reason, 
     void *user, void *in, size_t len) 
{ 
    return 0; 
} 

static struct libwebsocket_protocols protocols[] = { 
    /* first protocol must always be HTTP handler */ 
    { 
     "http-only", // name 
     callback_http, // callback 
     0    // per_session_data_size 
    }, 
    { 
     "SIGN_IN_OUT_REQUEST_PROTOCOL", // protocol name - very important! 
     callback_sign_in_out_request, // callback 
     sizeof(struct per_session_data__binary)    // we don't use any per session data 
    }, 
    { 
     "GET_REQUEST_PROTOCOL", 
     callback_get_request, 
     sizeof(struct per_session_data__binary) 
    }, 
    { 
     NULL, NULL, 0 /* End of list */ 
    } 
}; 

int main(void) { 
     // server url will be http://localhost:9000 
     int port = 9000; 
     const char *interface = NULL; 
     struct libwebsocket_context *context; 
     struct lws_context_creation_info info; 
     // we're not using ssl 
     const char *cert_path = NULL; 
     const char *key_path = NULL; 
     // no special options 
     int opts = 0; 

    info.port = port; 
    info.iface = interface; 
    info.protocols = protocols; 
    info.extensions = libwebsocket_get_internal_extensions(); 
    info.ssl_cert_filepath = cert_path; 
    info.ssl_private_key_filepath = key_path; 
    info.ssl_ca_filepath = NULL; 
    info.gid = -1; 
    info.uid = -1; 
    info.options = opts; 
    info.user = NULL; 
    //info.ka_time = 0; 
    //info.ka_probes = 100; 
    //info.ka_interval= 60; 

    context = libwebsocket_create_context(&info); 

     if (context == NULL) { 
      fprintf(stderr, "libwebsocket init failed\n"); 
      return -1; 
    } 

     printf("starting server...\n"); 

    // infinite loop, to end this server send SIGTERM. (CTRL+C) 
    while (1) { 
      libwebsocket_service(context, 50); 
     //printf("after service\n"); 
      // libwebsocket_service will process all waiting events with their 
      // callback functions and then wait 50 ms. 
      // (this is a single threaded webserver and this will keep our server 
      // from generating load while there are not requests to process) 
    } 
     libwebsocket_context_destroy(context); 

     return 0; 
} 

void sendLoginResponse(struct libwebsocket *wsi, void *in_buffer, size_t bufferlen, struct per_session_data__binary *out_buffer) 
{ 
    vector<string> userNames, passwords; 
    string userName, password; 
    bool loginValid = false; 
    int usernameLength, passwordLength; 
    int usernamePos, passwordPos; 


    userNames.push_back("Nautel"); 
    passwords.push_back("password"); 

    //Print Login Request Data 
    char* loginRequest = (char*) in_buffer; 
    usernameLength = loginRequest[USER_NAME_LENGTH]; 
    passwordLength = loginRequest[PASSWORD_LENGTH]; 
    usernamePos = PASSWORD_LENGTH + 1; 
    passwordPos = usernamePos + usernameLength; 

    //Get Username 
    for(int i=usernamePos; i < (usernamePos+usernameLength); i++) { 
     userName.push_back(loginRequest[i]); 
    } 

    //Get Password 
    for(int i=passwordPos; i < (passwordPos + passwordLength); i++) { 
     password.push_back(loginRequest[i]); 
    } 

    printf("Username: %s Password: %s\n", userName.c_str(), password.c_str()); 

    for(int i=0; i < userNames.size(); i++) { 
     loginValid = (!userName.compare(userNames[i]) && !password.compare(passwords[i])); 
     if(loginValid) break; 
    } 

    out_buffer->buf[USER_ACCOUNTS_IP_RESPONSE] = 0x13; 
    out_buffer->buf[RESPONSE_IP] = (loginValid) ? 0x01 : 0x00; 
    out_buffer->len = 2; 
    libwebsocket_write(wsi, out_buffer->buf, out_buffer->len, LWS_WRITE_BINARY); 
} 

void printSocketInfo(struct libwebsocket *wsi, struct libwebsocket_context *currentContext){ 
    char name[128]; 
    int name_len=sizeof(name); 
    char rip[16]; 
    int rip_len= sizeof(rip); 
    int fd; 

    fd = libwebsocket_get_socket_fd(wsi); 
    libwebsockets_get_peer_addresses (currentContext, wsi, fd, name, name_len, rip, rip_len); 

    printf("Name: %s, IP: %s\n", name, rip); 
} 

是否有可能讓客戶端擁有單個服務器支持的多個子協議,反之亦然。或者我需要從客戶端到服務器的多個websocket連接以使用不同的協議。

問候, Shreyas

回答

0

在握手過程中,支持的子協議服務器端列表被髮送給客戶端。客戶也發送它的名單。 它們必須至少有一個共同的子協議。

您可以實現自己的子協議或使用現有的ones

例如,在你的情況下使用libwebsockets庫(C/C++)和JavaScript的WebSocket的客戶端,如果你實現自己的子協議的WebSocket服務器:

服務器端:

static struct libwebsocket_protocols protocols[] = { 
    { 
     "http-only", 
     callback_http, 
     0    
    }, 
    { 
     "MySubProtocol", 
     dedicated_callback_function, 
     sizeof(struct per_session_data__binary)    
    } 
} 

客戶端:

var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "MySubProtocol"); 

更多信息herehere

1

一個WebSocket的客戶端可以宣佈多的WebSocket子協議的支持,但服務器必須從客戶端公佈的列表中選擇一子協議(支持)。

相關問題