C# socket 异步服务端丢失数据

iccarm 2010-01-22 05:21:32
C#通过socket 异步传输数据功能已实现,但网络网速不好的情况下会出现 客户端发送数据成功,但服务端接口不到,重启下服务端有能正常接收数据,请问一下如何才能避免网络不好的情况下数据正常接收?先谢了

一下是我的代码---------------------------------------

服务端代码 用线程调用 Listen()方法

private void Listen()
{

string strIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
if (strIP.Length < 9)
{
strIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[1].ToString();
}

IPAddress ip = IPAddress.Parse(strIP);
IPEndPoint ipe = new IPEndPoint(ip, 8889);
sockets = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sockets.Bind(ipe);
sockets.Listen(500);
while (isRun)
{
Control.CheckForIllegalCrossThreadCalls = false;

try
{
allDone.Reset();
sockets.BeginAccept(new AsyncCallback(AcceptCallback), sockets);
allDone.WaitOne();
}
catch
{

}
}

}
private void AcceptCallback(IAsyncResult ar)
{
try
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);

StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch
{

}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
string content = string.Empty;

StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);

if (bytesRead > 0)
{
state.sb.Append(Encoding.Default.GetString(state.buffer, 0, bytesRead));

string info = state.sb.ToString();

}
}
}
catch
{ }
}


客户端能正常发送数据,服务端偶尔会出现接收不到数据。

希望大家能帮我看看代码是不是有什么问题? 最好能够给点参考代码就最好了
...全文
216 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
hhc123 2010-01-26
  • 打赏
  • 举报
回复
cuike519 2010-01-26
  • 打赏
  • 举报
回复
楼主参考一下TCP如何建立可靠的连接吧,你可以实现一个简化版本。
lbkmaster 2010-01-26
  • 打赏
  • 举报
回复
他这种情况应该是在网络不稳定时候发生,所以设一个接收TIMEROUT就应该可以解决
bonylee 2010-01-26
  • 打赏
  • 举报
回复
加lock
private static readonly object objLock = new object();

lock(objlock)
{
//接受的方法
}
  • 打赏
  • 举报
回复
当SOCKET传送数据的时候,一般来说,你需要构建自己的消息体,比如,我的消息体是如下定义的:
消息类型-消息长度-消息本身
这样,你在取数据的时候,就可以取到很确切的消息长度,接收方根据这个长度去获取消息本身就行。
如下代码段:
recv = _currentSocket.Receive(dataType, 0, 4, 0);
if (recv == 0)
throw new Exception("receive dataType broken.");
recv = _currentSocket.Receive(datasize, 0, 4, 0);
if (recv == 0)
throw new Exception("receive dataSize broken.");
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;

byte[] data = null;
if (Encoding.ASCII.GetString(dataType, 0, recv) == "data")
{
data = new byte[size];
while (total < size)
{
recv = _currentSocket.Receive(data, total, dataleft, 0);
if (recv == 0)
throw new Exception("receive data broken.");
total += recv;
dataleft -= recv;
}
total = 0;
dataleft = 0;
_receivedData(_connectIndex, Encoding.ASCII.GetString(data));
Debug.Print("data = " + Encoding.ASCII.GetString(data));
}
先获取dataType,再获取datasize,继而获取data本身,具体参考下面的博文

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luminji/archive/2008/12/25/3606072.aspx
wenbin 2010-01-26
  • 打赏
  • 举报
回复
先发数据包的长度,再发送这个包

接收时就先接收包长度,再按照这个长度进行接收。
fengyoujie 2010-01-26
  • 打赏
  • 举报
回复
帮楼主顶了。
lbkmaster 2010-01-26
  • 打赏
  • 举报
回复
当SOCKET传送数据的时候,一般来说,你需要构建自己的消息体,比如,我的消息体是如下定义的:
消息类型-消息长度-消息本身
这样,你在取数据的时候,就可以取到很确切的消息长度,接收方根据这个长度去获取消息本身就行。
如下代码段:
recv = _currentSocket.Receive(dataType, 0, 4, 0); //1
if (recv == 0)
throw new Exception("receive dataType broken.");
recv = _currentSocket.Receive(datasize, 0, 4, 0); //2 if (recv == 0)
throw new Exception("receive dataSize broken.");
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;

byte[] data = null;


实际操作过程中 红色1和红色2存在问题:
1.当发送端发送完第一次数据后, 触发红1动作,但如果发送端马上发送第二次数据,由于接收端还没有开启第二次接收,这样数据包就会丢失,或者红1动作后处理数据过慢,而发送端还在不停地发送数据包,那红2就会接收到多次发送的数据包,所以在发送数据时要控制好时间,我的方法是每接收到一次数据包处理完后开启第二次接收同时发送确认数据包到发送端,发送端收到确认包后才发送数据。


Dim ReceMsgtemp() As Byte = Encoding.UTF8.GetBytes("Rcomplit")
Dim lint As Integer = newsocket.Receive(snbyte, 1024, SocketFlags.None)
If lint > 0 Then
sn = Encoding.UTF8.GetString(snbyte, 0, lint)
end If
Dim computconfigbyte(1024) As Byte
newsocket.Send(ReceMsgtemp)
lint = newsocket.Receive(computconfigbyte, 1024, SocketFlags.None)
If lint > 0 Then
computconfigtemp = Encoding.UTF8.GetString(computconfigbyte, 0, lint)
computconfig += computconfigtemp
End If
lbkmaster 2010-01-26
  • 打赏
  • 举报
回复
。。。。。。。。。。设置一个TIMEROUT,触发异常时重新发送和接收,不就OK了?建议不要用异步接收,难控件,我做过一个后来全改为倾听连接后开一个线程,接收其它数据而不使用异步接收

111,120

社区成员

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

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

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