注:本文仅为最近工作中用到的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的相关知识,都是从项目中学到的。有兴趣的可以一起交流,若有错漏欢迎指正。