说一下自己的思路,没有试过不知行不行。来一个抛砖引玉,各位大侠指教在绑定的时候调用下面的函数HANDLE CreateIoCompletionPort ( HANDLE FileHandle, // handle to file HANDLE ExistingCompletionPort, // handle to I/O completion port ULONG_PTR CompletionKey, // completion key DWORD NumberOfConcurrentThreads // number of threads to execute concurrently ); 在ULONG_PTR CompletionKey, // completion key 中同时将A和B的参数传进工作者线程,A和B同时绑定这个key 那么刚才的key中将有一个是HANDLE FileHandle, // handle to file这样在工作者线程中收到数据的时候就通过判断就可以决定向谁发送什么样的数据
对于Proxy,A就是A,B就是B,不能混在一起,当代码A->B的时候,A是Proxy的客户机,B是Proxy的服务器,一边需要Accept,一边需要的是Connect,虽然后续操作没有太大差别,但是还是两个连接,任何单方断开都不能处理资源的回收。 另外,在通讯当中,他们又是一致性的处理。对于A连接,B是A的Forward,同样的对于B连接A是B的Forward。两两没有差别。 [code=BatchFile] AcceptEx(ClientA) ... if ClientA.Accepted then ConnectEx(ServerB) ... if ServerB.Connected then { ClientA.Forward = ServerB ServerB.Forward = ClientA WSARecv(ClientA) WSARecv(ServerB) } ... if ClientA.Received then WSASend(ClientA.Forward/*ServerB*/,ClientA.Data) ... if ServerB.Received then WSASend(ServetB.Forward/*ClientA*/,ServerB.Data) ...[/code]
HANDLE FileHandle, // handle to file
HANDLE ExistingCompletionPort, // handle to I/O completion port
ULONG_PTR CompletionKey, // completion key
DWORD NumberOfConcurrentThreads // number of threads to execute concurrently
);
在ULONG_PTR CompletionKey, // completion key
中同时将A和B的参数传进工作者线程,A和B同时绑定这个key
那么刚才的key中将有一个是HANDLE FileHandle, // handle to file这样在工作者线程中收到数据的时候就通过判断就可以决定向谁发送什么样的数据
另外,在通讯当中,他们又是一致性的处理。对于A连接,B是A的Forward,同样的对于B连接A是B的Forward。两两没有差别。
[code=BatchFile]
AcceptEx(ClientA)
...
if ClientA.Accepted then
ConnectEx(ServerB)
...
if ServerB.Connected then
{
ClientA.Forward = ServerB
ServerB.Forward = ClientA
WSARecv(ClientA)
WSARecv(ServerB)
}
...
if ClientA.Received then
WSASend(ClientA.Forward/*ServerB*/,ClientA.Data)
...
if ServerB.Received then
WSASend(ServetB.Forward/*ClientA*/,ServerB.Data)
...[/code]
2. 有个Client 被 Accept
3. 创建该Client对应的CompletionKey并加入IOCP
4. 同时创建一个RemoteServer的Socket, 也创建此RemoteSocket的CompletionKey也加入上边的IOCP
5. 由于CompletionKey结构中有指向与自己相同结构的指针,即 CompletionKey* p,利用这个指针把刚才建立的两个CompletioKey互指,即变成Ring结构,简单说就是A->B, B->A
6. 然后进行GetQueuedCompletionStatus, 如果是发生接受完毕,则把接收到的数据全部发到对方,如果是发送完毕事件,假如是A->B,则如果收取的字节<缓冲大小(这么做虽然有问题,但现在这还是小问题),即表示数据已发送完毕则开始在B读取数据,则如果收取的字节=缓冲大小则认为还有数据要从A收取。但这么做有时候能互传数据,有时候就停滞不前了,最大的问题就是如果B是HTTP服务器,假如缓冲大小是4K,虽然网页超过4K比如10K, 但 只传了3K,HTTP服务器就不响应了,后面的数据就不传,结果A收到的是不完整的网页。
我又怀疑是不是网也有图片,每个要读取图片的时候重新Accept一下,是不是要改用AcceptEx。 虽然CompletionPort处理过程中不要使用阻塞操作,但这里的Accept跟CompletionPort几乎说是无关,哎,头大了。
OldCompletionKey Self;
OldCompletionKey *Forward;
}NewCompletionKey,*LPNewCompletionKey;
其他的什么都不需要做的主要在工作者线程中得到一个对应的关系即可
这个对应的关系就通过完成key传进去当收到的时候将收到的数据完整的传给对方不过要做好的是资源的回收等事情
{
SOCKET OriginalSocket;
IO_HANDLE *FinalHandle;
HANDLE DomainHandle;
char *DomainBuffer;
SOCKADDR_IN DestSocketAddress;
IODATA IOData;
DWORD TotalTransfer;
DWORD Timer;
BOOL IsActive;
省略部分数据
struct IO_HANDLE *Next;
}IOHANDLE,*LPIOHANDLE;
LPIOHANDLE IOHandleListHead = NULL;