TCP同步连续传输大量数据出现数据不一致现象,求解决方法。

panwen516 2009-01-03 01:44:44
有两个类TCPService与TCPClient,这是我自己封装的两个Socket类,实现的原理是通过多线程实现同步数据通信
第一个类TCPService:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using PDSCommon;
using System.Threading;

namespace BottomCommunicate
{
public class TCPService
{
Socket soc;
const string State = "State";
const string Next = "Next";
const string End = "End";
const string Again = "Again";
IPEndPoint ips = null;
List<Socket> listSocket = new List<Socket>();
private TCPService() { }
public TCPService(string ip, int port)
{
//IPEndPoint ips = null;
try
{
ips = new IPEndPoint(IPAddress.Parse(ip), port);
}
catch
{
MessageBox.Show("IP或端口错误!");
}
soc = new Socket(ips.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public TCPService(IPEndPoint ip)
{
ips = ip;
soc = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
#region ITcpService 成员
void Listen()
{
soc.Bind(ips);
soc.Listen(100);
ThreadPool.QueueUserWorkItem(ListenThread,soc);
}
void ListenThread(object obj)
{
Socket s = (Socket)obj;
Socket target = s.Accept();//当等待客户端连接时会阻塞
AcceptEvent(target);//与客户端建立连接,通知用户
listSocket.Add(target);
}
public bool Accept()
{
try
{
Listen();
return true;
}
catch (Exception ex)
{
MessageBox.Show("<TCPService,Accept>:" + ex.Message);
return false;
}
}

public event acceptSocket AcceptSocket;
void AcceptEvent(Socket target)
{
if (AcceptSocket != null)
AcceptSocket(target);
}

public bool Send(Socket target, byte[] data)
{
return Send(target, data, SocketFlags.None);
}

public bool Send(Socket target, byte[] data, SocketFlags socketflags)
{
lock (new object())
{
try
{
StateObject stateobject = new StateObject();
stateobject.target = target;
stateobject.data = data;
stateobject.socketflags = socketflags;
ThreadPool.QueueUserWorkItem(SendData, stateobject);
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
}
void SendData(object obj)
{
StateObject state = (StateObject)obj;
state.All = SendDegree(state.data);
state.target.Send(SendInfo(State));
bool ifend = false;
while (true)
{
byte[] info = new byte[CommonData.Size];//CommonData.Size = 1024;
state.target.Receive(info);
string infoData = ConversionControl.ReceiveConversion(info);
string[] array = infoData.Split(new string[] { "\0" }, StringSplitOptions.None);
switch (array[0])
{
//case State: break;
case Next: SendNextMethod(state); break;
case End: ifend = EndMethod(state); break;
}
if (ifend)
break;
}
}
#region 发送数据处理函数
int SendDegree(byte[] data)
{
//CommonData.Size = 1024
int count = data.Length / CommonData.Size;
if ((data.Length % CommonData.Size) > 0)
{
count++;
}
return count;
}
void SendNextMethod(StateObject state)//同步分段发送数据
{
if (state.currentCount < state.All)
{
if (state.currentCount + 1 != state.All)
state.target.Send(state.data, state.currentCount * CommonData.Size, CommonData.Size, state.socketflags);
else
if (state.data.Length > CommonData.Size)
state.target.Send(state.data, state.currentCount * CommonData.Size, state.data.Length - state.currentCount * CommonData.Size, state.socketflags);
else
state.target.Send(state.data,0,state.data.Length, state.socketflags);
state.currentCount++;
}
else
{
state.target.Send(SendInfo(End));
}
}
bool EndMethod(StateObject state)
{
state = null;
return true;
}
byte[] SendInfo(string info)//发送信号
{
byte[] by = new byte[CommonData.Size];
ConversionControl.SendConversion(info).CopyTo(by, 0);
return by;
}
#endregion
class StateObject
{
public Socket target;
public byte[] data;
public SocketFlags socketflags;
public int All;
public int currentCount;
}
#endregion

#region ITcpService 成员


public void Close()
{
for (int i = 0; i < listSocket.Count; i++)
{
listSocket[i].Shutdown(SocketShutdown.Both);
listSocket[i].Close();
}
soc.Close();
}

#endregion

#region IDisposable 成员

public void Dispose()
{
Close();
}

#endregion
}
}
...全文
715 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
happytostar 2012-01-12
  • 打赏
  • 举报
回复
数据包到达时间的问题,比如你接收到数据包A,然后给服务器发送一个确认包,表面上看很合理,但是你接收到的A不见得是服务器发给你的第一个包,你对A的确认信息也不见得服务器可以第一时间接收到,这样就会造成一个时间差,这时就会出现接收N个A的情况,如果你不对这些数据包的顺序做出处理的话就会出现你这个情况。
panwen516 2009-01-06
  • 打赏
  • 举报
回复
没人吗?自己顶自己
panwen516 2009-01-05
  • 打赏
  • 举报
回复
用异步写要处理不同电脑之间线程同步的事,比同步发送更麻烦。如果这个方法不行,我只有用异步发送数据了,问题是这个问题我不搞清楚心里不舒服。
都几天了都没有一个人知道原因在那吗?同事叫我来CSDN说高手多,唉~~~~~~~~~~~~~
bbbbbb888888 2009-01-04
  • 打赏
  • 举报
回复
多看看异步socket是怎么作的。
panwen516 2009-01-04
  • 打赏
  • 举报
回复
我在传大量数据时,客户端用List<byte>来作缓冲区,所以在Text_Client例子中,用户收到的是一个完整的数据。当然,在服务端连续发送时就会有问题,还不知道这个问题怎么解决了。
项目急呀。。。。
都没有人知道的吗?
jscn123789abc 2009-01-03
  • 打赏
  • 举报
回复
具体原因不太明白,只知道之前同事传输大量数据总喜欢开辟缓冲区...
china_west 2009-01-03
  • 打赏
  • 举报
回复
不懂,帮顶
jf
GTX280 2009-01-03
  • 打赏
  • 举报
回复
楼主这个应该是传输速度太慢导致的数据不同步,试试吧
GTX280 2009-01-03
  • 打赏
  • 举报
回复
将Size设大一点(1024*100),速度会快点吧,前两天看到过一个类似的问题
panwen516 2009-01-03
  • 打赏
  • 举报
回复
我改了还是不行,我用的是单独线程的同步做法。他的问题跟我的问题不是同一个问题。
慢慢发送数据就没有问题(发送一次,等到客户端接收到后在发第二次没有问题的,但连续发送就出问题了)
我知道是同步的问题,代码也跟了是连续发送时其他线程的值改变了当前线程的值(不是单个线程里的变量不会影响到其他线程的变量的吗?变量是线程内的局部变量),所以发送就乱了,但不知道怎么改。
panwen516 2009-01-03
  • 打赏
  • 举报
回复
根据上面TCPService与TCPClient来实现的例子:
服务端Text_Service例子:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PDSCommon;
using BottomCommunicate;
using System.Net;
using System.Net.Sockets;
namespace Text_Service
{
public partial class Form1 : Form//其实这个服务端窗体只有RichTextBox,Lable,Botton三个控件
{
TCPService serive;
Socket soc;
int n = 0;//为了记录发送数据的次数
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
serive = new TCPService("192.168.8.9",8049);//这个IP与端口根据你们自己的来实现
serive.AcceptSocket += new acceptSocket(serive_AcceptSocket);
serive.Accept();
}

void serive_AcceptSocket(System.Net.Sockets.Socket target)//当接受了客户端的连接时就会触发这个事件,所以可以连接多个客户端
{
soc = target;//如果想连接多客户端可以用List<Socket>来实现这里
}

/// <summary>
/// 这是发送按钮的事件方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
serive.Send(soc, ConversionControl.SendConversion(SendRichText.Rtf));//SendRichText是RichTextBox控件
n++;
label1.Text = n.ToString();//Label控件是为了记录服务端向客户端发送了多少次数据,是否跟客户端接收次数一样
}


}
}

客户端Text_Client例子:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PDSCommon;
using BottomCommunicate;

namespace Text_Client
{
public partial class Form1 : Form//客户端窗体只有RichTextBox,Lable两个控件
{
TCPClient client;
int n = 0;//记录接收数据次数,是否与服务端发送次数一致
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
client = new TCPClient("192.168.8.9", 8049);
client.Receive += new receiveData(client_Receive);//接收数据事件,这个事件的触发是等一次发送的大量数据都传完后才会触发的,所以客户端接收到的是一个完整的数据btye[].
client.Connection();
}

void client_Receive(byte[] data)
{
ReceiveRichText.Rtf = ConversionControl.ReceiveConversion(data);//将字节数据转换成字符串
n++;
label1.Text = n.ToString();
}
}
}

大家将程序服务端与客户端两个程序跑起来,然后由服务端向客户端发送数据(什么都可以),如果发送数据大小不超过CommonData.Size(我定的大小是1024)的大小时不管服务端发送多少次,客户端都能接收到。但如果发送图片(最好用桌面的截图,因为这样发送的数据量很大效果明显),当服务端不连续发送时,客户端都能正确接收(客户端需要等待2-3秒才能接收到整张截图),但如果服务端连续发送的话,客户端就接收不到正确的数据了。我跟了代码,还是同步的问题,但不知道怎么解决。希望高手指点,项目急~~~~~~~~~~~~~~~~~~~~~~~~~~~
panwen516 2009-01-03
  • 打赏
  • 举报
回复
第二个类:TCPClient
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using PDSCommon;
using System.Threading;

namespace BottomCommunicate
{
public class TCPClient
{
Socket soc;
IPEndPoint ips = null;
const string State = "State";
const string Next = "Next";
const string End = "End";
const string Again = "Again";
private TCPClient() { }
public TCPClient(string ip, int port)
{
try
{
ips = new IPEndPoint(IPAddress.Parse(ip), port);
}
catch
{
MessageBox.Show("IP或端口错误!");
}
soc = new Socket(ips.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public TCPClient(IPEndPoint ip)
{
ips = ip;
soc = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
#region ITcpClient 成员

public bool Connection()
{
try
{
ThreadPool.QueueUserWorkItem(ConnectionRun, null);//异步连接并且同步接收数据
return true;
}
catch (Exception ex)
{
MessageBox.Show("<TCPClient, Connection>" +ex.Message);
return false;
}

}
void ConnectionRun(object obj)
{
soc.Connect(ips);
if (soc.Connected)
ReceiveData();//同步接收数据
}
void ReceiveData()
{
List<byte> listbyte = new List<byte>();
while (true)
{
byte[] by = new byte[CommonData.Size];
soc.Receive(by);
string infodata = ConversionControl.ReceiveConversion(by);
string[] array = infodata.Split(new string[] { "\0" }, StringSplitOptions.None);
switch (array[0])
{
case State: soc.Send(SendInfo(Next)); break;
case End: EndMethod(listbyte); break;//一次通信结束,并且等待下次通信开始
default: listbyte.AddRange(by); soc.Send(SendInfo(Next)); break;
}
}
}
byte[] SendInfo(string info)//发送信号
{
byte[] by = new byte[CommonData.Size];
ConversionControl.SendConversion(info).CopyTo(by,0);
return by;
}
void EndMethod(List<byte> listbyte)//一次通信结束
{
ReceiveEvent(listbyte.ToArray());
listbyte.Clear();
soc.Send(SendInfo(End));
}
public event receiveData Receive;
void ReceiveEvent(byte[] data)
{
if (Receive != null)
Receive(data);
}
#endregion

#region ITcpClient 成员


public void Close()
{
soc.Close();
}

#endregion

#region IDisposable 成员

public void Dispose()
{
Close();
}

#endregion
}
}

第三个类CommonData:
using System;
using System.Collections.Generic;
using System.Text;

namespace PDSCommon
{
public static class CommonData
{
public const int Size = 1024;
}
}

第四个类ConversionControl:
using System;
using System.Collections.Generic;
using System.Text;

namespace PDSCommon
{
public static class ConversionControl
{
public static string ReceiveConversion(byte[] data)
{
return Encoding.Default.GetString(data);
}
public static byte[] SendConversion(string data)
{
return Encoding.Default.GetBytes(data);
}
}
}

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧