聊一聊我用到的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的相关知识,都是从项目中学到的。有兴趣的可以一起交流,若有错漏欢迎指正。

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