做一个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数据
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数据
2. 一帧数据40Byte,我设置ReceiveBufferSize = 40,速度更慢了
3. 还是不明白为什么加上Send后数据就出现的流畅了...
4. 感谢回答
因为客户端每次固定发送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语句后鼠标反而移动的很流畅。
楼主的这种用法实际上是丢失了很多数据。
具体可参考:C#通讯调试工具v3.0中TCP部分。
两个问题:
1. 通讯调试工具v3.0 每次大概接收800个字节(有时候是840或者更多),跟我在1楼说的情况很想,数据是一块一块的跳出来的,虽然这样加快了处理速度,但是实时性并不高(下位机每次发送40个字节),我想要的是实时性处理的,有个几毫秒的延迟没有关系。
2. 不知道是不是我的使用方法有问题,停止监听了以后,仍然还在接收数据。文本框还是不断刷新。
3. 非常感谢你的回答~
1,该工具就是实事求是的显示每次接收到的数据。至于你说的实时性并不高,我不太懂你的具体指向。
2,停止监听,跟断开TCP连接是两码事。你若要断开连接,可以右击TCP连接对象列表操作。
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的
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手机传感器的数据
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。你意思是,加上Send虽然看起来流畅了,其实是传输速度变慢了???
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
windows不是实时系统,我是说两个DateTime.Now的差没有这个精度。一般都是15ms或者10ms左右的一个比较稳点的值。
最开始我写的是if (numBytes > 0),效果是一样的
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
你的第二个图显示出,时间差的精度达到1ms了,很是奇怪。
代码也在上面,(timeNew - timeOld).TotalMilliseconds
不是DateTime.Now,应该是DateSpan.TotalMilliseconds的数值。
你的第二个图显示出,时间差的精度达到1ms了,很是奇怪。
应该是10ms左右,没有1ms啊???
而且输出时间差只是为了和第一个图比较~ 呵呵 没啥别的意思
额 不过貌似跑题了 我在1楼说的主要问题是:即使设置缓存大小40,如果在每次接收数据后不加Send,数据仍然是一卡一卡的
这个不是数据一卡一卡,实时情况就是接收数据的频率有这么快。如果你非得人为的把数据分割规律显示,那你就先存入缓存,然后再由UI定时10MS取一条来显示好了。已验证过,好使!不过定时时间不好掌握啊,毕竟不是均匀的10MS~
否则就应该是固定的 10.XXXms 与 0ms 交替出现。
否则就应该是固定的 10.XXXms 与 0ms 交替出现。这个我觉得很正常吧,你在下位机持续发送数据,中间sleep(10),应该也会得到这样子~