1. 程式人生 > >Socket 相關資料(隨筆)

Socket 相關資料(隨筆)

gpo har 數據類型 ext 由於 throw ack 應該 soc

由於項目上的 http 請求量較大,項目上性能跟不上。於是考慮把 短連接的 http 換成 長連接的tcp 形式 試試效果。

先 研究了一下 長連接方式。就是要用到 socket 方面的知識。

技術分享圖片

技術分享圖片

package com.bkc.bpmp.common.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/** * 搭建服務器端 a)、創建ServerSocket對象綁定監聽端口。 b)、通過accept()方法監聽客戶端的請求。 c)、建立連接後,通過輸入輸出流讀取客戶端發送的請求信息。 d)、通過輸出流向客戶端發送請求信息。 e)、關閉相關資源。 * @author ppnie * */ public class SocketService { // 搭建服務器端 public static void main(String[] args) throws IOException { SocketService socketService
= new SocketService(); // 1、a)創建一個服務器端Socket,即SocketService socketService.oneServer(); } public void oneServer() { try { ServerSocket server = null; try { server = new ServerSocket(5209);
// b)指定綁定的端口,並監聽此端口。 System.out.println("服務器啟動成功"); // 創建一個ServerSocket在端口5209監聽客戶請求 } catch (Exception e) { System.out.println("沒有啟動監聽:" + e); // 出錯,打印出錯信息 } Socket socket = null; try { socket = server.accept(); // 2、調用accept()方法開始監聽,等待客戶端的連接 // 使用accept()阻塞等待客戶請求,有客戶 // 請求到來則產生一個Socket對象,並繼續執行 } catch (Exception e) { System.out.println("Error." + e); // 出錯,打印出錯信息 } // 3、獲取輸入流,並讀取客戶端信息 String line; BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象得到輸入流,並構造相應的BufferedReader對象 PrintWriter writer = new PrintWriter(socket.getOutputStream()); // 由Socket對象得到輸出流,並構造PrintWriter對象 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 System.out.println("Client:" + in.readLine()); // 在標準輸出上打印從客戶端讀入的字符串 line = br.readLine(); // 從標準輸入讀入一字符串 // 4、獲取輸出流,響應客戶端的請求 while (!line.equals("end")) { // 如果該字符串為 "bye",則停止循環 writer.println(line); // 向客戶端輸出該字符串 writer.flush(); // 刷新輸出流,使Client馬上收到該字符串 System.out.println("Server:" + line); // 在系統標準輸出上打印讀入的字符串 System.out.println("Client:" + in.readLine()); // 從Client讀入一字符串,並打印到標準輸出上 line = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 // 5、關閉資源 writer.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket server.close(); // 關閉ServerSocket } catch (Exception e) {// 出錯,打印出錯信息 System.out.println("Error." + e); } } } package com.bkc.bpmp.common.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketClient { // 搭建客戶端 public static void main(String[] args) throws IOException { try { // 1、創建客戶端Socket,指定服務器地址和端口 // Socket socket=new Socket("127.0.0.1",5200); Socket socket = new Socket("192.168.1.99", 5209); System.out.println("客戶端啟動成功"); // 2、獲取輸出流,向服務器端發送信息 // 向本機的52000端口發出客戶請求 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket對象得到輸出流,並構造PrintWriter對象 // 3、獲取輸入流,並讀取服務器端的響應信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象得到輸入流,並構造相應的BufferedReader對象 String readline; readline = br.readLine(); // 從系統標準輸入讀入一字符串 while (!readline.equals("end")) { // 若從標準輸入讀入的字符串為 "end"則停止循環 write.println(readline); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server馬上收到該字符串 System.out.println("Client:" + readline); // 在系統標準輸出上打印讀入的字符串 System.out.println("Server:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 // 4、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket } catch (Exception e) { System.out.println("can not listen to:" + e);// 出錯,打印出錯信息 } } }

這是一個簡單的 用java 實現 socket 客戶端與服務端的 代碼。

但是這樣的例子,並不能實際運用與項目之中。在實際項目中需要考慮到 套接字的連接什麽時候關閉,流什麽時候關閉,參數的傳入與信息的響應都需要得到結果。

若是這裏使用的方法同 http 的話,應該是 一個請求一個對應的響應結果,若是長連接,應該如何把多線程與長連接 結合起來呢?

現在的項目是 使用C++ 服務端 和 java 客戶端 來使用 socket 進行通信。

C++ 與 Java 之間的通信還涉及到了一個 網絡字節碼 不一致的問題。以及 還有一個 自定義協議 的問題

假設 自定義協議 為

技術分享圖片

java 客戶端代碼(至於這裏的BytePtr ,就是 網絡字節碼 的轉碼)

public class BytePtr {

    public static byte[] toLH(short n) {  
        byte[] b = new byte[2];  
        b[0] = (byte) (n & 0xff);  
        b[1] = (byte) (n >> 8 & 0xff);  
        return b;  
      }
    
    public   static   byte [] toLH( int  n) {  
        byte [] b =  new   byte [ 4 ];  
        b[0 ] = ( byte ) (n &  0xff );  
        b[1 ] = ( byte ) (n >>  8  &  0xff );  
        b[2 ] = ( byte ) (n >>  16  &  0xff );  
        b[3 ] = ( byte ) (n >>  24  &  0xff );  
        return  b;  
      }  
    
    public static byte[] addBytes(byte[] data1, byte[] data2) {  
        byte[] data3 = new byte[data1.length + data2.length];  
        System.arraycopy(data1, 0, data3, 0, data1.length);  
        System.arraycopy(data2, 0, data3, data1.length, data2.length);  
        return data3;  
      
    }
}

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class ChatClient
{
    
    public static void main(String[] args)
    {
        try
        {
            Socket client = new Socket("192.168.1.108", 10008);
            OutputStream out = client.getOutputStream();
            DataOutputStream outs = new DataOutputStream(out);
            Scanner scaner = new Scanner(System.in);
            genProtocol(outs, scaner.next());
            parseProtocol(client);
            
            outs.close();
            out.close();
            client.close();
        }
        catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
    /**
     * 構造協議
     *
     * @param out
     * @param msg
     * @throws IOException
     */
    private static void genProtocol(DataOutputStream out, String msg)
        throws IOException
    {
        short type = 10001; // 消息類型
        byte[] bytes = msg.getBytes(); // 消息內容
        int totalLen = bytes.length; // 消息長度
        out.write((BytePtr.addBytes(BytePtr.addBytes(BytePtr.toLH(type), BytePtr.toLH(totalLen)), bytes))); // 寫入消息內容
        out.flush();
    }
    
    private static void parseProtocol(Socket client)
        throws IOException
    {
        InputStream is = client.getInputStream();
        DataInputStream dis = new DataInputStream(is); // 讀取Java標準數據類型的輸入流
        
        // 協議解析
        
        int totalLen = dis.readInt(); // 讀取消息長度
        byte[] data = new byte[totalLen]; // 定義存放消息內容的字節數組
        int len = is.read(data);
        String text = new String(data, 0, len);
        System.out.println("發來的內容是:" + text);
        
        is.close();
        dis.close();
    }
    
}

哦,這裏還提到 一個工具 Wireshark,用來抓取包,來查看一下網絡字節碼到底傳送的是一些什麽

技術分享圖片

哦,還有 提到的 netty 技術,至於怎麽用,還是先看看再說。

至於 有一些電子書之類的,可以 到腳本之家 去下載。

最最重要的一點,下載的電子書、視頻、源碼 之類的,一定要看啊。

Socket 相關資料(隨筆)