我正在用C#创建一个IOCP服务器,调用win apis。我有一个接受线程连接和工作线程取决于CPU核心。
我的问题是,我有两个线程试图同时处理相同的数据,基于以下片段,你能告诉我解决方案是什么吗,或者这是一个设计问题?
public class WorkerThread
{
public void Worker(NetSharedData data)
{
IntPtr bytestransfer = Marshal.AllocHGlobal(sizeof(UInt32));
IntPtr clientid = Marshal.AllocHGlobal(sizeof(UInt32));
IntPtr poverlapped = Marshal.AllocHGlobal(sizeof(UInt32));
Console.WriteLine("Worker thread running");
while (true)
{
Marshal.WriteInt32(clientid, 0);
Marshal.WriteInt32(bytestransfer, 0);
if (SocketInvoke.GetQueuedCompletionStatus(data.completionport, bytestransfer, clientid, poverlapped, SocketInvoke.INFINITE) == true)
{
if (Marshal.ReadInt32(poverlapped) == 0)
{
//thread shutdown
Console.WriteLine("Worker thread shutdown");
break;
}
Client client = data.Clients[Marshal.ReadInt32(clientid)];
if (Marshal.ReadInt32(bytestransfer) != 0)
{
if (client.operationtype == SocketInvoke.FD_WRITE)
{
if (client.send_data.ispending_operation == true)
{
client.SendLeft((uint)Marshal.ReadInt32(bytestransfer));
break;
}
}
if (client.operationtype == SocketInvoke.FD_READ)
{
if (!client.Recv((uint)Marshal.ReadInt32(bytestransfer)))
{
client.Close();
break;
}
if (data.OnRecv(client) == true)
{
//SendLeft test
}
}
}
}
}
}
}
/*
//THIS IS A CODE SNIPPET THAT BELONGS TO THE ACCEPT THREAD CLASS
*/
public virtual bool Recv(uint expected_data_transfer)
{
IntPtr pwsabuf;
IntPtr wsaoverlapped;
IntPtr bytes_recv = Marshal.AllocHGlobal(sizeof(int));
IntPtr flags = Marshal.AllocHGlobal(sizeof(int));
Marshal.WriteInt32(flags, 0);
set_total_transfer(SocketInvoke.FD_READ, expected_data_transfer);
pwsabuf = recv_data.rtn_wsabuffarray(recv_data.buffer, (uint)recv_data.bufflen);
wsaoverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SocketInvoke.WSAOVERLAPPED)));
Marshal.StructureToPtr(overlapped, wsaoverlapped, false);
SocketInvoke.FillMemory(wsaoverlapped, (uint)Marshal.SizeOf(typeof(SocketInvoke.WSAOVERLAPPED)), 0);
unsafe
{
setoptype(SocketInvoke.FD_READ);
if (SocketInvoke.WSARecv(Convert.ToUInt32(sock.Handle.ToInt32()), pwsabuf,
(uint)1, bytes_recv, flags, wsaoverlapped, (IntPtr)null) == SocketInvoke.SOCKET_ERROR)
{
if (Marshal.GetLastWin32Error() != SocketInvoke.WSA_IO_PENDING)
{
return false;
}
return true;
}
}
return true;
}另外,是否可以使用WSASend和WSARecv获取数据的部分发送或部分接收?
发布于 2012-11-24 18:39:43
1)为什么要这样做?要么使用托管异步套接字方法,要么使用C或C++编写整个套接字代码,并通过一个简洁的接口将其公开给托管代码。
2)我猜是因为代码不清楚,但是...每个读或写操作都需要一个唯一的重叠结构。
3)是的,WSASend可能会失败,并且已经发送了部分数据,通常只在数据缓冲区大于操作系统页面大小,并且达到锁定页面限制时,或者在用完非分页池的情况下。如果发生这种情况,那么你可能无法从这种情况中恢复过来--不要一开始就通过限制你可以处理的连接数量来进入这种情况。希望能够处理100,000个连接,但要注意有多少重叠的操作正在等待处理。
4)与所有TCP read操作一样,WSARecv可以返回1字节和所提供的缓冲区大小之间的任何值。如果它返回0,则对等项已关闭其连接的发送端。
5)使用AcceptEx并去掉接受线程。如果您支持从一个程序中侦听多个端口,则具有专用的接受线程会导致另一个线程切换到上下文,并且无法扩展。
https://stackoverflow.com/questions/13539021
复制相似问题