2013-04-17 226 views
3

我想通過基於Javascript的客戶端和基於Java的服務器實現WebSocket。我認爲我已經完成了所有正確的步驟,但由於未知原因,我無法與兩者建立聯繫。建立與Java服務器和Javascript客戶端的WebSocket連接

當服務器套接字接收到一個連接時,它會處理以形成一個websocket-accept響應,並將其發送回客戶端,但客戶端套接字中的連接立即關閉,奇怪的是沒有握手問題。

有沒有人有一個想法可能是什麼問題?

以下是一個Java實現我的服務器代碼:

package server; 

import java.io.IOException; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 
import java.util.List; 

import server.message.Message; 
import server.message.SpeakMessage; 


public class Server implements ConnectionListener { 
    private static final int PORT = 1509; 
    private MessageDispatcher dispatcher = new MessageDispatcher(); 
    private List<ConnectionManager> clients = new ArrayList<>(); 

    public void listen() { 
     try (ServerSocket server = new ServerSocket(PORT)) { 
      System.out.printf("Listening on port %d...%n", PORT); 
      while (true) { 
       System.out.println("Waiting for connection..."); 
       Socket client = server.accept(); 
       System.out.println("Incoming connection - Attempting to establish connection..."); 
       ConnectionManager manager = new ConnectionManager(client, dispatcher, this); 
       manager.start(); 
      } 
     } catch (IOException e) { 
      System.out.println("Unable to start server"); 
      e.printStackTrace(); 
     } 
     System.exit(0); 
    } 

    public void execute() { 
     try { 
      while (true) { 
       if (dispatcher.isEmpty()) { 
        Thread.sleep(100); 
        continue; 
       } 
       Message msg = dispatcher.read(); 
       if (msg instanceof SpeakMessage) 
        broadcast(MessageEncoder.spoke(((SpeakMessage) msg).getText())); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 
    } 

    public static void main(String[] args) { 
     final Server server = new Server(); 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       server.listen(); 
      } 
     }).start(); 
     server.execute(); 
    } 

    public synchronized void broadcast(byte[] message) { 
     for (ConnectionManager client : clients) { 
      client.send(message); 
     } 
    } 

    @Override 
    public synchronized void clientConnected(ConnectionManager who) { 
     clients.add(who); 
     System.out.println("Connected client " + clients.size()); 
    } 

    @Override 
    public synchronized void clientDisconnected(ConnectionManager who) { 
     clients.remove(who); 
    } 
} 

繼承人子服務器的ConnectionManager:

package server; 

import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.lang.reflect.InvocationTargetException; 
import java.net.Socket; 
import java.security.MessageDigest; 
import java.util.Properties; 

import server.message.HandshakeMessage; 
import server.message.Message; 


public class ConnectionManager { 
    private static final int CLIENT_VERSION = 1; 
    private Socket socket; 
    private MessageDecoder decoder = new MessageDecoder(); 
    private MessageDispatcher dispatcher; 
    private ConnectionListener listener; 

    public ConnectionManager(Socket connection, MessageDispatcher dispatcher, ConnectionListener listener) { 
     socket = connection; 
     this.dispatcher = dispatcher; 
     this.listener = listener; 
    } 

    public void start() { 
     Thread t = new Thread(new ChannelReader()); 
     t.setName("Client thread"); 
     t.setDaemon(true); 
     t.start(); 
    } 

    public void send(byte[] data) { 
     if (socket == null) 
      return; 

     try { 
      DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); 
      dos.write(data); 
      dos.flush(); 
     } catch (IOException e) { 
      disconnect("Client closed the connection"); 
     } 
    } 

    private class ChannelReader implements Runnable { 
     private boolean accepted = false; 
     private String ret = null; 

     @Override 
     public void run() { 
      try { 
       DataInputStream in = new DataInputStream(socket.getInputStream()); 
       while (socket != null && socket.isConnected()) { 
        int len = in.readShort(); 
        if (len < 0) { 
         disconnect("Invalid message length."); 
        } 

        String s; 
        readLine(in); 
        Properties props = new Properties(); 
        while((s=readLine(in)) != null && !s.equals("")) { 
         String[] q = s.split(": "); 
         props.put(q[0], q[1]); 
        } 

        if(props.get("Upgrade").equals("websocket") && props.get("Sec-WebSocket-Version").equals("13")) { // check if is websocket 8 
         String key = (String) props.get("Sec-WebSocket-Key"); 
         String r = key + "" + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // magic key 
         MessageDigest md = MessageDigest.getInstance("SHA-1"); 
         md.reset(); 
         md.update(r.getBytes()); 
         byte[] sha1hash = md.digest(); 


         String returnBase = base64(sha1hash); 


         ret = "HTTP/1.1 101 Switching Protocols\r\n"; 
          ret+="Upgrade: websocket\r\n"; 
          ret+="Connection: Upgrade\r\n"; 
          ret+="Sec-WebSocket-Accept: "+returnBase; 

        } else { 
         disconnect("Client got wrong version of websocket"); 
        } 

        Message msg = decoder.decode((String) props.get("Sec-WebSocket-Protocol")); 

        if (!accepted) { 
         doHandshake(msg); 
        } else if (dispatcher != null) { 
         dispatcher.dispatch(msg); 
        } 
       } 
      } catch (Exception e) { 
       disconnect(e.getMessage()); 
       e.printStackTrace(); 
      } 
     } 

     private void doHandshake(Message msg) { 
      if (!(msg instanceof HandshakeMessage)) { 
       disconnect("Missing handshake message"); 
       return; 
      } 
      HandshakeMessage handshake = (HandshakeMessage) msg; 
      if (handshake.getVersion() != CLIENT_VERSION) { 
       disconnect("Client failed in handshake."); 
       return; 
      } 
      send(ret.getBytes()); 
      accepted = true; 
      listener.clientConnected(ConnectionManager.this); 
     } 

     private String base64(byte[] input) throws ClassNotFoundException, 
     SecurityException, NoSuchMethodException, IllegalArgumentException, 
     IllegalAccessException, InvocationTargetException, InstantiationException { 
      Class<?> c = Class.forName("sun.misc.BASE64Encoder"); 
      java.lang.reflect.Method m = c.getMethod("encode", new Class<?>[]{byte[].class}); 
      String s = (String) m.invoke(c.newInstance(), input); 
      return s; 
     } 

     private String readLine(InputStream in) { 
      try{ 
       String line = ""; 
       int pread; 
       int read = 0; 
       while(true) { 
        pread = read; 
        read = in.read(); 
        if(read!=13&&read!=10) 
         line += (char) read; 
        if(pread==13&&read==10) break; 
       } 
       return line; 
      }catch(IOException ex){ 

      } 
      return null; 
     } 

    } 

    public synchronized void disconnect(String message) { 
     System.err.println(message); 
     if (socket != null) { 
      try { 
       socket.close(); 
      } catch (IOException e) { 

      } 
     } 
     socket = null; 
     listener.clientDisconnected(ConnectionManager.this); 
    } 
} 

而且MessageDispatcher:

package server; 

import java.util.Queue; 
import java.util.concurrent.LinkedBlockingDeque; 

import server.message.Message; 


public class MessageDispatcher { 
    Queue<Message> messageQueue = new LinkedBlockingDeque<>(); 

    public void dispatch(Message message) { 
     messageQueue.offer(message); 
    } 

    public Message read() { 
     return messageQueue.poll(); 
    } 

    public boolean isEmpty() { 
     return messageQueue.isEmpty(); 
    } 
} 

而且在繼承人實現我的客戶端代碼javascript:

var canvas, // Canvas DOM element 
    ctx, // Canvas rendering context 
    socket; // Socket connection 

function init() { 
    // Initialise the canvas 
    canvas = document.getElementById("gameCanvas"); 
    ctx = canvas.getContext("2d"); 
    // Maximise the canvas 
    canvas.width = window.innerWidth; 
    canvas.height = window.innerHeight; 

    // Initialise socket connection 
    if (window.WebSocket) { 
     socket = new WebSocket("ws://localhost:1509/", ["1", "YURI"]); 
     socket.onopen = onSocketConnected(); 
     socket.onclose = onSocketDisconnect(); 
     socket.onmessage = onSocketMessage(); 
     socket.onerror = onSocketError(); 
    } else { 
     alert("The browser does not support websocket."); 
    } 

}; 

// Socket message 
function onSocketMessage(message) { 
    console.log('Message: ' + message.data); 
}; 

// Socket error 
function onSocketError(error) { 
    console.log('Error: ' + error.data); 
}; 

// Socket connected 
function onSocketConnected() { 
    console.log("Connected to socket server"); 
}; 

// Socket disconnected 
function onSocketDisconnect() { 
    console.log("Disconnected from socket server"); 
}; 
+1

你是否設法找到解決方案。我需要構建這樣的東西,這將是有用的重用您的示例。 – Akosha

回答

4

我想,這是因爲您正在使用Java服務器端的Socket包和客戶端的WebSocket API。你的想法非常好,但技術錯誤。 保留WebSocket在客戶端(Javascript),因爲你沒有很多其他的可能性,但在服務器端(Java)嘗試JWebSocket。事實上,WebSocket使用TCP/IP,但通過TCP/IP使用它自己的通信協議。 Java Socket套件純粹是TCP/IP。使用JWebSocket重新編寫服務器,可以在以下位置找到有關JWebSocket的所有詳細信息: http://jwebsocket.org/。 我希望我的回答能幫助你。

+0

請提供一些示例代碼與您的答案,以更好地幫助。 –

相關問題