异步Socket接收数据后缓存处理问题

异步接收数据都正常,是个定长TLV包,但是接收到后都是直接写入bufflist后再getdata出来处理,发现有时会有掉包情况,以为是线程安全问题,后来加入了lock段将bufflist内代码锁住,依然会有掉包现象,导致组包失败,请教了一些人,回答仍然是线程安全问题,请问是否有更好的处理办法,如有请贴出代码,因为理论我都明白,也不是解包问题(这个解包方式只是随便写的简单方式)现需要能实际解决缓存数据包问题的方法
C# code
    
    
user.BuffList.InsertByteArray(data); // 插入数据包缓冲池 do { try { byte[] buff = user.BuffList.GetData(); // 取出存在的数据包 if (buff == null) break; DataHandler(buff, user); // 将每个数据包指令进行处理 } catch { // 取包异常 } } while ( true);


C# code
    
    
public class BuffList { public object locklist = new object(); public List< byte> ByteList { get; set; } public BuffList() { ByteList = new List< byte>(); } public void Clecr() { lock (locklist) { ByteList.Clear(); } } public void InsertByteArray( byte[] Data) { lock (locklist) { ByteList.AddRange(Data); } } public Int16 readint16wgh() { byte[] temp = new byte[ 2]; ByteList.CopyTo( 0, temp, 0, 2); return BitConverter.ToInt16(temp, 0); } public enum CmdType { XXX = 1101, } public byte[] GetData() { lock (locklist) { if (ByteList.Count > 288) { if ((CmdType)readint16wgh() == CmdType.XXX) { byte[] temp = new byte[ 289]; ByteList.CopyTo( 0, temp, 0, 289); if (packet.CheckWGHData(temp)) { ByteList.RemoveRange( 0, 289); return temp; } } else { // 包异常,无法正确解析 } return null; } else { return null; } } } }
bdmh
2011-06-29 12:34:37
建议,把接收和数据处理分开,接收后放到列表中,单独线程对列表逐个处理
hudingwen
2011-06-29 12:39:13
已分开,你看到的这些代码都是接收后委托了另一个线程进行处理的,也就是说我贴出来的代码都是在另一条线程上,但是不一定是一条线程,系统处理不过来时可能会大于一条线程
hudingwen
2011-06-29 13:46:22
哪位兄弟有解决方法呀
djc7811
2011-06-29 13:50:33
引用 1 楼 bdmh 的回复:

建议,把接收和数据处理分开,接收后放到列表中,单独线程对列表逐个处理

接收到数据后,异步处理,你是异步接收的,然后再次加个异步回调处理,我先前就是这样处理的,就没有问题,现在用Delphi开发了,没有那个代码了
hudingwen
2011-06-29 14:03:15
引用 4 楼 djc7811 的回复:
引用 1 楼 bdmh 的回复:

建议,把接收和数据处理分开,接收后放到列表中,单独线程对列表逐个处理

接收到数据后,异步处理,你是异步接收的,然后再次加个异步回调处理,我先前就是这样处理的,就没有问题,现在用Delphi开发了,没有那个代码了

我现在就是异步接收异步回调,关键是我这个缓存机制还是存在线程安全问题,每秒大概100个数据包左右,数据包输入回调是个委托,我记得系统会跟据某些机制开出一条或者更多线程处理这些数据,如果是那样的话,就会有可能多于一条线程进行insert操作,那么就会导致数据包乱序,但是我已加入lock锁,依然有问题
djc7811
2011-06-29 14:13:12
1、发送端发送数据间隔时间长些;
2、接收端用链表接收,边接收边处理数据,接收时Add新数据,处理完毕Delete旧数据
hudingwen
2011-06-29 14:15:26
引用 6 楼 djc7811 的回复:
1、发送端发送数据间隔时间长些;
2、接收端用链表接收,边接收边处理数据,接收时Add新数据,处理完毕Delete旧数据

兄弟,你没看我代码,已是边接收边处理数据,已是接收时add,处理完毕deltete...........关键是我上面说的,线程安全问题
djc7811
2011-06-29 14:17:23
不要加Lock
hudingwen
2011-06-29 14:18:40
引用 8 楼 djc7811 的回复:
不要加Lock

不加lock也会包乱序,我是刚开始没加,出现包乱序,现在加了,仍然包乱序
hudingwen
2011-06-29 14:34:35
哪位兄弟有解决方法呀
hudingwen
2011-06-29 15:07:17
哪位兄弟有解决方法呀
hdw163
2011-06-30 12:43:15
帮顶,望有高手
hudingwen
2011-06-30 13:23:43
我顶呀
FJCfjcFJCfjc
2011-06-30 14:11:12
套接字发送字节流时是根据字节的多少进行多次发送的,所以接收时也要多次接收才行,不然可能有数据丢失问题.
huahua2000
2011-06-30 14:13:12
把你的线程设置为后台线程,处理效率会更快!
hudingwen
2011-06-30 15:35:22
引用 14 楼 fjcfjcfjcfjc 的回复:
套接字发送字节流时是根据字节的多少进行多次发送的,所以接收时也要多次接收才行,不然可能有数据丢失问题.

套接字没丢包,是插缓存时可能由于线程安全问题,导致插包顺序问题,请看前几楼
hudingwen
2011-06-30 16:50:30
引用 15 楼 huahua2000 的回复:
把你的线程设置为后台线程,处理效率会更快!

大哥我需要解决问题的方法。。。
sp1234
2011-06-30 17:06:10
引用 2 楼 hudingwen 的回复:

已分开,你看到的这些代码都是接收后委托了另一个线程进行处理的,也就是说我贴出来的代码都是在另一条线程上,但是不一定是一条线程,系统处理不过来时可能会大于一条线程


你太逗了,这个怎么能“委托了另一个线程进行处理”呢?真是咄咄怪事。我是想不出来,除非你只是为了追时髦,或者你的整个接受代码都是抄别人的。
sp1234
2011-06-30 17:06:58
这也太面向了吧?如果你在另一个线程中处理,你不承担责任吗?
ulihss
2011-06-30 17:10:23
你包乱序是不是因为你的连接是不是断断续续的??
hudingwen
2011-07-01 01:35:23
引用 18 楼 sp1234 的回复:
引用 2 楼 hudingwen 的回复:

已分开,你看到的这些代码都是接收后委托了另一个线程进行处理的,也就是说我贴出来的代码都是在另一条线程上,但是不一定是一条线程,系统处理不过来时可能会大于一条线程


你太逗了,这个怎么能“委托了另一个线程进行处理”呢?真是咄咄怪事。我是想不出来,除非你只是为了追时髦,或者你的整个接受代码都是抄别人的。

我不知道逗在哪?我也不是什么高手。如果你很高手就直接给出方法好了。

以下是我写的关socket的接收,委托部分,至于抄?微软官方有SocketAsyncEventArgs例子,一步一样自己看

而我帖子的第一段代码就是在InputHandler函数内
C# code
     
     
public delegate void InputHandler( byte[] data, SocketAsyncEventArgs socketAsync); public InputHandler Input { get; set; } void BeginReceive(SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success&&e.BytesTransferred> 0) { byte[] data = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, data, 0, data.Length); if ( this.Input != null) this.Input.BeginInvoke(data, e, RecevieCallBack, Input); if (!e.AcceptSocket.ReceiveAsync(e)) { BeginReceive(e); } } }
hudingwen
2011-07-01 01:40:07
引用 20 楼 ulihss 的回复:
你包乱序是不是因为你的连接是不是断断续续的??

不是,长连接,局域网内,没断过,包乱序是我观察后得出的结果,不一定正确,但问了一些人,大多数都认为是因为BuffList的线程安全问题。因为我也不确定BeginInvoke(data, e, RecevieCallBack, Input)后是不是一定是单线程。如果不是的话,是否就有可能导致前面的还没写入,后面的先写入了,导致了包乱序。
hudingwen
2011-07-01 01:47:14
引用 19 楼 sp1234 的回复:
这也太面向了吧?如果你在另一个线程中处理,你不承担责任吗?

我不太清楚你所说的承担责任,我理解是socket本身作为主线程时只需负责好握手,收,发这些基本就好,怎么处理收到的数据,和怎么组成数据发出去都应该由其他来处理,以达到最优化,或许是错的,或许是每个人的理解不一样吧
oONukeOo
2011-07-01 09:14:51
你所看到的"掉包"现象实际上是异步调试出现的问题,实际上包的顺序是对的。。。
建议你仔细检查下GetData()函数,再组包的时候是否情况都考虑到了
csnd_freeman
2011-07-01 10:58:14
刚刚开始学习socket,来关注一下。
tyler3180
2011-07-01 16:35:50

 user.BuffList.InsertByteArray(data); //插入数据包缓冲池
加上互斥
类似生产者与消费者问题
hudingwen
2011-07-01 22:28:26
引用 24 楼 oonukeoo 的回复:
你所看到的"掉包"现象实际上是异步调试出现的问题,实际上包的顺序是对的。。。
建议你仔细检查下GetData()函数,再组包的时候是否情况都考虑到了

确实是异步调用出现的问题,是类似多线程读写的问题,就是说insert数据时,有可能有多于一个异步调用,有可能刚好第二条线程先获取了锁先写了进去,如果不用这种异步调用而用阻塞调用,直接BeginReceive中处理是可以解决这个问题,但是这样无论是效率还是本身架构上都显得不合适。
hudingwen
2011-07-01 22:35:47
引用 26 楼 tyler3180 的回复:
user.BuffList.InsertByteArray(data); //插入数据包缓冲池
加上互斥
类似生产者与消费者问题

你是指在使用 user.BuffList.InsertByteArray(data)时互斥?你说的我可以试试,但我觉得不一定行,因为异步调用Input函数时,Input函数本身是否只在一个线程上工作?如果不在是否会互斥?因为这个方式和我在Bufflist内函数加互斥似乎是一样的,我在BuffList.InsertByteArray(data)内部insert时已经加了锁,看代码
C# code
     
     
public void InsertByteArray( byte[] Data) { lock (locklist) { ByteList.AddRange(Data); } }

按道理来说,如果在需要执行BuffList.InsertByteArray(data)时加锁可以的话,那么当其执行InsertByteArray函数本身时就已经有互斥锁机制了。
hudingwen
2011-07-02 21:42:22
有无高手呀~随便指点指点呀
oONukeOo
2011-07-03 23:57:12
引用 27 楼 hudingwen 的回复:
引用 24 楼 oonukeoo 的回复:
你所看到的"掉包"现象实际上是异步调试出现的问题,实际上包的顺序是对的。。。
建议你仔细检查下GetData()函数,再组包的时候是否情况都考虑到了

确实是异步调用出现的问题,是类似多线程读写的问题,就是说insert数据时,有可能有多于一个异步调用,有可能刚好第二条线程先获取了锁先写了进去,如果不用这种异步调用而用阻塞调用,直接BeginRe……

我们写过类似的代码。。。基本问题都出在处理上而不是想象中的线程问题(我们也是这么猜想的) 后来用了笨办法 在处理过程中添加写LOG 对照LOG测试处理中的问题 如果你还没解决这个问题 建议尝试下
alexccmm
2011-07-04 02:09:49
可能原因、包发太快、n包同时到达
方案一:包与包之间暂停一下下:sleep时间自测罗
方案二:序列化后自己加上包长度、收到包后解出包长度、如果有多的就是下一个包、可就解出下一包、不可就等下一个数据、合包解包、

方案一比较简单
djc7811
2011-07-04 15:19:11
交互模式收发
alexccmm
2011-07-04 15:27:57
发包时断点、看序列化后的大小、
收包后、在断点、看收包后的大小、
看size有没有一样、
过大就是包挤在一块
strife
2011-07-06 09:53:13
看看看看
bei0305
2011-12-04 23:50:03
兄弟你问题解决了吗?
chenandczh
2011-12-05 08:18:22
1.Socket .Accept
判断Socket.Connect
true就接收,结束后到1
false就循环到1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在android中,我们可以使用socket通过网络接收视频数据以播放视频。首先,在android中创建一个socket需使用网络权限。 接下来,我们可以使用MediaPlayer类来播放视频,同时通过socket获取视频数据。建议使用异步线程来处理网络I/O操作。代码示例: ``` //创建socket Socket socket = new Socket(IP, PORT); InputStream inputStream = socket.getInputStream(); //创建MediaPlayer对象 MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(inputStream.getFD()); //异步线程处理网络I/O操作 new Thread(new Runnable() { @Override public void run() { try { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { //将buffer中的数据写入到MediaPlayer中 mediaPlayer.write(buffer, 0, bytesRead); } } catch (IOException e) { e.printStackTrace(); } } }).start(); //开始播放 mediaPlayer.prepare(); mediaPlayer.start(); ``` 需要注意的是,如果通过socket接收的视频数据为流媒体格式,如RTSP或HLS,需要使用相应的协议处理。同时,需要保证网络连接稳定,否则视频播放可能会卡顿或出现播放失败的情况。 ### 回答2: Android 是一款广泛使用的移动操作系统,它拥有强大的网络通信能力,通过 Socket 接收播放视频也变得轻而易举。 在 Android 中,可以使用 Socket 进行网络通信,包括接收和发送数据。要接收播放视频,需要首先建立一个 Socket 连接,然后通过该连接接收视频数据流。 Android 提供了一些网络相关的类和方法,比如 Socket 类、InputStream 和 OutputStream 类等,可以方便地进行 Socket 连接和数据传输。 对于视频播放,Android 中可以使用 MediaPlayer 类来实现,该类封装了视频播放的相关操作。通过设置 MediaPlayer 类的数据源为 Socket 的 InputStream,就可以实现 Socket 接收播放视频了。具体步骤如下: 1. 建立 Socket 连接。 Socket socket = new Socket(ip, port); 2. 获取 Socket 的输入流。 InputStream inputStream = socket.getInputStream(); 3. 创建 MediaPlayer 对象。 MediaPlayer mediaPlayer = new MediaPlayer(); 4. 设置 MediaPlayer 的数据源为 Socket 的输入流。 mediaPlayer.setDataSource(inputStream.getFD()); 5. 准备 MediaPlayer。 mediaPlayer.prepare(); 6. 开始播放视频。 mediaPlayer.start(); 通过上述步骤,即可利用 Socket 接收播放视频。需要注意的是,视频数据流的传输需要保证网络稳定,否则可能会产生卡顿或者播放失败等问题。此外,还需要根据具体业务需求做出相应的优化和处理,比如视频缓存、播放控制等等。 ### 回答3: 在使用 Android 通过 Socket 接收播放视频的过程中,我们需要先使用 Socket 建立连接,然后将视频数据通过 Socket 发送到 Android 设备。接收数据的主要方式有两种,一种是使用 InputStream 对象来进行数据的读取,另外一种是使用 NIO 进行数据读取。 在使用 InputStream 进行数据读取时,我们可以通过循环不断地读取数据并将数据写入到文件中,然后使用 Android 提供的 VideoView 组件来进行视频播放。需要注意的是,在进行数据读取时需要考虑到网络传输中的一些常见问题,例如数据包丢失、网络延迟等情况。 另外,在使用 NIO 进行数据读取时,我们可以将数据读取到内存中,然后再转换成视频文件并进行播放。使用 NIO 的好处在于可以提高数据传输的效率和性能,不过相对来说实现起来也会比较复杂。 总体来说,Android 通过 Socket 接收播放视频的过程相对来说比较繁琐,并且需要考虑到网络传输的不稳定性和数据丢失的风险。因此,在实际开发中需要谨慎考虑这个方案是否适合项目的需求和技术实现能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值