Socket通信连续接收数据不流畅,求解惑!!!
做一个Socket通信的功能,客户端是Android手机,用Java写的代码,服务端暂时是用C#开发的Winform程序(局域网内WIFI进行数据传输)。但是接收数据的时候,数据在文本框中是一块一块出来的,很不流畅。上个图:前三列数据是Android手机发送的数据(重力加速度计的数据,这个不重要),第四列输出的是两帧数据之间的时间差(单位ms),相关代码如下:
while (socketStatus)
{
SocketPacket sPacket = new SocketPacket();
sPacket.workSocket = listener.Accept();
Socket handler = sPacket.workSocket;
timeOld = DateTime.Now;
while (true)
{
try
{
int numBytes = sPacket.workSocket.Receive(sPacket.buffer);
if (numBytes == 40)
{
//accelerometer in units (m/s^2)
float ax = BitConverter.ToSingle(sPacket.buffer, 0);
float ay = BitConverter.ToSingle(sPacket.buffer, 4);
float az = BitConverter.ToSingle(sPacket.buffer, 8);
float gx = BitConverter.ToSingle(sPacket.buffer, 12);
float gy = BitConverter.ToSingle(sPacket.buffer, 16);
float gz = BitConverter.ToSingle(sPacket.buffer, 20);
float mx = BitConverter.ToSingle(sPacket.buffer, 24);
float my = BitConverter.ToSingle(sPacket.buffer, 28);
float mz = BitConverter.ToSingle(sPacket.buffer, 32);
timeNew = DateTime.Now;
AppendToTxt(ax.ToString("0.00") + "\t" + ay.ToString("0.00") + "\t" + az.ToString("0.00") + "\t" + (timeNew - timeOld).TotalMilliseconds + "\r\n");
timeOld = timeNew;
//Send(handler, "OK");
}
else if (numBytes == 0)
{
break;
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
break;
}
}
}
可以看出接收数据的时间间隔很不稳定,具体的视觉效果,看起来在textBox框中数据是一下子整块跳出来的。上面相关的Send代码我注释掉了,如果加上去,数据反而看起来流畅了很多。
Send方法:
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
}
catch (Exception ex)
{
throw ex;
}
}
如果每次接收完数据后,就进行一次Send,数据看起来就是这样的:
因为在Android手机上,每次发送完收据后sleep(9),加上程序运行的时间,所以时间间隔是10ms左右,这样子在WINFORM上看起来数据就是很流畅的流下去。
但是我并不需要向客户端发送数据,服务端只需要接收并处理数据就好了,为什么会出现这种情况呢???
一开始我以为是异步接收数据的问题,后来我重写了服务端的C#代码,不管是同步接收还是异步接收数据都是这样的情况。
会不会和TCP的握手协议有关呢???求解惑!!! 通信 socket 数据 --------------------编程问答-------------------- tcp/ip 如果2次发送时间间隔很短 会在缓冲满了以后在发送 --------------------编程问答--------------------
1. 缓冲大小是用ReceiveBufferSize设置的吗?
2. 一帧数据40Byte,我设置ReceiveBufferSize = 40,速度更慢了。。。
3. 还是不明白为什么加上Send后数据就出现的流畅了...
4. 感谢回答。。。 --------------------编程问答-------------------- 那个不叫流程。原来是一下子连续得到20个消息(在非常不精确的DataTime类型的对象的误差范围之内)。现在每得到一个消息都卡了一下下,这样你的Send语句是让程序变得更慢了,而不是变快了。 --------------------编程问答-------------------- 从你两个图来看,接收速度都很慢,但是基本上是一样速度的。
你可以试试把 AppendToTxt 仅仅记录在内存中,而不是写到窗口UI控件上,看看结果如何。 --------------------编程问答--------------------
理论上应该是像你说的这样,而且一开始我也是这么认为的(Send会让程序变慢)。
因为客户端每次固定发送40个Byte数据,我把服务端接收buffer大小设置为40。
class SocketPacket
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 40;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
这样仍然达不到我所说的那种数据流畅的效果。
2. 关于你所说的记录在内存中,查看效果,我尝试过下面的做法:
让数据控制鼠标的移动(不在UI控件上显示),如果不加Send,鼠标指针一卡一卡的,那种卡的感觉就像内存不够用了似的~加上Send语句后鼠标反而移动的很流畅。 --------------------编程问答-------------------- 楼主:TCP的数据是以流的形式发送和接收的,所以不应该判断某一次接收的数据大小是否为40,而是应该把收到的数据进行累计,满到40个的时候显示,其实满到4个就可以了。
楼主的这种用法实际上是丢失了很多数据。 --------------------编程问答--------------------
沉了???自己水起…… --------------------编程问答-------------------- 你这个接收数据缓存区不应该设置为40,应该设置1024或更大些。每次接收到数据时,是可以判断总共接收了多少个有效数据位的,然后将有效数据提取存入缓存内,而每次存入数据到缓存后,进行数据有效性检查,有效则取出然后输出到其他地方,比如UI。
具体可参考:C#通讯调试工具v3.0中TCP部分。 --------------------编程问答--------------------
当我设置成1024的时候,每次接收的有效数据位都是40的倍数(一般是40,80,120,很少有超过120的),为了显示数据传输的实时性,我就直接设置成40了~而且设置成1024并没有解决我上面所述的问题啊…… --------------------编程问答--------------------
你还是不明白缓存的作用,你说能收到的数据位数是40的倍数,那你一次接收即可处理多条数据,而你为什么非得拆成几个40来处理呢?你可以先拿我那个工具调试看看。 --------------------编程问答--------------------
两个问题:
1. 通讯调试工具v3.0 每次大概接收800个字节(有时候是840或者更多),跟我在1楼说的情况很想,数据是一块一块的跳出来的,虽然这样加快了处理速度,但是实时性并不高(下位机每次发送40个字节),我想要的是实时性处理的,有个几毫秒的延迟没有关系。
2. 不知道是不是我的使用方法有问题,停止监听了以后,仍然还在接收数据。文本框还是不断刷新。
3. 非常感谢你的回答~ --------------------编程问答--------------------
当我设置成1024的时候,每次接收的有效数据位都是40的倍数(一般是40,80,120,很少有超过120的),为了显示数据传输的实时性,我就直接设置成40了~而且设置成1024并没有解决我上面所述的问题啊……
你还是不明白缓存的作用,你说能收到的数据位数是40的倍数,那你一次接收即可处理多条数据,而你为什么非得拆成几个40来处理呢?你可以先拿我那个工具调试看看。
两个问题:
1. 通讯调试工具v3.0 每次大概接收800个字节(有时候是840或者更多),跟我在1楼说的情况很想,数据是一块一块的跳出来的,虽然这样加快了处理速度,但是实时性并不高(下位机每次发送40个字节),我想要的是实时性处理的,有个几毫秒的延迟没有关系。
2. 不知道是不是我的使用方法有问题,停止监听了以后,仍然还在接收数据。文本框还是不断刷新。
3. 非常感谢你的回答~
1,该工具就是实事求是的显示每次接收到的数据。至于你说的实时性并不高,我不太懂你的具体指向。
2,停止监听,跟断开TCP连接是两码事。你若要断开连接,可以右击TCP连接对象列表操作。 --------------------编程问答-------------------- 我仔细看了下你之前帖子内容,似乎你所说的流畅就是数据是一条,一条,有规律的在文本框里显示?这根不是不是真正的所谓实时性。 --------------------编程问答-------------------- Java客户端每次发送数据是否有Refresh? --------------------编程问答--------------------
我仔细看了下你之前帖子内容,似乎你所说的流畅就是数据是一条,一条,有规律的在文本框里显示?这根不是不是真正的所谓实时性。
额 是这样的,我下位机每次(约10ms间隔)发送40个字节,在PC机Server端接收数据后要进行相应的数据处理,我希望接收到40个字节后立即进行数据处理。现在遇到的状态是每次从缓存中读取的数据都是40个N倍,也就是缓存中存储了N帧的数据。所以我才把缓存大小设置成了40.
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的。。。 --------------------编程问答--------------------
Java客户端每次发送数据是否有Refresh?
public void run() {
try {
PORT = Integer.parseInt(port.getText().toString());
serverIpAddress = ipAdr.getText().toString();
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
socket = new Socket(serverAddr, PORT);
connected = true;
outputStream = new DataOutputStream(socket.getOutputStream());
while (connected) {
if (connected && outputStream != null) {
byte[] byte_ax = float2byte(ax);
byte[] byte_ay = float2byte(ay);
byte[] byte_az = float2byte(az);
byte[] byte_gx = float2byte(gx);
byte[] byte_gy = float2byte(gy);
byte[] byte_gz = float2byte(gz);
byte[] byte_mx = float2byte(mx);
byte[] byte_my = float2byte(my);
byte[] byte_mz = float2byte(mz);
byte[] btemp = new byte[40];
for (int i = 0; i < 4; i++) {
btemp[i] = byte_ax[i];
btemp[i + 4] = byte_ay[i];
btemp[i + 8] = byte_az[i];
btemp[i + 12] = byte_gx[i];
btemp[i + 16] = byte_gy[i];
btemp[i + 20] = byte_gz[i];
btemp[i + 24] = byte_mx[i];
btemp[i + +28] = byte_my[i];
btemp[i + 32] = byte_mz[i];
}
outputStream.write(btemp);
outputStream.flush();
Thread.sleep(9);
}
}
} catch (Exception e) {
refreshDisplay(e.getMessage());
} finally {
try {
info_disp = false;
connected = false;
connectPhones.setText("Start Streaming");
outputStream.close();
socket.close();
} catch (Exception a) {
}
}
}
你说的是上面的outputStream.flush();吗?
数据refresh的频率很高,发送的是Android手机传感器的数据。。。 --------------------编程问答--------------------
我仔细看了下你之前帖子内容,似乎你所说的流畅就是数据是一条,一条,有规律的在文本框里显示?这根不是不是真正的所谓实时性。
额 是这样的,我下位机每次(约10ms间隔)发送40个字节,在PC机Server端接收数据后要进行相应的数据处理,我希望接收到40个字节后立即进行数据处理。现在遇到的状态是每次从缓存中读取的数据都是40个N倍,也就是缓存中存储了N帧的数据。所以我才把缓存大小设置成了40.
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的。。。
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。 --------------------编程问答-------------------- 有一个问题,你的第二个图的时间差很怪异,windows的C#的DateTime.Now没有这个精确度。 --------------------编程问答--------------------
有一个问题,你的第二个图的时间差很怪异,windows的C#的DateTime.Now没有这个精确度。
你是说10ms左右吗?
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。 --------------------编程问答-------------------- 另外windows不是一个实时操作系统,if (numBytes == 40)这个判断可能过滤掉了很多有效数据,TCP粘包是很正常的,必须要考虑的。 --------------------编程问答--------------------
我仔细看了下你之前帖子内容,似乎你所说的流畅就是数据是一条,一条,有规律的在文本框里显示?这根不是不是真正的所谓实时性。
额 是这样的,我下位机每次(约10ms间隔)发送40个字节,在PC机Server端接收数据后要进行相应的数据处理,我希望接收到40个字节后立即进行数据处理。现在遇到的状态是每次从缓存中读取的数据都是40个N倍,也就是缓存中存储了N帧的数据。所以我才把缓存大小设置成了40.
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的。。。
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。
你意思是,加上Send虽然看起来流畅了,其实是传输速度变慢了??? --------------------编程问答--------------------
有一个问题,你的第二个图的时间差很怪异,windows的C#的DateTime.Now没有这个精确度。
你是说10ms左右吗?
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
windows不是实时系统,我是说两个DateTime.Now的差没有这个精度。一般都是15ms或者10ms左右的一个比较稳点的值。 --------------------编程问答--------------------
另外windows不是一个实时操作系统,if (numBytes == 40)这个判断可能过滤掉了很多有效数据,TCP粘包是很正常的,必须要考虑的。
恩 有考虑到, 40正好是我这里一个包的大小,不多不少~
最开始我写的是if (numBytes > 0),效果是一样的。。。 --------------------编程问答--------------------
有一个问题,你的第二个图的时间差很怪异,windows的C#的DateTime.Now没有这个精确度。
你是说10ms左右吗?
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
你的第二个图显示出,时间差的精度达到1ms了,很是奇怪。 --------------------编程问答--------------------
有一个问题,你的第二个图的时间差很怪异,windows的C#的DateTime.Now没有这个精确度。
你是说10ms左右吗?
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
你的第二个图显示出,时间差的精度达到1ms了,很是奇怪。
应该是10ms左右,没有1ms啊???
而且输出时间差只是为了和第一个图比较~ 呵呵 没啥别的意思 --------------------编程问答--------------------
我仔细看了下你之前帖子内容,似乎你所说的流畅就是数据是一条,一条,有规律的在文本框里显示?这根不是不是真正的所谓实时性。
额 是这样的,我下位机每次(约10ms间隔)发送40个字节,在PC机Server端接收数据后要进行相应的数据处理,我希望接收到40个字节后立即进行数据处理。现在遇到的状态是每次从缓存中读取的数据都是40个N倍,也就是缓存中存储了N帧的数据。所以我才把缓存大小设置成了40.
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的。。。
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。
已验证过,好使!不过定时时间不好掌握啊,毕竟不是均匀的10MS~ --------------------编程问答--------------------
应该是10ms左右,没有1ms啊???
而且输出时间差只是为了和第一个图比较~ 呵呵 没啥别的意思
我是说两个DateTime.Now的差 9,10,11,12 ms都有,很奇怪。要得到这样的差,时间精度必须达到1ms以上。
否则就应该是固定的 10.XXXms 与 0ms 交替出现。 --------------------编程问答--------------------
应该是10ms左右,没有1ms啊???
而且输出时间差只是为了和第一个图比较~ 呵呵 没啥别的意思
我是说两个DateTime.Now的差 9,10,11,12 ms都有,很奇怪。要得到这样的差,时间精度必须达到1ms以上。
否则就应该是固定的 10.XXXms 与 0ms 交替出现。
这个我觉得很正常吧,你在下位机持续发送数据,中间sleep(10),应该也会得到这样子~ --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 没有人讨论了??? --------------------编程问答-------------------- 建议去看下ESFramework框架中对于数据的发送和接受的高效处理方法,也许会给你带来启发。 --------------------编程问答-------------------- 多线程才行。
补充:.NET技术 , C#