##socket 丢包粘包解决方式

采用固定头部长度(一般为4个字节),包头保存的是包体的长度

header+body

包头+包体

下面的例子不是按照上图中规定的格式编写的,但是思路都是一样的,先读出一个包头,得到包体的长度,解析出包体

public class SocketServer {
public static void main(String args[]) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress());
System.out.println("启动服务端~");
while (true) {
Socket socket = serverSocket.accept();
new ReceiveThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
} static class ReceiveThread extends Thread {
public static final int PACKET_HEAD_LENGTH = ;// 包头长度
private Socket socket;
private volatile byte[] bytes = new byte[]; public ReceiveThread(Socket socket) {
this.socket = socket;
} //将b数组 下标从begin到end-1的值追加到a数组的后面,并返回
public byte[] mergebyte(byte[] a, byte[] b, int begin, int end) {
byte[] add = new byte[a.length + end - begin];
int i = ;
for (i = ; i < a.length; i++) {
add[i] = a[i];
}
for (int k = begin; k < end; k++, i++) {
add[i] = b[k];
}
return add;
} @Override
public void run() {
int count = ;
while (true) {
try {
InputStream reader = socket.getInputStream();
{ //这里可以保证正好读取到4个字节的包头
if (bytes.length < PACKET_HEAD_LENGTH) { //【第一次进来,或者经过一次循环bytes的长度被置为0】
byte[] head = new byte[PACKET_HEAD_LENGTH - bytes.length];
int couter = reader.read(head);
if (couter < ) {
continue;
}
bytes = mergebyte(bytes, head, , couter);
if (couter < PACKET_HEAD_LENGTH) {
continue;
}
}
} // 取出包体长度
byte[] temp = new byte[];
temp = mergebyte(temp, bytes, , PACKET_HEAD_LENGTH);
int bodylength = ByteUtil.byteArrayToInt(temp);// 包体长度 //完整读取一个包
if (bytes.length < bodylength + PACKET_HEAD_LENGTH) {// 不够一个包
byte[] body = new byte[bodylength + PACKET_HEAD_LENGTH - bytes.length];// 剩下应该读的字节(凑一个包)
int couter = reader.read(body);
if (couter < ) {
continue;
}
bytes = mergebyte(bytes, body, , couter);
if (couter < body.length) {
continue;
}
} //把包体的内容读取出来
byte[] body = new byte[];
body = mergebyte(body, bytes, PACKET_HEAD_LENGTH, bytes.length);
count++;
System.out.println("server receive body: " + count + new String(body));
//为读取下一个包将数组长度重置为空数组,长度为0
bytes = new byte[];
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public class ClientSocket {
public static void main(String args[]) throws IOException {
System.out.println("启动客户端~");
Socket clientSocket = new Socket();
clientSocket.connect(new InetSocketAddress());
new SendThread(clientSocket).start(); } static class SendThread extends Thread {
Socket socket;
public SendThread(Socket socket) {
this.socket = socket;
} @Override
public void run() {
String reqMessage = "HelloWorl ! from clientsocket this is test half packages!";
for (int i = ; i < ; i++) {
sendPacket(reqMessage+ "u "+ i);
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } public void sendPacket(String message) {
byte[] contentBytes = message.getBytes();// 包体内容
int contentlength = contentBytes.length;// 包体长度
byte[] headbytes = ByteUtil.intToByteArray(contentlength);// 包头字节数组
byte[] bytes = new byte[headbytes.length + contentlength];// 包=包头+包体
int i = ;
for (i = ; i < headbytes.length; i++) {// 包头
bytes[i] = headbytes[i];
}
for (int j = i, k = ; k < contentlength; k++, j++) {// 包体
bytes[j] = contentBytes[k];
}
try {
OutputStream writer = socket.getOutputStream();
writer.write(bytes);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
public class ByteUtil {

    public static void main(String[] args) {
byte[] res = intToByteArray();
System.out.println(byteArrayToInt(res)); } public static byte[] intToByteArray(int i) {
byte[] result = new byte[];
// 由高位到低位
result[] = (byte) ((i >> ) & 0xFF);
result[] = (byte) ((i >> ) & 0xFF);
result[] = (byte) ((i >> ) & 0xFF);
result[] = (byte) (i & 0xFF);
return result;
} public static int byteArrayToInt(byte[] bytes) {
int value = ;
// 由高位到低位
for (int i = ; i < ; i++) {
int shift = ( - - i) * ;
value += (bytes[i] & 0x000000FF) << shift;// 往高位游
}
return value;
}
}

转自: https://blog.csdn.net/nongfuyumin/article/details/78298380?utm_source=blogxgwz5

socket编程解决粘包和丢包问题的更多相关文章

  1. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  2. VS2015编译FFMPEG,修改FFmpeg缓冲区大小解决实时流解码丢包问题,FFmpeg错误rtsp流地址卡死的问题,设置超时

    之前尝试过很多网上利用Windows编译FFmpeg的文章,都没有办法编译X64位的FFmpeg,有些教程中有专门提到编译64位的FFmpeg需要下载mingw-w64-install,但是编译的过程 ...

  3. 嵌入式开发之UDP 丢包--- UDP 丢包控制方法

    0. 发送端可以,发送五次左右,再Sleep 1.调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失.对于这种情况可以修改接收 ...

  4. socket编程 TCP 粘包和半包 的问题及解决办法

    一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...

  5. Socket编程--TCP粘包问题

    TCP是个流协议,它存在粘包问题 产生粘包的原因是: TCP所传输的报文段有MSS的限制,如果套接字缓冲区的大小大于MSS,也会导致消息的分割发送. 由于链路层最大发送单元MTU,在IP层会进行数据的 ...

  6. day34 基于TCP和UDP的套接字方法 粘包问题 丢包问题

    TCP 基于流的协议 又叫可靠性传输协议 通过三次握手 四次挥手 来保证数据传输完毕 缺点效率低 正因为是基于流的协议 所以会出现粘包问题粘包问题:原因一:是应为数据是先发送给操作系统,在操作系统中有 ...

  7. socket之解决粘包方法

    low方法 import socket,subprocess ip_port=('127.0.0.1',8080) s=socket.socket(socket.AF_INET,socket.SOCK ...

  8. C#中Socket编程解决应用程序直接的通信

    using System;using System.Collections.Generic;using System.Linq;using System.Text; using System.Net; ...

  9. UDP丢包和无序 问题的解决方法

    最近在做一个项目,在这之前,做了个验证程序. 发现客户端连续发来1000个1024字节的包,服务器端出现了丢包现象. 纠其原因,是服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了. 我用过s ...

随机推荐

  1. struts2_项目运行报404

    1.缺少jar包,commons-lang3-3.2.jar 参考网址:https://blog.csdn.net/u013457382/article/details/50972401 2.stru ...

  2. Java_冒泡排序_原理及优化

    冒泡排序及其优化 一.原理及优化原理 1.原理讲解 冒泡排序即:第一个数与第二个数进行比较,如果满足条件位置不变,再把第二个数与第三个数进行比较.不满足条件则替换位置,再把第二个数与第三个数进行比较, ...

  3. MySQL技巧(二)——无限级分类表设计

    无限级分类表的设计(掌握'自身连接') 类似图书这种,会有很多种分类,而且在现实生活中这种分类会无限的往下分,所以不可能每有一个分类就创建一个分类表.应该使用下面这种语句 DROP TABLE IF ...

  4. linux下ftp服务器搭建

    1.yum install vsftpd  使用yum安装ftp 2.创建并授权ftp文件目录   mkdir -P /ftp/ftpadmin       chmod -R 777 /ftp/ftp ...

  5. mybatis缓存机制

    目录 mybatis缓存机制 Executor和缓存 一级缓存 小结 二级缓存 小结 mybatis缓存机制 mybatis支持一.二级缓存来提高查询效率,能够正确的使用缓存的前提是熟悉mybatis ...

  6. JavaScript机器学习之线性回归

    译者按: AI时代,不会机器学习的JavaScript开发者不是好的前端工程师. 原文: Machine Learning with JavaScript : Part 1 译者: Fundebug ...

  7. 学linux,从Ubuntu开始

    1.安装过程出现0x00000000指令引用的0x00000000内存该内存不能为written 如果你安装的是inux系统 需要在设置-->系统--> 处理器--启用PAE支持我的就是这 ...

  8. iOS中时间与时间戳的相互转化

    //获取当前系统时间的时间戳 #pragma mark - 获取当前时间的 时间戳 +(NSInteger)getNowTimestamp{ NSDateFormatter *formatter = ...

  9. Loadrunner 脚本优化-事务函数简介

    脚本优化-事务函数简介 by:授客 QQ:1033553122 1.事务的开始和结束名称需要相同 lr_start_transaction(“transaction_name”); …//事务处理 l ...

  10. ionic开发中,输入法键盘弹出遮挡住div元素

    采用ionic 开发中,遇到键盘弹出遮挡元素的问题. 以登陆页面为例,输入用户名和密码时,键盘遮挡了登陆按钮. 最终采用自定义指令解决了问题: .directive('popupKeyBoardSho ...