完成端口高并发数据接收发送问题

bj_leo_3000 2016-01-14 09:47:58
我用完成端口做了一个中转服务器,需要同时接收100个客户端每100ms发来一次255bytes的数据,然后将所有收到数据发给另外1客户端。
目前接收数据目前没有问题,但转发经常没有发出去。
接收使用socket.ReceiveAsync,在回调函数中使用socket.SendAsync发送,发送出去的数据只有接收到的数据的十分之一。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;

namespace IOCPServer
{
public class ClientToken
{
public Socket ConnectSocket;
public SocketAsyncEventArgs ReceiveEventArgs;
public SocketAsyncEventArgs SendEventArgs;
protected byte[] RecvBuffer;
public ClientToken()
{
ReceiveEventArgs = new SocketAsyncEventArgs();
ReceiveEventArgs.UserToken = this;
SendEventArgs = new SocketAsyncEventArgs();
SendEventArgs.UserToken = this;
RecvBuffer = new byte[1024];
ReceiveEventArgs.SetBuffer(RecvBuffer, 0, RecvBuffer.Length);
}
}

public class IOCPServer
{
bool IsInit;
bool IsRun;
Socket listenSocket;
List<ClientToken> ClientList;
Object m_Mutex;
public void Init()
{
if (IsInit == true)
return;
m_Mutex = null;
ClientList = new List<ClientToken>(1);
IsInit = true;
}

public void UnInit()
{
if (IsInit == false)
return;
ClientList.Clear();
IsInit = false;
}
public bool Start(IPEndPoint localEndPoint)
{
if (IsRun)
return true;
try
{
listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(localEndPoint);
listenSocket.Listen(100);
}
catch (SocketException e)
{
if (e.NativeErrorCode == 10048)
MessageBox.Show("监听端口已经被占用", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
else
MessageBox.Show(e.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
StartAccept(null);
IsRun = true;

return true;
}

public void Stop()
{
if (IsRun == false)
return;
try
{
listenSocket.Close();
}
catch (Exception E)
{
}

IsRun = false;
}

public void StartAccept(SocketAsyncEventArgs acceptEventArgs)
{
if (acceptEventArgs == null)
{
acceptEventArgs = new SocketAsyncEventArgs();
acceptEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
}
else
{
acceptEventArgs.AcceptSocket = null; //释放上次绑定的Socket,等待下一个Socket连接
}

bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArgs);
if (!willRaiseEvent)
{
ProcessAccept(acceptEventArgs);
}
}

void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs acceptEventArgs)
{
try
{
if (acceptEventArgs.AcceptSocket.Connected == true)
ProcessAccept(acceptEventArgs);
}
catch (Exception E)
{
}
}

private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs)
{
ClientToken cliToken = new ClientToken();
cliToken.ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
cliToken.SendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
cliToken.ConnectSocket = acceptEventArgs.AcceptSocket;
ClientList.Add(cliToken);
try
{
bool willRaiseEvent = cliToken.ConnectSocket.ReceiveAsync(cliToken.ReceiveEventArgs); //投递接收请求
if (!willRaiseEvent)
{
lock (cliToken)
{
ProcessReceive(cliToken.ReceiveEventArgs);
}
}
}
catch (Exception E)
{
}

StartAccept(acceptEventArgs); //把当前异步事件释放,等待下次连接
}

void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs)
{
ClientToken cliToken = (ClientToken)asyncEventArgs.UserToken;
try
{
lock (cliToken)
{
if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive)
ProcessReceive(asyncEventArgs);
}
}
catch (Exception E)
{
}
}

private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs)
{
ClientToken cliToken = (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);
bool willRaiseEvent = cliToken.ConnectSocket.ReceiveAsync(cliToken.ReceiveEventArgs); //投递接收请求
if (!willRaiseEvent)
ProcessReceive(cliToken.ReceiveEventArgs);
}
else
{
CloseClientSocket(cliToken);
}
}

public void CloseClientSocket(ClientToken cliToken)
{
if (cliToken.ConnectSocket == null)
return;

try
{
cliToken.ConnectSocket.Shutdown(SocketShutdown.Both);
}
catch (Exception E)
{
}
cliToken.ConnectSocket.Close();
cliToken.ConnectSocket = null;
ClientList.Remove(cliToken);
}

public bool SendAsync(Socket connectSocket, SocketAsyncEventArgs sendEventArgs, byte[] buffer, int offset, int count)
{
if (connectSocket == null)
return false;
bool willRaiseEvent = true;
try
{
sendEventArgs.SetBuffer(buffer, offset, count);
willRaiseEvent = connectSocket.SendAsync(sendEventArgs);
}
catch (Exception E)
{
return false;
}
return false;
}
}
}
...全文
333 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
Poopaye 2016-08-31
  • 打赏
  • 举报
回复
1、异常的地方没有做任何处理 2、连返回值都懒得检查 3、哪来的自信?
2031313 2016-08-31
  • 打赏
  • 举报
回复
为什么多连接的socket接收数据出现丢失数据的现象?
  • 打赏
  • 举报
回复
另外可以直接看到一堆“小问题”,例如: 1. 使用所谓 IOCP,不用 new Socket,而要使用 new TcpListener 机制,然后充其量地,TcpListener对象的 Socket 属性可以用。不要写 new Socket(.......) 这种代码。 2. 人家的TcpListener 内置的 Listen(int.MaxValue) 代码。而不是什么 Listen(100)。 3. Buffer 大小是怎样确定为 1024 的?这个 Buffer 不是底层 tcp 机制的 buffer,这个大小通常开到几百K 才能发挥最好的效果。 还有监听的地址应该是本机的所有网卡地址,等等问题,就不多说了。也没有时间去细看。
  • 打赏
  • 举报
回复
有些一眼可以看出的问题。例如: public class ClientToken { public Socket ConnectSocket; public SocketAsyncEventArgs ReceiveEventArgs; public SocketAsyncEventArgs SendEventArgs; ........... 这里,第一个定义毫无意义,你根本没有用到,删除多余的代码才能保证代码质量。而后边两个定义,至少有一个你肯定在代码中产生了“并发冲突”情况发生时去丢失了其真正要处理数据。要么是 ReceiveEventArgs,要么是 SendEventArgs,你肯定有一个地方明明应该创建多个对象实例,而为了空洞地“共享使用”这种噱头而共享使用了公共对象实例。
  • 打赏
  • 举报
回复
既然accept没问题,那可以考虑将accept的数据放入队列,然后开个线程从队列中取消息进行发送
bj_leo_3000 2016-01-14
  • 打赏
  • 举报
回复
哪位高手给解释一下。

110,499

社区成员

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

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

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