1. 程式人生 > >JAVA Sokcet(服務端)連線WebSocket個人總結

JAVA Sokcet(服務端)連線WebSocket個人總結

package com.cx;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextArea;
/**
  * @author(作者) :Cx
 */
public class WebServer {
	private int port = 8888;
    private ServerSocket serverSocket;
    private List<Handler> handlers = new ArrayList<Handler>();
    JTextArea text;//顯示資訊
 
    public WebServer(JTextArea text) throws IOException {
    	this.text = text;
        serverSocket = new ServerSocket(port);
        text.setText("WebSocket伺服器已啟動!\n");
        text.append("等待客戶端連線...!\n");
    }
 
    public void service() {
        Socket socket = null;
        while (true) {
            try {
            	//接收socket請求
                socket = serverSocket.accept();
                //判斷
                if(handlers.size()>0){
            		for (Handler handler : handlers) {
            			if(handler.getSpeech()!=null){
            				handler.getSpeech().flag=false;
            			}
					}
            		handlers.clear();
            	}
                //開啟執行緒,接收不同的socket請求
                Handler handler = new Handler(socket);
                handlers.add(handler);
                Thread workThread = new Thread(handler);
                workThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    class Handler implements Runnable {
    	private Speech speech = new Speech();
        private Socket socket;
        private boolean hasHandshake = false;
        Charset charset = Charset.forName("UTF-8");  
        
        public Speech getSpeech(){
        	return this.speech;
        }
        
        public Handler(Socket socket) {
            this.socket = socket;
        }
 
        private PrintWriter getWriter(Socket socket) throws IOException {
            OutputStream socketOut = socket.getOutputStream();
            return new PrintWriter(socketOut, true);
        }
        public void run() {
            try {
                System.out.println("New connection accepted"
                        + socket.getInetAddress() + ":" + socket.getPort());
                text.append("New connection accepted!.."+socket.getInetAddress()+":"+socket.getPort()+"\n");
                text.setCaretPosition(text.getText().length());
                //獲取socket輸入流資訊
                InputStream in = socket.getInputStream();
                //獲取socket輸出
                PrintWriter pw = getWriter(socket);
                //讀入快取(定義一個1M的快取區)
                byte[] buf = new byte[1024];
                //讀到位元組(讀取輸入流資料到快取)
                int len = in.read(buf, 0, 1024);
                //讀到位元組陣列(定義一個容納資料大小合適快取區)
                byte[] res = new byte[len];
                //將buf內中資料拷貝到res中
                System.arraycopy(buf, 0, res, 0, len);
                //列印res快取內容
                String key = new String(res);
                if(!hasHandshake && key.indexOf("Key") > 0){
                    //握手
                	//通過字串擷取獲取key值
                    key = key.substring(0, key.indexOf("==") + 2);
                    key = key.substring(key.indexOf("Key") + 4, key.length()).trim();
                    //拼接WEBSOCKET傳輸協議的安全校驗字串
                    key+= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                    //通過SHA-1演算法進行更新
                    MessageDigest md = MessageDigest.getInstance("SHA-1");  
                    md.update(key.getBytes("utf-8"), 0, key.length());
                    byte[] sha1Hash = md.digest();  
                    //進行Base64加密
                    sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();  
                    key = encoder.encode(sha1Hash);  
                    //伺服器端返回輸出內容
                    pw.println("HTTP/1.1 101 Switching Protocols");
                    pw.println("Upgrade: websocket");
                    pw.println("Connection: Upgrade");
                    pw.println("Sec-WebSocket-Accept: " + key);
                    pw.println();
                    pw.flush();
                    //將握手標誌更新,只握一次
                    hasHandshake = true;
                    //伺服器返回成功,---握手協議完成,進行TCP通訊
                    //進行語音互動
					//當時做語音時用到的
                    speech.verifySocket(this);
                    //----------------------以下是獲取到瀏覽器傳送的訊息--------
                    //接收資料
                    byte[] first = new byte[1];
                	//這裡會阻塞
                    int read = in.read(first, 0, 1);
                    //讀取第一個位元組是否有值,開始接收資料
                    while(read > 0){
                    	//讓byte和十六進位制做與運算(二進位制也就是11111111)
                    	//獲取到第一個位元組的數值
                        int b = first[0] & 0xFF;
                        //1為字元資料,8為關閉socket(只要低四位的值判斷)
                        byte opCode = (byte) (b & 0x0F);
                        if(opCode == 8){
                            socket.getOutputStream().close();
                            break;
                        }
                        b = in.read();
                        //只能描述127
                        int payloadLength = b & 0x7F;
                        if (payloadLength == 126) {
                            byte[] extended = new byte[2];
                            in.read(extended, 0, 2);
                            int shift = 0;
                            payloadLength = 0;
                            for (int i = extended.length - 1; i >= 0; i--) {
                                payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
                                shift += 2;
                            }
                        } else if (payloadLength == 127) {
                            byte[] extended = new byte[8];
                            in.read(extended, 0, 8);
                            int shift = 0;
                            payloadLength = 0;
                            for (int i = extended.length - 1; i >= 0; i--) {
                                payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
                                shift += 8;
                            }
                        }
                        //掩碼
                        byte[] mask = new byte[4];
                        in.read(mask, 0, 4);
                        int readThisFragment = 1;
                        ByteBuffer byteBuf = ByteBuffer.allocate(payloadLength + 30);
                        byteBuf.put("瀏覽器: ".getBytes("UTF-8"));
                        while(payloadLength > 0){
                             int masked = in.read();
                             masked = masked ^ (mask[(int) ((readThisFragment - 1) % 4)] & 0xFF);
                             byteBuf.put((byte) masked);
                             payloadLength--;
                             readThisFragment++;
                        }
                        byteBuf.flip();
                        //將內容返回給客戶端
                        responseClient(byteBuf, true);
                        //列印內容
                        printRes(byteBuf.array());
                        in.read(first, 0, 1);
                    }
                }
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            	System.out.println("*********************廢棄Socket回收階段******************!");
                try {
                    if (socket != null){
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
 
        public void responseClient(ByteBuffer byteBuf, boolean finalFragment) throws IOException {
            OutputStream out = socket.getOutputStream();
            int first = 0x00;
            //是否是輸出最後的WebSocket響應片段
                if (finalFragment) {
                    first = first + 0x80;
                    first = first + 0x1;
                }
                out.write(first);
                if (byteBuf.limit() < 126) {
                    out.write(byteBuf.limit());
                } else if (byteBuf.limit() < 65536) {
                out.write(126);
                out.write(byteBuf.limit() >>> 8);
                out.write(byteBuf.limit() & 0xFF);
                } else {
                // Will never be more than 2^31-1
                out.write(127);
                out.write(0);
                out.write(0);
                out.write(0);
                out.write(0);
                out.write(byteBuf.limit() >>> 24);
                out.write(byteBuf.limit() >>> 16);
                out.write(byteBuf.limit() >>> 8);
                out.write(byteBuf.limit() & 0xFF);
                }
                // Write the content
                out.write(byteBuf.array(), 0, byteBuf.limit());
                out.flush();
        }
         
        private void printRes(byte[] array) {
            ByteArrayInputStream  byteIn = new ByteArrayInputStream(array);
            InputStreamReader reader = new InputStreamReader(byteIn, charset.newDecoder());
            int b = 0;
            String res = "";
            try {
                while((b = reader.read()) > 0){
                    res += (char)b;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(res);
        }
    }
}