public void WorkerThread()
{
while (Wait() != -1)
{
// Infinite loop
}
}
// return value
// 0 = disconnect or others
// 1 = recv
// 2 = send
public int Wait()
{
PerHandleData perHandleData;
PerIoData perIoData;
Overlapped overlapped;
IntPtr intPtrPerHandleData;
IntPtr intPtrOverlapped;
uint bytesTransferred;
// Wait until all socket I/O completes.
bool ret = Win32Api.GetQueuedCompletionStatus(
completionPort: completionPort,
lpNumberOfBytesTransferred: out bytesTransferred,
lpCompletionKey: out intPtrPerHandleData,
lpOverlapped: out intPtrOverlapped,
dwMilliseconds: uint.MaxValue);
Console.WriteLine("Get queued completion status");
// Problem during overlapped I/O.
if (intPtrOverlapped == IntPtr.Zero)
{
Logger.ErrorLog();
// Reset();
return -1;
}
// Recover PerIoData and PerHandleData from IntPtr
GCHandle gchPerHandleData = GCHandle.FromIntPtr(intPtrPerHandleData);
perHandleData = (PerHandleData)gchPerHandleData.Target;
overlapped = new Overlapped();
Marshal.PtrToStructure(intPtrOverlapped, overlapped);
GCHandle gchPerIoData = GCHandle.FromIntPtr(overlapped.PerIoDataPtr);
perIoData = (PerIoData)gchPerIoData.Target;
// When socket is disconnected, there is no transferred data.
// Release resources and close the socket.
if (bytesTransferred == 0 && ret == false)
{
Logger.ErrorLog();
Console.WriteLine("disconnected from socket: "
+ perHandleData.Socket.GetHashCode());
DisconnectCallBack(perHandleData.Socket);
socketRefCount[perHandleData.Socket] =
(int)socketRefCount[perHandleData.Socket] - 1;
if ((int) socketRefCount[perHandleData.Socket] == 0)
{
socketRefCount.Remove(perHandleData.Socket);
perHandleData.Socket.Close();
}
gchPerHandleData.Free();
gchPerIoData.Free();
return 0;
}
// When receive done, invoke call back function
// and release resources of per I/O data.
else if (perIoData.State == OperationState.Receive)
{
byte[] buffer = new byte[bytesTransferred];
Array.Copy(perIoData.Buffer, buffer, bytesTransferred);
String data = Encoding.UTF8.GetString(buffer);
Console.WriteLine("received from socket: " +
perHandleData.Socket.GetHashCode());
ReceiveCallBack(perHandleData.Socket, data);
// Decrement reference count to the socket.
socketRefCount[perHandleData.Socket] =
(int)socketRefCount[perHandleData.Socket] - 1;
gchPerIoData.Free();
return 1;
}
// When send done, release resources of per I/O data.
// If sending was partial, send remaining data.
else
{
if (perIoData.WSABuffer.Length != bytesTransferred)
{
byte[] dataBytes = new byte[perIoData.WSABuffer.Length -
bytesTransferred];
Array.Copy(perIoData.Buffer, bytesTransferred, dataBytes, 0,
dataBytes.Length);
Send(perHandleData.Socket, dataBytes);
// Decrement reference count to the socket.
socketRefCount[perHandleData.Socket] =
(int)socketRefCount[perHandleData.Socket] - 1;
}
else
{
Console.WriteLine("sent to socket: " +
perHandleData.Socket.GetHashCode());
SendCallBack(perHandleData.Socket);
// Decrement reference count to the socket.
socketRefCount[perHandleData.Socket] =
(int)socketRefCount[perHandleData.Socket] - 1;
gchPerIoData.Free();
}
return 2;
}
}