socket 异步接收大数据包问题
Korny 2004-10-23 03:11:24 问题描述:在TCP socket 异步接收中,假设客户端向服务器发送一个大数据包,服务器必须分次用beginreceive来接收,有两个方试可以判断一个包是否已经接收完整,一是在流里先写入包的大小,二是在流里写入结束标志符。我现在采用第1种情况,但出现错误,提示是序列化时,我估计是包没有收完整。下面我贴出关键代码,请大家分析一下,是否正确? 以及如何解决服务器异步接收大包的情况?
//单个用户的socket
public class StateObject
{
public bool connected = false; // ID received flag
public Socket workSocket = null; // Client socket.
public Socket partnerSocket = null; // Partner socket.
public const int BufferSize = 4; // Size of receive buffer.
public byte[] buffer = new byte[BufferSize];// Receive buffer.
public StringBuilder sb = new StringBuilder();//Received data String.
public string id = String.Empty; // Host or conversation ID
public DateTime TimeStamp;
/*zsb*/
public byte[] MessBuffer;
public bool AllDataReceived=true;
public int DataSize;
public int DataLeft;
public int DataCurrentTotal;
}
//服务器接收数据
protected void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the async state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
try
{
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
/*zsb*/
Console.WriteLine("这次实际收到:"+bytesRead.ToString());
if(state.AllDataReceived) //上条数据全部收到,意味着新数据的开始
{
//recv=handler.Receive(datasize,0,4,0);
int size=BitConverter.ToInt32(state.buffer,0);
Console.WriteLine("消息大小:"+size.ToString());
state.DataSize=size;
state.MessBuffer=new byte[state.DataSize];
state.DataCurrentTotal=0;
state.DataLeft=size;
state.AllDataReceived=false;
state.DataCurrentTotal+=bytesRead;
state.DataLeft-=bytesRead;
//去收
handler.BeginReceive(state.MessBuffer, state.DataCurrentTotal, state.DataLeft, 0, new AsyncCallback(this.ReadCallback), state);
}
else
{
state.DataCurrentTotal+=bytesRead;
state.DataLeft-=bytesRead;
}
if(state.DataCurrentTotal>=state.DataSize)//数据已经完整
{
Console.WriteLine("数据已经完整");
state.AllDataReceived=true;
SerialMessage sm=new SerialMessage();
sm=(SerialMessage)OperMess.DecodingMessage(state.MessBuffer,0,state.MessBuffer.Length);
if(sm.ExecAction=="USER_LOGIN") //这里抢先注册,此时有sokcet
{
this.RegisterToUserHT_USERLOING(sm, state);
}
else
{
MessageQueue.Enqueue(sm);
}
// Console.WriteLine("去收前4个字节");
// handler.BeginReceive(state.buffer, 0, 4, 0,
// new AsyncCallback(this.ReadCallback), state);
}
else
{
Console.WriteLine("再去收");
handler.BeginReceive(state.MessBuffer, state.DataCurrentTotal, state.DataLeft, 0, new AsyncCallback(this.ReadCallback), state);
}
}//bytesRead >0
else
{ // Disconnected
this.RemoveUserFromState(state);
}
}
catch (System.Net.Sockets.SocketException es)
{
this.RemoveUserFromState(state);
if (es.ErrorCode != 64)
{
Console.WriteLine( string.Format("ReadCallback Socket Exception: {0}, {1}.", es.ErrorCode, es.ToString()));
}
}
catch (Exception e)
{
this.RemoveUserFromState(state);
if (e.GetType().FullName != "System.ObjectDisposedException")
{
Console.WriteLine(string.Format("ReadCallback Exception: {0}.", e.ToString()));
}
}
}