问题描述
第一次写通讯,C#通过TcpClient连接到一个C++编号的TCP服务,但是连接上后,从C++服务端推送过来的时候有丢包,请问这个怎么解决,,..求写过通讯的高手们帮帮忙,下面是我整个TCP通讯的主要代码!客户端TCP连接类usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Net.Sockets;usingSystem.Windows.Forms;usingSystem.Net;namespaceTcpMsg{publicclassLeafTCPClient{///<summary>///当前客户端名称///</summary>privatestring_Name="未定义";publicstringName{get{return_Name;}}publicvoidSetName(){if(_NetWork.Connected){IPEndPointiepR=(IPEndPoint)_NetWork.Client.RemoteEndPoint;IPEndPointiepL=(IPEndPoint)_NetWork.Client.LocalEndPoint;_Name=iepL.Port+"->"+iepR.ToString();}}///<summary>///TCP客户端///</summary>privateTcpClient_NetWork=null;publicTcpClientNetWork{get{return_NetWork;}set{_NetWork=value;SetName();}}///<summary>///数据接收缓存区///</summary>publicbyte[]buffer=newbyte[2048];///<summary>///断开客户端连接///</summary>publicvoidDisConnect(){try{if(_NetWork!=null&&_NetWork.Connected){NetworkStreamns=_NetWork.GetStream();ns.Close();_NetWork.Close();}}catch(Exceptionex){MessageBox.Show(ex.Message,"错误",MessageBoxButtons.OK,MessageBoxIcon.Error);}}}}
//TCP通讯事件usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Net.Sockets;namespaceTcpMsg{publicclassLeafEvent{///<summary>///数据接收事件///</summary>///<paramname="sender"></param>///<paramname="data"></param>publicdelegatevoidDataReceivedHandler(objectsender,byte[]data);///<summary>///发送数据事件///</summary>///<paramname="data"></param>publicdelegateboolDataSendHandler(byte[]data);///<summary>///捕获到IP数据包///作者:MaximusYe///添加时间:2013年9月16日///</summary>///<paramname="packet"></param>//publicdelegatevoidPacketReceived(Model.IPPacketpacket);}}
窗体程序,启动服务和接收回调处理publiceventLeafEvent.DataReceivedHandlerDataReceived;LeafTCPClientclient=null;privatevoidbtnConnect_Click(objectsender,EventArgse){if((client!=null)&&(client.NetWork.Connected)){client.DisConnect();}else{client=newLeafTCPClient();try{client.NetWork=newTcpClient();client.NetWork.Connect(txtip.Text.Trim(),Int32.Parse(txtport.Text));client.SetName();client.NetWork.GetStream().BeginRead(client.buffer,0,client.buffer.Length,newAsyncCallback(TCPCallBack),client);setBtnStatus();SetText("连接成功!");}catch(Exceptionex){client.DisConnect();MessageBox.Show(ex.Message,"错误",MessageBoxButtons.OK,MessageBoxIcon.Error);}}setBtnStatus();}delegatevoidSetControl();privatevoidsetBtnStatus(){if((btnConnect.InvokeRequired)||(btnSend.InvokeRequired)){this.Invoke(newSetControl(setBtnStatus));}else{intcon=((client==null)||(!client.NetWork.Connected))?0:1;string[]constr={"连接","断开"};bool[]btnEnabled={false,true};btnConnect.Text=constr[con];btnSend.Enabled=btnEnabled[con];button1.Enabled=btnEnabled[con];}}privatevoidSetText(stringtext){txtMsg.Invoke(newMethodInvoker(delegate{txtMsg.AppendText(DateTime.Now.ToString("yyyy-MM-ddHH:mm:ss")+"消息:"+text+Environment.NewLine+Environment.NewLine);}));}///<summary>///回调函数///</summary>///<paramname="ar"></param>privatevoidTCPCallBack(IAsyncResultar){LeafTCPClientclient=(LeafTCPClient)ar.AsyncState;if(client.NetWork.Connected){NetworkStreamns=client.NetWork.GetStream();try{byte[]recdata=newbyte[ns.EndRead(ar)];Array.Copy(client.buffer,recdata,recdata.Length);if(recdata.Length>0){if(DataReceived!=null){DataReceived.BeginInvoke(client.Name,recdata,null,null);//异步输出数据}ns.BeginRead(client.buffer,0,client.buffer.Length,newAsyncCallback(TCPCallBack),client);stringsdata;sdata=newstring(Encoding.Default.GetChars(recdata));SetText(sdata);}else{}}catch(Exceptionex){MessageBox.Show(ex.Message,"错误",MessageBoxButtons.OK,MessageBoxIcon.Error);client.DisConnect();//lstClient.Remove(client);//BindLstClient();}}else{SetText("连接已被关闭!");}}publicboolSendData(stringmsg){try{if(client.NetWork.Connected==false){SetText("连接已被关闭!");returnfalse;}SetText("发送消息:"+msg);byte[]data;data=Encoding.GetEncoding("GB2312").GetBytes(msg);client.NetWork.GetStream().Write(data,0,data.Length);returntrue;}catch(Exceptionex){MessageBox.Show(client.Name+":"+ex.Message,"错误",MessageBoxButtons.OK,MessageBoxIcon.Error);returnfalse;}}
解决方案
解决方案二:
根本不是丢包,而是楼主不了解TCP通讯的特点,它是基于流的,所以接收数据的时候,有可能不是一下子收全的,而是分批到达,楼主的代码没有这方面的处理.
解决方案三:
同意#1楼。发送端可能分3次发送2000、1000、500个字节,而接收端可能分4次接收到500、1800、700、500个字节。因为TCP数据发送是一个非常复杂的过程,为了高效同时又不滥占带宽,接收端你看到的结果会按照windows的规则自动合并或者分包。只要你使用TCP,那么你就应该自定义消息信令格式,接收端可以知道消息什么时候结束。例如HTTP(当然,这也是基于TCP的)消息头和消息体分别是以两个连续的“换行回车”结束的。接收端需要在分解到消息结束标志时,才可能去执行什么DataReceived.BeginInvoke代码。不能提前去丢数据输出。