========用TCPCLient发送数据丢失问题??

lz_0618 2009-04-24 10:48:20
服务器端采用的异步Socket,
客户端使用的是TCPClient类,采用的是短连接,也就是说连接和关闭都写在一个函数中了:
1,实例化TCPClient
2,设定读取和发送超时都为500,连接
3,获取NetStream
4,发送数据
5,读取服务器返回内容(服务器原样返回)
6,关闭连接

问题是:在服务器端都能监控到Socket的连接和关闭连接,但偶尔出现接收不到数据的问题,从而引起客户端读超时,而且手工测试(点一下鼠标发送一个)时(服务器压力不大),也出现错误,在一个循环中连续发送,出现错误的概率也差不多,甚至还要少,真奇怪了??
SOCKET不是可靠通讯吗,怎么会这样,不知道是客户端的问题还是服务器端的问题?????
...全文
595 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
ayun00 2009-11-16
  • 打赏
  • 举报
回复
楼主是哪里出现了问题呢?
lz_0618 2009-04-28
  • 打赏
  • 举报
回复
哈哈,终于解决了,给出的代码没有问题,有问题的代码在其他部分
lz_0618 2009-04-27
  • 打赏
  • 举报
回复
to kingdomgps :
经测试,同一台XP下也不出现问题!!

那我的问题会是服务器的哪一部分出现问题,大家给点提示???
注册失败 2009-04-27
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 walkghost 的回复:]
catch 里面表写return;

1,当服务器部署在XP下的时候,丢包现象比较严重
--你在几台XP下作的测试?
2,当服务器部署在2003下,且客户端在另一台2003机器上时,丢包现象少一点
--同上,你在几台2003上做的测试?
3,当服务器和客户端都在同一台2003机器下时,不出现丢包!!!!!
--这个说明程序应该没多大问题。你把测试做严谨些。找一个干净的网络和几个干净机器做测试。

[/Quote]
同一台服务器的TCP/IP通讯是基于内存拷贝的
因排除了很多出现问题的原因
你试试在同一台XP下做个测试,我估计结果也是不会丢包的
lz_0618 2009-04-27
  • 打赏
  • 举报
回复
1的测试在两台XP机器上进行的,XP机器性能越差,出现丢包的概率越大

XP(机器性能较差)往2003(性能较好)也没有发现问题

读超时时,不管超时时间设多长,都没有用,不设超时,就给阻塞住了

想把测试做严谨些,但没有那么多机器啊
xudongdong1990 2009-04-27
  • 打赏
  • 举报
回复
嗯,我觉得3楼答复得很好,我也这样干过
walkghost 2009-04-27
  • 打赏
  • 举报
回复
catch 里面表写return;

1,当服务器部署在XP下的时候,丢包现象比较严重
--你在几台XP下作的测试?
2,当服务器部署在2003下,且客户端在另一台2003机器上时,丢包现象少一点
--同上,你在几台2003上做的测试?
3,当服务器和客户端都在同一台2003机器下时,不出现丢包!!!!!
--这个说明程序应该没多大问题。你把测试做严谨些。找一个干净的网络和几个干净机器做测试。
lz_0618 2009-04-27
  • 打赏
  • 举报
回复
下载了一个Echo 服务器程序,经测试似乎没有问题,所以看来似乎(似乎?)是服务器端的问题!!
但测试现象让我很疑惑:
1,当服务器部署在XP下的时候,丢包现象比较严重
2,当服务器部署在2003下,且客户端在另一台2003机器上时,丢包现象少一点
3,当服务器和客户端都在同一台2003机器下时,不出现丢包!!!!!

难道还是我服务器的问题吗??????

下面是我服务器端接收部分的主要代码:
private void StartToListen(object sender, DoWorkEventArgs e)
{
try
{
_listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listenerSocket.Bind(new IPEndPoint(_serverIP, _serverPort));
_listenerSocket.Listen(200);
}
catch(Exception ee)
{
_ServerClosed = true;
ServerFailEventArgs serverFailEventArgs = new ServerFailEventArgs(ee);
OnServerStartListenFail(this, serverFailEventArgs);
return;
//throw;
}

OnServerStartListen(this, new EventArgs());

while (!_ServerClosed)
{
try
{
this.CreateNewClientSocketManager(_listenerSocket.Accept());
}
catch
{
}
}

OnServerStopListen(this, new EventArgs());

}


private void CreateNewClientSocketManager(Socket socket)
{
ClientSocketManager newClientSocketManager = new ClientSocketManager(socket);
........
lock (_clients)
{
_clients.Add(newClientSocketManager);
}
OnClientConnected(newClientSocketManager, new ClientEventArgs(newClientSocketManager));

}

ClientSocketManager类(部分):
public ClientSocketManager(Socket clientSocket)
{
this._socket = clientSocket;
//this.networkStream = new NetworkStream(this._socket);
this.bwReceiver = new BackgroundWorker();
this.bwReceiver.DoWork += new DoWorkEventHandler(StartReceive);
this.bwReceiver.RunWorkerAsync();
}

private void StartReceive(object sender, DoWorkEventArgs e)
{
try
{
StateObject state = new StateObject();
state.workSocket = _socket;
IAsyncResult asynResult = _socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
asynResult.AsyncWaitHandle.WaitOne();

}
catch//(Exception ee)
{
//throw ee;

}
}

private void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;

if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
if (bytesRead == 0)
{
//服务器端已经关闭了????
//this.OnServerDisconnected(new ServerEventArgs(_ClientSocket));
this.OnDisconnected(new ClientEventArgs(this));
this.Close();
return;
}

_lastActionDateTime = DateTime.Now;
//已经接收到数据

state.sb.Append(Encoding.Default.GetString(state.buffer, 0, bytesRead));
Debug.WriteLine("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<(Remote port:"+ Port+"):" + ConvertBytesToHex(state.buffer,bytesRead,true,false));
//触发接收数据事件
lock (SyncRoot) //有没有必要????
{
ClientDataReceivedEventArgs dea = new ClientDataReceivedEventArgs(state.buffer, bytesRead);
try
{
OnDataReceived(dea);
}
catch
{
}

string aa = state.sb.ToString();
state.sb.Remove(0, aa.Length);

if (!dea.HasDealWith)
{
//DONE:触发接收字符串数据事件
ClientStringReceivedEventArgs srEa = new ClientStringReceivedEventArgs(aa);
try
{
OnStringReceived(srEa);
}
catch
{
}
}
}
IAsyncResult asynResult = _socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
asynResult.AsyncWaitHandle.WaitOne();
}

}
catch (Exception ee)
{
//this.OnServerDisconnected(new ServerEventArgs(_ClientSocket));
this.OnDisconnected(new ClientEventArgs(this));
this.Close();
return;
//throw ee;
//EndReceive会引发异常
}
}

fengyecsdn 2009-04-27
  • 打赏
  • 举报
回复
我出现过类似的情况。
C/S都是采用变长数据包发送的。
而且我自己加了一个封包头。 就是包头是4字节的版本标识,然后是4字节的包体长度,后边就是数据是经过序列化以后的字节流。 包体长度就是字节流的长度。

但是我的传输过程常出现丢包的问题。开始是以为我的包头或者长度有误。 经过检查,数据是正确的。
最后总结出这样一个问题。
如果数据部进行封包,直接序列化到NETSTREAM里发送出去。 基本没问题。 数据是可以正常发送的。 但是实际业务里不太方便管理和控制。

最后我发现解决的办法就是使用固定长的数据块。
缓冲区是4K,每次发送的数据加上包头都要小于4K,然后整个4K一起发出。问题解决。胆识浪费带宽很多。
后来采用16倍数也没处问题。就是要发送的数据加包头一起计算总长,然后补齐到16的倍数。
比如数据流100字节,头8字节。108字节,108/16=6 , 6+1=7 , 16*7= 112.则实际缓冲区占用112字节,并一起送出。
也就是说网络每次传输的数据都是16的整倍数,最后的几个自己肯定是0补空。
如果全部数据正好是16的倍数,比如112,那么也最后补上一个16字节的0.发送128字节。

经过多次实现,好像(只是好像)是因为NETCLIENT读数据的时候并非按字节精确控制(除非你按字节读)
当有数据长度不科学的时候,容易出现数据错位。 用16倍数长度,变长发送数据就OK。
walkghost 2009-04-27
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 lz_0618 的回复:]
在调试时出现了更怪异的事情:

1,我将服务器端源代码拷贝到了XP机器上,在那台机器上重新编译,直接执行Debug目录下的可执行文件,启动Socket服务器,用2003的机器当客户端测试,发现重新编译后的服务器端,很少出现问题!!!
2,我在XP机器的VS调试环境下,执行并启动Socket服务器,用2003的机器当客户端测试,测试了几千个数据包,居然没有出现错误!!!

命苦啊,调试状态下不出现错误
[/Quote]
你在XP的机器上发布一下,然后用2003做客户端连XP的服务端,再把发布的程序在2003和xp上交叉测试。
lz_0618 2009-04-27
  • 打赏
  • 举报
回复
在调试时出现了更怪异的事情:

1,我将服务器端源代码拷贝到了XP机器上,在那台机器上重新编译,直接执行Debug目录下的可执行文件,启动Socket服务器,用2003的机器当客户端测试,发现重新编译后的服务器端,很少出现问题!!!
2,我在XP机器的VS调试环境下,执行并启动Socket服务器,用2003的机器当客户端测试,测试了几千个数据包,居然没有出现错误!!!

命苦啊,调试状态下不出现错误
lz_0618 2009-04-26
  • 打赏
  • 举报
回复
哈哈,好主意,原来想在周六用Delphi编个服务器端试下,但单位去不了!
既然有测试程序,明天下载个测试程序试一下吧,但这种现象实在奇怪!
saisky 2009-04-26
  • 打赏
  • 举报
回复
想楼上说的,找个测试工具试下
walkghost 2009-04-26
  • 打赏
  • 举报
回复
你先要确定是客户端还是服务端的问题:
找个TCPIP测试程序作为服务端,网上有,你找不到的话,我发给你一个,我一直在用,很好用的。把tcpip测试程序放到服务器上,用你的客户端去连服务端,你的客户端不是一直在阻止方式接收服务端的返回么,那就把netstream的读取超时设置长一些,比如5000-100000ms,然后用你的客户端链接这个测试程序,如果返回正常,那么证明网线没有问题,如果返回不正常,再把你自己的程序和测试程序放在同一台机器上测试,如果正常,则证明是网线的问题或者是交换机的问题。如果这时,还不正常,就用TCPIP测试程序去连接你的服务程序。最终你就能找到时哪儿出了问题。
提醒下LZ:出了问题先自己想办法找出问题所在,然后思考解决办法,实在找不到了,再求助别人,这样对你比较有好处。
you684 2009-04-26
  • 打赏
  • 举报
回复
恩,赞同,我们做试验的时候很少有这种情况,tcp是面向连接的吗
biggates_86 2009-04-26
  • 打赏
  • 举报
回复
换网线

111,092

社区成员

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

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

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