聊一聊我用到的SOCKET

注:本文僅爲最近工作中用到的socket的整理

最近在做音視頻項目,socket用的就比較多了,以前項目裏也有隻是僅限於websocket有個心跳包的那種長連接。不過接收的都是字符串的形式。

今天我要聊的是最近用到的短連接,就是用socket進行tcp通訊。

先說一哈基本流程:連接->發送包->接收包->關閉

就這麼快,拿完數據就把流關閉了。

一個包一個包發的是什麼? byte[] 數據!

也就是發送包和接收包是以字節流的形式來完成的。

這就涉及到一個字節轉換的問題,一個int佔用4個字節。

比如說我要發送 int 1 那麼發送的其實是一串[ 0 , 0 , 0 , 1 ]的數據包。

但是不會這麼簡單,一般都是這樣定義的:

服務器和客戶端會約定一個數據結構,一般是C語言的那種形式


發送:

struct	head	//包頭(這個是不和服務器約定好的,不會變的,不管接收還是發送都是這個格式)
{
	int head_msg;	//頭信息,和服務器的約定,比如說約定頭信息爲10086當我讀取的時候讀到是10086證明是服務器發出的包,我們才進行解析,其他的就不用管了。
	int length;	//包長度,一般爲總長度,就是head+body的長度,一個int是4個字節,那麼這個head的長度就是4+4+4=12個字節,這裏length就要填12。
	int command_id;	//命令碼,假如約定命令碼100是查詢用戶數據,這裏就填100。
}

struct body
{
	int device_id;	//設備的id。
}

接收:
struct	head
{
	int head_msg;	//和上面一樣。
	int length;	//假如接收到的length爲80,那麼80-12=68就是body的字節長度。
	int command_id;	//命令碼,假如約定命令碼200是查詢用戶數據的返回,那麼解析到這裏是200就進行相關解析。
}

struct body
{
	int device_id;	//剛剛查詢的設備的id。
	int user_id;	//設備上用戶的id。
	char[64] user_name;	//設備上用戶名。
}

以上只是舉例,講一個約定數據結構的基本概念,實際項目根據具體需求而定。

比如說上面的發送命令,包頭是3個int 那麼就是3*4=12個字節,body是一個int那麼就是4個字節,12+4=16個字節,所以按上面的格式發送命令的話,就是16個字節了。
服務器接收的話,先是讀取12個字節,因爲是約定的包頭,不會改變的。
然後讀取包頭的裏的command_id命令碼,就知道我body只有一個int,只需要再讀取4個字節就可以了。
同理,客戶端這邊接收到服務器發送的消息也是這種讀法。

最後用代碼簡單的講一下

連接服務器

Socket socket = new Socket(HOST, PORT);//HOST和PORT分別是服務器的ip地址的端口號

是否連接成功(連接服務器後調用這個檢測是否連接成功,成功後就可以交互數據了)

socket.isConnected()

輸入流和輸出流,用於發送數據到服務器,和讀取服務器發送過來的數據。

OutputStream outputStream = socket.getOutputStream();//獲取輸出流,就是我給服務器發數據的流。
InputStream inputStream = socket.getInputStream();//獲取輸入流,就是服務器給我發送的 我需要讀取的數據

向服務器發送一個數據包

outPutStream.write(byte b[]);//byte b[]是上邊講的head+body轉成字節流後的byte數組

讀取服務器發送過來的數據包

byte[] head = new byte[12];//先讀取頭,約定的不變的長度。
inputStream.read(head);//然後根據上面講到的head數據結構讀取到包的長度。

//假如包長度是200那麼,200-12=178就是body的長度

byte[] body= new byte[178];//再繼續讀取178位
inputStream.read(body);//然後就可以解析服務器的數據了。

一個完整的發送和讀取的流基本就這樣完成了

上面說了,這個TCP是短連接,用完就關閉。

那麼,解析數據完成後需要關閉socket,關閉需要順序,否則會拋出異常。

        if (socket != null) {
            if (socket.isConnected()) {
                    if (inputStream != null)	inputStream.close();
                    if (outputStream != null)	outputStream.close();
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

至此,一個socket的全部操作就完成了。

這就是我最近學習到的socket的相關知識,都是從項目中學到的。有興趣的可以一起交流,若有錯漏歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章