问题描述
我用完成端口做了一个中转服务器,需要同时接收100个客户端每100ms发来一次255bytes的数据,然后将所有收到数据发给另外1客户端。目前接收数据目前没有问题,但转发经常没有发出去。接收使用socket.ReceiveAsync,在回调函数中使用socket.SendAsync发送,发送出去的数据只有接收到的数据的十分之一。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Net.Sockets;usingSystem.Net;usingSystem.Windows.Forms;namespaceIOCPServer{publicclassClientToken{publicSocketConnectSocket;publicSocketAsyncEventArgsReceiveEventArgs;publicSocketAsyncEventArgsSendEventArgs;protectedbyte[]RecvBuffer;publicClientToken(){ReceiveEventArgs=newSocketAsyncEventArgs();ReceiveEventArgs.UserToken=this;SendEventArgs=newSocketAsyncEventArgs();SendEventArgs.UserToken=this;RecvBuffer=newbyte[1024];ReceiveEventArgs.SetBuffer(RecvBuffer,0,RecvBuffer.Length);}}publicclassIOCPServer{boolIsInit;boolIsRun;SocketlistenSocket;List<ClientToken>ClientList;Objectm_Mutex;publicvoidInit(){if(IsInit==true)return;m_Mutex=null;ClientList=newList<ClientToken>(1);IsInit=true;}publicvoidUnInit(){if(IsInit==false)return;ClientList.Clear();IsInit=false;}publicboolStart(IPEndPointlocalEndPoint){if(IsRun)returntrue;try{listenSocket=newSocket(localEndPoint.AddressFamily,SocketType.Stream,ProtocolType.Tcp);listenSocket.Bind(localEndPoint);listenSocket.Listen(100);}catch(SocketExceptione){if(e.NativeErrorCode==10048)MessageBox.Show("监听端口已经被占用","提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);elseMessageBox.Show(e.Message,"提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);returnfalse;}StartAccept(null);IsRun=true;returntrue;}publicvoidStop(){if(IsRun==false)return;try{listenSocket.Close();}catch(ExceptionE){}IsRun=false;}publicvoidStartAccept(SocketAsyncEventArgsacceptEventArgs){if(acceptEventArgs==null){acceptEventArgs=newSocketAsyncEventArgs();acceptEventArgs.Completed+=newEventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);}else{acceptEventArgs.AcceptSocket=null;//释放上次绑定的Socket,等待下一个Socket连接}boolwillRaiseEvent=listenSocket.AcceptAsync(acceptEventArgs);if(!willRaiseEvent){ProcessAccept(acceptEventArgs);}}voidAcceptEventArg_Completed(objectsender,SocketAsyncEventArgsacceptEventArgs){try{if(acceptEventArgs.AcceptSocket.Connected==true)ProcessAccept(acceptEventArgs);}catch(ExceptionE){}}privatevoidProcessAccept(SocketAsyncEventArgsacceptEventArgs){ClientTokencliToken=newClientToken();cliToken.ReceiveEventArgs.Completed+=newEventHandler<SocketAsyncEventArgs>(IO_Completed);cliToken.SendEventArgs.Completed+=newEventHandler<SocketAsyncEventArgs>(IO_Completed);cliToken.ConnectSocket=acceptEventArgs.AcceptSocket;ClientList.Add(cliToken);try{boolwillRaiseEvent=cliToken.ConnectSocket.ReceiveAsync(cliToken.ReceiveEventArgs);//投递接收请求if(!willRaiseEvent){lock(cliToken){ProcessReceive(cliToken.ReceiveEventArgs);}}}catch(ExceptionE){}StartAccept(acceptEventArgs);//把当前异步事件释放,等待下次连接}voidIO_Completed(objectsender,SocketAsyncEventArgsasyncEventArgs){ClientTokencliToken=(ClientToken)asyncEventArgs.UserToken;try{lock(cliToken){if(asyncEventArgs.LastOperation==SocketAsyncOperation.Receive)ProcessReceive(asyncEventArgs);}}catch(ExceptionE){}}privatevoidProcessReceive(SocketAsyncEventArgsreceiveEventArgs){ClientTokencliToken=(ClientToken)receiveEventArgs.UserToken;if(cliToken.ConnectSocket==null)return;if(cliToken.ReceiveEventArgs.BytesTransferred>0&&cliToken.ReceiveEventArgs.SocketError==SocketError.Success){SendAsync(cliToken.ConnectSocket,cliToken.SendEventArgs,cliToken.ReceiveEventArgs.Buffer,cliToken.ReceiveEventArgs.Offset,cliToken.ReceiveEventArgs.BytesTransferred);boolwillRaiseEvent=cliToken.ConnectSocket.ReceiveAsync(cliToken.ReceiveEventArgs);//投递接收请求if(!willRaiseEvent)ProcessReceive(cliToken.ReceiveEventArgs);}else{CloseClientSocket(cliToken);}}publicvoidCloseClientSocket(ClientTokencliToken){if(cliToken.ConnectSocket==null)return;try{cliToken.ConnectSocket.Shutdown(SocketShutdown.Both);}catch(ExceptionE){}cliToken.ConnectSocket.Close();cliToken.ConnectSocket=null;ClientList.Remove(cliToken);}publicboolSendAsync(SocketconnectSocket,SocketAsyncEventArgssendEventArgs,byte[]buffer,intoffset,intcount){if(connectSocket==null)returnfalse;boolwillRaiseEvent=true;try{sendEventArgs.SetBuffer(buffer,offset,count);willRaiseEvent=connectSocket.SendAsync(sendEventArgs);}catch(ExceptionE){returnfalse;}returnfalse;}}}
解决方案
本帖最后由 bj_leo_3000 于 2016-01-14 11:31:59 编辑
解决方案二:
哪位高手给解释一下。
解决方案三:
既然accept没问题,那可以考虑将accept的数据放入队列,然后开个线程从队列中取消息进行发送
解决方案四:
有些一眼可以看出的问题。例如:publicclassClientToken{publicSocketConnectSocket;publicSocketAsyncEventArgsReceiveEventArgs;publicSocketAsyncEventArgsSendEventArgs;...........这里,第一个定义毫无意义,你根本没有用到,删除多余的代码才能保证代码质量。而后边两个定义,至少有一个你肯定在代码中产生了“并发冲突”情况发生时去丢失了其真正要处理数据。要么是ReceiveEventArgs,要么是SendEventArgs,你肯定有一个地方明明应该创建多个对象实例,而为了空洞地“共享使用”这种噱头而共享使用了公共对象实例。
解决方案五:
另外可以直接看到一堆“小问题”,例如:1.使用所谓IOCP,不用newSocket,而要使用newTcpListener机制,然后充其量地,TcpListener对象的Socket属性可以用。不要写newSocket(.......)这种代码。2.人家的TcpListener内置的Listen(int.MaxValue)代码。而不是什么Listen(100)。3.Buffer大小是怎样确定为1024的?这个Buffer不是底层tcp机制的buffer,这个大小通常开到几百K才能发挥最好的效果。还有监听的地址应该是本机的所有网卡地址,等等问题,就不多说了。也没有时间去细看。