为何IOCP能够同时处理成千上万个连接???(20分)

晕,刚才没看到张无忌说过话了,哈,继续说吧,不过感觉DFW现在变成骂市了,TNND
 
很久没时间来了,没想到这么热闹。[:D]

就事论事,大家到这里来原本应该是帮助楼主解决问题,学习技术的,而
不是为了吵架而来,所以尽管观点不同都应该摆事实讲道理,对的终究是对的,
错的终究是错的。

很久没有写程序了,所以对于新技术、新名词已经陌生了,不过,我始终相信一点,
万变不离其宗。在哪一个层次上效率高,要看具体应用,要看你的需求,看你要求
高的开发效率还是高的运行效率。对于运行效率而言,就算你是在Ring0上实现,
都用汇编写的代码,效率也未必高于用高级语言在上层的实现。你的架构、你的算法、
你在针对于特定环境的优化上都会影响程序的效率,何况,你的底层代码会不会影响
上层程序的运行效率尚未可知。大家都排队,你插队先买到东西,能说你的效率高嘛?

至于使用Delphi开发的人员水平高低,我觉得没有必要争论,工具而已,有人喜欢
用刀,有人喜欢用枪,只要能如期保质保量完成任务,无所谓的。当然,现在许多
开发工具越来越强大了,对于开发者的要求越来越低了,所以,大家感觉总体水平
下降了,但是,高水平程序员依然存在,只不过隐藏在大量的开发者中了。

开发驱动程序的程序员是不是比写数据库程序的程序员水平高,我不好说,因人而异
都有高手和低手,都需要拥有大量相关知识和经验才能写出好程序。
 
楼上的tesug的无知发挥到了极点,他老人家的原话:
>>对于运行效率而言,就算你是在Ring0上实现,
>>都用汇编写的代码,效率也未必高于用高级语言在上层的实现

俺贴一个微软DDK的例子代码给脑子灌水的看看吧,微软的内核Socket例子:

NTSTATUS TdiCall(
PIRP Irp,
PDEVICE_OBJECT DeviceObject,
PIO_STATUS_BLOCK IoStatusBlock,
BOOLEAN CanCancel)
/*
* FUNCTION: Calls a transport driver device
* ARGUMENTS:
* Irp = Pointer to I/O Request Packet
* DeviceObject = Pointer to device object to call
* IoStatusBlock = Address of buffer with I/O status block
* CanCancel = TRUE if the IRP can be cancelled, FALSE if not
* RETURNS:
* Status of operation
* NOTES
* All requests are completed synchronously. A request may be cancelled
*/
{
KEVENT Event;
PKEVENT Events[2];
NTSTATUS Status;
Events[0] = &StopEvent;
Events[1] = &Event;

KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp->UserEvent = &Event;
Irp->UserIosb = IoStatusBlock;

Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)
{
if (CanCancel)
{
Status = KeWaitForMultipleObjects(2, (PVOID)Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);

if (KeReadStateEvent(&StopEvent) != 0)
{
if (IoCancelIrp(Irp))
{
TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP./n"));
}
else
{
TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP./n"));
}
return STATUS_CANCELLED;
}
}
else
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}

return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS;
}


NTSTATUS TdiOpenDevice(
PWSTR Protocol,
ULONG EaLength,
PFILE_FULL_EA_INFORMATION EaInfo,
PHANDLE Handle,
PFILE_OBJECT *Object)
/*
* FUNCTION: Opens a device
* ARGUMENTS:
* Protocol = Pointer to buffer with name of device
* EaLength = Length of EA information
* EaInfo = Pointer to buffer with EA information
* Handle = Address of buffer to place device handle
* Object = Address of buffer to place device object
* RETURNS:
* Status of operation
*/
{
OBJECT_ATTRIBUTES Attr;
IO_STATUS_BLOCK Iosb;
UNICODE_STRING Name;
NTSTATUS Status;

RtlInitUnicodeString(&Name, Protocol);
InitializeObjectAttributes(
&Attr, /* Attribute buffer */
&Name, /* Device name */
OBJ_CASE_INSENSITIVE, /* Attributes */
NULL, /* Root directory */
NULL); /* Security descriptor */

Status = ZwCreateFile(
Handle, /* Return file handle */
GENERIC_READ | GENERIC_WRITE, /* Desired access */
&Attr, /* Object attributes */
&Iosb, /* IO status */
0, /* Initial allocation size */
FILE_ATTRIBUTE_NORMAL, /* File attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */
FILE_OPEN_IF, /* Create disposition */
0, /* Create options */
EaInfo, /* EA buffer */
EaLength); /* EA length */

if (NT_SUCCESS(Status))
{
Status = ObReferenceObjectByHandle(
*Handle, /* Handle to open file */
GENERIC_READ | GENERIC_WRITE, /* Access mode */
NULL, /* Object type */
KernelMode, /* Access mode */
(PVOID*)Object, /* Pointer to object */
NULL); /* Handle information */

if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X)./n", Status));
ZwClose(*Handle);
}
}
else
{
TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)/n", Status));
}

return Status;
}


NTSTATUS TdiCloseDevice(
HANDLE Handle,
PFILE_OBJECT FileObject)
{
if (FileObject)
ObDereferenceObject(FileObject);

if (Handle)
ZwClose(Handle);

return STATUS_SUCCESS;
}


NTSTATUS TdiOpenTransport(
PWSTR Protocol,
USHORT Port,
PHANDLE Transport,
PFILE_OBJECT *TransportObject)
/*
* FUNCTION: Opens a transport driver
* ARGUMENTS:
* Protocol = Pointer to buffer with name of device
* Port = Port number to use
* Transport = Address of buffer to place transport device handle
* TransportObject = Address of buffer to place transport object
* RETURNS:
* Status of operation
*/
{
PFILE_FULL_EA_INFORMATION EaInfo;
PTA_IP_ADDRESS Address;
NTSTATUS Status;
ULONG EaLength;

/* EaName must be 0-termed, even though TDI_TRANSPORT_ADDRESS_LENGTH does *not* include the 0 */
EaLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS) + 1;
EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);

if (!EaInfo)
{
TDI_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));
return STATUS_INSUFFICIENT_RESOURCES;
}

RtlZeroMemory(EaInfo, EaLength);

EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;

/* don't copy the 0; we have already zeroed it */
RtlCopyMemory(EaInfo->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);

EaInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
Address = (PTA_IP_ADDRESS)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1); // 0-term
Address->TAAddressCount = 1;
Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
Address->Address[0].Address[0].sin_port = WH2N(Port);
Address->Address[0].Address[0].in_addr = 0;

Status = TdiOpenDevice(Protocol, EaLength, EaInfo, Transport, TransportObject);

ExFreePool(EaInfo);

return Status;
}


NTSTATUS TdiQueryDeviceControl(
PFILE_OBJECT FileObject,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG Return)
/*
* FUNCTION: Queries a device for information
* ARGUMENTS:
* FileObject = Pointer to device object
* IoControlCode = I/O control code
* InputBuffer = Pointer to buffer with input data
* InputBufferLength = Length of InputBuffer
* OutputBuffer = Address of buffer to place output data
* OutputBufferLength = Length of OutputBuffer
* RETURNS:
* Status of operation
*/
{
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION IoStack;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
PIRP Irp;

DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength, OutputBuffer,
OutputBufferLength, FALSE, NULL, NULL);

if (!Irp)
{
TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed./n"));
return STATUS_INSUFFICIENT_RESOURCES;
}

IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->DeviceObject = DeviceObject;
IoStack->FileObject = FileObject;
Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);

if (Return)
*Return = Iosb.Information;

return Status;
}


NTSTATUS TdiQueryInformationEx(
PFILE_OBJECT FileObject,
ULONG Entity,
ULONG Instance,
ULONG Class,
ULONG Type,
ULONG Id,
PVOID OutputBuffer,
PULONG OutputLength)
/*
* FUNCTION: Extended query for information
* ARGUMENTS:
* FileObject = Pointer to transport object
* Entity = Entity
* Instance = Instance
* Class = Entity class
* Type = Entity type
* Id = Entity id
* OutputBuffer = Address of buffer to place data
* OutputLength = Address of buffer with length of OutputBuffer (updated)
* RETURNS:
* Status of operation
*/
{
TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;

RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
QueryInfo.ID.toi_entity.tei_entity = Entity;
QueryInfo.ID.toi_entity.tei_instance = Instance;
QueryInfo.ID.toi_class = Class;
QueryInfo.ID.toi_type = Type;
QueryInfo.ID.toi_id = Id;

return TdiQueryDeviceControl(
FileObject, /* Transport/connection object */
IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */
&QueryInfo, /* Input buffer */
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */
OutputBuffer, /* Output buffer */
*OutputLength, /* Output buffer length */
OutputLength); /* Return information */
}


NTSTATUS TdiQueryAddress(
PFILE_OBJECT FileObject,
PULONG Address)
/*
* FUNCTION: Queries for a local IP address
* ARGUMENTS:
* FileObject = Pointer to file object
* Address = Address of buffer to place local address
* RETURNS:
* Status of operation
*/
{
ULONG i;
TDIEntityID *Entities;
ULONG EntityCount;
ULONG EntityType;
IPSNMP_INFO SnmpInfo;
PIPADDR_ENTRY IpAddress;
ULONG BufferSize;
NTSTATUS Status = STATUS_SUCCESS;

TDI_DbgPrint(MAX_TRACE, ("Called/n"));

BufferSize = sizeof(TDIEntityID) * 20;
Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);

if (!Entities)
{
TDI_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));
return STATUS_INSUFFICIENT_RESOURCES;
}

/* Query device for supported entities */
Status = TdiQueryInformationEx(
FileObject, /* File object */
GENERIC_ENTITY, /* Entity */
TL_INSTANCE, /* Instance */
INFO_CLASS_GENERIC, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
ENTITY_LIST_ID, /* Entity id */
Entities, /* Output buffer */
&BufferSize); /* Output buffer size */

if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X)./n", Status));
ExFreePool(Entities);
return Status;
}

/* Locate an IP entity */
EntityCount = BufferSize / sizeof(TDIEntityID);

TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d/n", EntityCount));

for (i = 0; i < EntityCount; i++)
{
if (Entities.tei_entity == CL_NL_ENTITY)
{
/* Query device for entity type */
BufferSize = sizeof(EntityType);
Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities.tei_instance, /* Instance */
INFO_CLASS_GENERIC, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
ENTITY_TYPE_ID, /* Entity id */
&EntityType, /* Output buffer */
&BufferSize); /* Output buffer size */

if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP))
{
TDI_DbgPrint(MIN_TRACE, (&quot;Unable to get entity of type IP (Status = 0x%X)./n&quot;, Status));
break;
}

/* Query device for SNMP information */
BufferSize = sizeof(SnmpInfo);
Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities.tei_instance, /* Instance */
INFO_CLASS_PROTOCOL, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
IP_MIB_STATS_ID, /* Entity id */
&SnmpInfo, /* Output buffer */
&BufferSize); /* Output buffer size */

if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0))
{
TDI_DbgPrint(MIN_TRACE, (&quot;Unable to get SNMP information or no IP addresses available (Status = 0x%X)./n&quot;, Status));
break;
}

/* Query device for all IP addresses */
if (SnmpInfo.NumAddr != 0)
{
BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
if (!IpAddress)
{
TDI_DbgPrint(MIN_TRACE, (&quot;Insufficient resources./n&quot;));
break;
}

Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities.tei_instance, /* Instance */
INFO_CLASS_PROTOCOL, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */
IpAddress, /* Output buffer */
&BufferSize); /* Output buffer size */

if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, (&quot;Unable to get IP address (Status = 0x%X)./n&quot;, Status));
ExFreePool(IpAddress);
break;
}

if (SnmpInfo.NumAddr != 1)
{
/* Skip loopback address */
*Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr);
}
else
{
/* Select the first address returned */
*Address = DN2H(IpAddress->Addr);
}
ExFreePool(IpAddress);

}
else
{
Status = STATUS_UNSUCCESSFUL;
break;
}
}
}

ExFreePool(Entities);

TDI_DbgPrint(MAX_TRACE, (&quot;Leaving/n&quot;));

return Status;
}


NTSTATUS TdiSendDatagram(
PFILE_OBJECT TransportObject,
USHORT Port,
ULONG Address,
PVOID Buffer,
ULONG BufferSize)
/*
* FUNCTION: Sends a datagram
* ARGUMENTS:
* TransportObject = Pointer to transport object
* Port = Remote port
* Address = Remote address
* Buffer = Pointer to buffer with data to send
* BufferSize = Length of Buffer
* RETURNS:
* Status of operation
*/
{
PIRP Irp;
PMDL Mdl;
PDEVICE_OBJECT DeviceObject;
PTDI_CONNECTION_INFORMATION ConnectInfo;
PTA_IP_ADDRESS TA;
PTDI_ADDRESS_IP IpAddress;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;

DeviceObject = IoGetRelatedDeviceObject(TransportObject);
ConnectInfo = (PTDI_CONNECTION_INFORMATION)
ExAllocatePool(NonPagedPool,
sizeof(TDI_CONNECTION_INFORMATION) +
sizeof(TA_IP_ADDRESS));

if (!ConnectInfo)
return STATUS_INSUFFICIENT_RESOURCES;

RtlZeroMemory(ConnectInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));

ConnectInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
ConnectInfo->RemoteAddress = (PUCHAR) ((ULONG)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));

TA = (PTA_IP_ADDRESS)(ConnectInfo->RemoteAddress);
TA->TAAddressCount = 1;
TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address);
IpAddress->sin_port = WH2N(Port);
IpAddress->in_addr = DH2N(Address);
Irp = TdiBuildInternalDeviceControlIrp(
TDI_SEND_DATAGRAM, /* Sub function */
DeviceObject, /* Device object */
TransportObject, /* File object */
NULL, /* Event */
NULL); /* Return buffer */

if (!Irp)
{
TDI_DbgPrint(MIN_TRACE, (&quot;TdiBuildInternalDeviceControlIrp() failed./n&quot;));
ExFreePool(ConnectInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}

Mdl = IoAllocateMdl(
Buffer, /* Virtual address of buffer */
BufferSize, /* Length of buffer */
FALSE, /* Not secondary */
FALSE, /* Don't charge quota */
NULL); /* Don't use IRP */

if (!Mdl)
{
TDI_DbgPrint(MIN_TRACE, (&quot;IoAllocateMdl() failed./n&quot;));
IoFreeIrp(Irp);
ExFreePool(ConnectInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}

#ifdef _MSC_VER
try
{
#endif
MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
#ifdef _MSC_VER
}
except(EXCEPTION_EXECUTE_HANDLER)
{
TDI_DbgPrint(MIN_TRACE, (&quot;MmProbeAndLockPages() failed./n&quot;));
IoFreeMdl(Mdl);
IoFreeIrp(Irp);
ExFreePool(ConnectInfo);
return STATUS_UNSUCCESSFUL;
}
#endif

TdiBuildSendDatagram(
Irp, /* I/O Request Packet */
DeviceObject, /* Device object */
TransportObject, /* File object */
NULL, /* Completion routine */
NULL, /* Completion context */
Mdl, /* Descriptor for data buffer */
BufferSize, /* Size of data to send */
ConnectInfo); /* Connection information */

Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);

ExFreePool(ConnectInfo);

return Status;
}


NTSTATUS TdiReceiveDatagram(
PFILE_OBJECT TransportObject,
USHORT Port,
PULONG Address,
PUCHAR Buffer,
PULONG BufferSize)
/*
* FUNCTION: Receives a datagram
* ARGUMENTS:
* TransportObject = Pointer to transport object
* Port = Port to receive on
* Address = Address of buffer to place remote address
* Buffer = Address of buffer to place received data
* BufferSize = Address of buffer with length of Buffer (updated)
* RETURNS:
* Status of operation
*/
{
PTDI_CONNECTION_INFORMATION ReceiveInfo;
PTDI_CONNECTION_INFORMATION ReturnInfo;
PTA_IP_ADDRESS ReturnAddress;
PDEVICE_OBJECT DeviceObject;
PTDI_ADDRESS_IP IpAddress;
IO_STATUS_BLOCK Iosb;
PVOID MdlBuffer;
NTSTATUS Status;
PIRP Irp;
PMDL Mdl;

DeviceObject = IoGetRelatedDeviceObject(TransportObject);
if (!DeviceObject)
return STATUS_INVALID_PARAMETER;

ReceiveInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool,
sizeof(TDI_CONNECTION_INFORMATION) +
sizeof(TDI_CONNECTION_INFORMATION) +
sizeof(TA_IP_ADDRESS));

if (!ReceiveInfo)
return STATUS_INSUFFICIENT_RESOURCES;

MdlBuffer = ExAllocatePool(PagedPool, *BufferSize);
if (!MdlBuffer)
return STATUS_INSUFFICIENT_RESOURCES;

RtlZeroMemory(ReceiveInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TDI_CONNECTION_INFORMATION) +
sizeof(TA_IP_ADDRESS));

RtlCopyMemory(MdlBuffer, Buffer, *BufferSize);

/* Receive from any address */
ReceiveInfo->RemoteAddressLength = 0;
ReceiveInfo->RemoteAddress = NULL;

ReturnInfo = (PTDI_CONNECTION_INFORMATION) ((ULONG)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));
ReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
ReturnInfo->RemoteAddress = (PUCHAR) ((ULONG)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));

ReturnAddress = (PTA_IP_ADDRESS)(ReturnInfo->RemoteAddress);
ReturnAddress->TAAddressCount = 1;
ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
ReturnAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;

IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address);
IpAddress->sin_port = WH2N(Port);
IpAddress->in_addr = DH2N(LocalAddress);

Irp = TdiBuildInternalDeviceControlIrp(
TDI_RECEIVE_DATAGRAM, /* Sub function */
DeviceObject, /* Device object */
TransportObject, /* File object */
NULL, /* Event */
NULL); /* Return buffer */

if (!Irp)
{
ExFreePool(MdlBuffer);
ExFreePool(ReceiveInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}

Mdl = IoAllocateMdl(
MdlBuffer, /* Virtual address */
*BufferSize, /* Length of buffer */
FALSE, /* Not secondary */
FALSE, /* Don't charge quota */
NULL); /* Don't use IRP */

if (!Mdl)
{
IoFreeIrp(Irp);
ExFreePool(MdlBuffer);
ExFreePool(ReceiveInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}

#ifdef _MSC_VER
try
{
#endif
MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
#ifdef _MSC_VER
}
except (EXCEPTION_EXECUTE_HANDLER)
{
TDI_DbgPrint(MIN_TRACE, (&quot;MmProbeAndLockPages() failed./n&quot;));
IoFreeMdl(Mdl);
IoFreeIrp(Irp);
ExFreePool(MdlBuffer);
ExFreePool(ReceiveInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}
#endif

TdiBuildReceiveDatagram(
Irp, /* I/O Request Packet */
DeviceObject, /* Device object */
TransportObject, /* File object */
NULL, /* Completion routine */
NULL, /* Completion context */
Mdl, /* Data buffer */
*BufferSize, /* Size of data buffer */
ReceiveInfo, /* Connection information */
ReturnInfo, /* Connection information */
TDI_RECEIVE_NORMAL); /* Flags */

Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE);

if (NT_SUCCESS(Status))
{
RtlCopyMemory(Buffer, MdlBuffer, Iosb.Information);
*BufferSize = Iosb.Information;
*Address = DN2H(IpAddress->in_addr);
}

ExFreePool(MdlBuffer);
ExFreePool(ReceiveInfo);

return Status;
}


VOID TdiSendThread(
PVOID Context)
/*
* FUNCTION: Send thread
* ARGUMENTS:
* Context = Pointer to context information
* NOTES:
* Transmits an UDP packet every two seconds to ourselves on the chosen port
*/
{
KEVENT Event;
PKEVENT Events[2];
LARGE_INTEGER Timeout;
NTSTATUS Status = STATUS_SUCCESS;
UCHAR Data[40] = &quot;Testing one, two, three, ...&quot;;

if (!OpenError)
{
Timeout.QuadPart = 10000000L; /* Second factor */
Timeout.QuadPart *= 2; /* Number of seconds */
Timeout.QuadPart = -(Timeout.QuadPart); /* Relative time */

KeInitializeEvent(&Event, SynchronizationEvent, FALSE);

Events[0] = &StopEvent;
Events[1] = &Event;

while (NT_SUCCESS(Status))
{
/* Wait until timeout or stop flag is set */
KeWaitForMultipleObjects( 2, (PVOID)Events, WaitAny, Executive, KernelMode, FALSE, &Timeout, NULL);

if (KeReadStateEvent(&StopEvent) != 0)
{
TDI_DbgPrint(MAX_TRACE, (&quot;Received terminate signal.../n&quot;));
break;
}

DbgPrint(&quot;Sending data - '%s'/n&quot;, Data);

Status = TdiSendDatagram(TdiTransportObject, TEST_PORT, LocalAddress, Data, sizeof(Data));

if (!NT_SUCCESS(Status))
DbgPrint(&quot;Failed sending data (Status = 0x%X)/n&quot;, Status);
}
}

TDI_DbgPrint(MAX_TRACE, (&quot;Terminating send thread.../n&quot;));

PsTerminateSystemThread(STATUS_SUCCESS);
}


VOID TdiReceiveThread(
PVOID Context)
/*
* FUNCTION: Receive thread
* ARGUMENTS:
* Context = Pointer to context information
* NOTES:
* Waits until an UDP packet is received on the chosen endpoint and displays the data
*/
{
ULONG Address;
UCHAR Data[40];
ULONG Size;
NTSTATUS Status = STATUS_SUCCESS;

if (!OpenError)
{
while (NT_SUCCESS(Status))
{
Size = sizeof(Data);
RtlZeroMemory(Data, Size);

Status = TdiReceiveDatagram(TdiTransportObject, TEST_PORT, &Address, Data, &Size);

if (NT_SUCCESS(Status))
{
DbgPrint(&quot;Received data - '%s'/n&quot;, Data);
}
else
if (Status != STATUS_CANCELLED)
{
TDI_DbgPrint(MIN_TRACE, (&quot;Receive error (Status = 0x%X)./n&quot;, Status));
}
else
{
TDI_DbgPrint(MAX_TRACE, (&quot;IRP was cancelled./n&quot;));
}
}
}

TDI_DbgPrint(MAX_TRACE, (&quot;Terminating receive thread.../n&quot;));

PsTerminateSystemThread(STATUS_SUCCESS);
}


VOID TdiOpenThread(
PVOID Context)
/*
* FUNCTION: Open thread
* ARGUMENTS:
* Context = Pointer to context information (event)
*/
{
NTSTATUS Status;

TDI_DbgPrint(MAX_TRACE, (&quot;Called./n&quot;));

OpenError = TRUE;

Status = TdiOpenTransport(UDP_DEVICE_NAME, TEST_PORT, &TdiTransport, &TdiTransportObject);

if (NT_SUCCESS(Status))
{
Status = TdiQueryAddress(TdiTransportObject, &LocalAddress);

if (NT_SUCCESS(Status))
{
OpenError = FALSE;
DbgPrint(&quot;Using local IP address 0x%X/n&quot;, LocalAddress);
}
else
{
TDI_DbgPrint(MIN_TRACE, (&quot;Unable to determine local IP address./n&quot;));
}
}
else
TDI_DbgPrint(MIN_TRACE, (&quot;Cannot open transport (Status = 0x%X)./n&quot;, Status));

TDI_DbgPrint(MAX_TRACE, (&quot;Setting close event./n&quot;));

KeSetEvent((PKEVENT)Context, 0, FALSE);

TDI_DbgPrint(MIN_TRACE, (&quot;Leaving./n&quot;));
}


VOID TdiUnload(
PDRIVER_OBJECT DriverObject)
/*
* FUNCTION: Unload routine
* ARGUMENTS:
* DriverObject = Pointer to a driver object for this driver
*/
{
PVOID ReceiveThreadObject = 0;
PVOID SendThreadObject = 0;

TDI_DbgPrint(MAX_TRACE, (&quot;Setting stop flag/n&quot;));

/* Get pointers to the thread objects */
ObReferenceObjectByHandle(SendThread, THREAD_ALL_ACCESS, NULL, KernelMode, &SendThreadObject, NULL);
ObReferenceObjectByHandle(ReceiveThread, THREAD_ALL_ACCESS, NULL, KernelMode, &ReceiveThreadObject, NULL);

KeSetEvent(&StopEvent, 0, FALSE);

/* Wait for send thread to stop */
KeWaitForSingleObject(SendThreadObject, Executive, KernelMode, FALSE, NULL);

/* Wait for receive thread to stop */
KeWaitForSingleObject(ReceiveThreadObject, Executive, KernelMode, FALSE, NULL);

/* Close device */
TdiCloseDevice(TdiTransport, TdiTransportObject);
}


NTSTATUS
#ifndef _MSC_VER
STDCALL
#endif
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
/*
* FUNCTION: Main driver entry point
* ARGUMENTS:
* DriverObject = Pointer to a driver object for this driver
* RegistryPath = Registry node for configuration parameters
* RETURNS:
* Status of driver initialization
*/
{
KEVENT Event;
NTSTATUS Status;
WORK_QUEUE_ITEM WorkItem;

KeInitializeEvent(&StopEvent, NotificationEvent, FALSE);

/* Call TdiOpenThread() */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
ExInitializeWorkItem(&WorkItem, TdiOpenThread, &Event);
ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, NULL);

/* Create a UDP send thread that sends a dgram every 2 seconds */
Status = PsCreateSystemThread(
&SendThread, /* Thread handle */
0, /* Desired access */
NULL, /* Object attributes */
NULL, /* Process handle */
NULL, /* Client id */
(PKSTART_ROUTINE)TdiSendThread, /* Start routine */
NULL); /* Start context */

if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, (&quot;PsCreateSystemThread() failed for send thread (Status = 0x%X)./n&quot;, Status));
return STATUS_INSUFFICIENT_RESOURCES;
}

/* Create a UDP receive thread */
Status = PsCreateSystemThread(
&ReceiveThread, /* Thread handle */
0, /* Desired access */
NULL, /* Object attributes */
NULL, /* Process handle */
NULL, /* Client id */
(PKSTART_ROUTINE)TdiReceiveThread, /* Start routine */
NULL); /* Start context */

if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, (&quot;PsCreateSystemThread() failed for receive thread (Status = 0x%X)./n&quot;, Status));
ZwClose(SendThread);
return STATUS_INSUFFICIENT_RESOURCES;
}

DriverObject->DriverUnload = (PDRIVER_UNLOAD)TdiUnload;

return STATUS_SUCCESS;
}
 
大家做Delphi的觉得ring0是汇编吗?驱动是用汇编写的吗?哈哈,今天第一次觉得这群人可爱啊,驱动程序是PE的一种啊,跟Win32的dll没有本质区别,真的好可爱啊。有没有人觉得这么一个声明的函数不会调用:
NTSTATUS TdiSendDatagram(
PFILE_OBJECT TransportObject,
USHORT Port,
ULONG Address,
PVOID Buffer,
ULONG BufferSize);
这个函数你理解不了?不会调用?驱动里面的socket和win32里面的,你看了这个函数你觉得有差别吗?
 
再摘抄一个微软提供的内核socket的头文件,大家看明白了,也就明白我为什么跟那些伪高手,伪专家急了,看看他们说了些什么,仔细地看,他们的知识结构几乎不堪一击。

#if !defined(KSOCKET_H)
#define KSOCKET_H

#if defined(__cplusplus)
extern &quot;C&quot; {
#endif

typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;

#define AF_INET 2

#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3

#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17

#define INADDR_ANY 0x00000000
#define INADDR_LOOPBACK 0x7f000001
#define INADDR_BROADCAST 0xffffffff
#define INADDR_NONE 0xffffffff

#define MSG_OOB 0x1

#define SOMAXCONN 5

#define SD_RECEIVE 0x00
#define SD_SEND 0x01
#define SD_BOTH 0x02

#ifndef FD_SETSIZE
#define FD_SETSIZE 64
#endif

typedef struct fd_set {
u_int fd_count;
int fd_array[FD_SETSIZE];
} fd_set;

struct hostent {
char *h_name;
char **h_aliases;
short h_addrtype;
short h_length;
char **h_addr_list;
};

#define h_addr h_addr_list[0]

struct in_addr {
union {
struct { u_char s_b1, s_b2, s_b3, s_b4; } S_un_b;
struct { u_short s_w1, s_w2; } S_un_w;
u_long S_addr;
} S_un;
};

#define s_addr S_un.S_addr

struct protoent {
char *p_name;
char **p_aliases;
short p_proto;
};

struct servent {
char *s_name;
char **s_aliases;
short s_port;
char *s_proto;
};

struct sockaddr {
u_short sa_family;
char sa_data[14];
};

struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

struct timeval {
long tv_sec;
long tv_usec;
};

int __cdecl accept(int socket, struct sockaddr *addr, int *addrlen);
int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen);
int __cdecl close(int socket);
int __cdecl connect(int socket, const struct sockaddr *addr, int addrlen);
struct hostent * __cdecl gethostbyaddr(const char *addr, int addrlen, int type);
struct hostent * __cdecl gethostbyname(const char *name);
int __cdecl gethostname(char *name, int namelen);
int __cdecl getpeername(int socket, struct sockaddr *addr, int *addrlen);
struct protoent * __cdecl getprotobyname(const char *name);
struct protoent * __cdecl getprotobynumber(int number);
struct servent * __cdecl getservbyname(const char *name, const char *proto);
struct servent * __cdecl getservbyport(int port, const char *proto);
int __cdecl getsockname(int socket, struct sockaddr *addr, int *addrlen);
int __cdecl getsockopt(int socket, int level, int optname, char *optval, int *optlen);
u_long __cdecl htonl(u_long hostlong);
u_short __cdecl htons(u_short hostshort);
u_long __cdecl inet_addr(const char *name);
int __cdecl inet_aton(const char *name, struct in_addr *addr);
char * __cdecl inet_ntoa(struct in_addr addr);
int __cdecl listen(int socket, int backlog);
u_long __cdecl ntohl(u_long netlong);
u_short __cdecl ntohs(u_short netshort);
int __cdecl recv(int socket, char *buf, int len, int flags);
int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen);
int __cdecl select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);
int __cdecl send(int socket, const char *buf, int len, int flags);
int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen);
int __cdecl setsockopt(int socket, int level, int optname, const char *optval, int optlen);
int __cdecl shutdown(int socket, int how);
int __cdecl socket(int af, int type, int protocol);

#if defined(__cplusplus)
}
#endif

#endif // !defined(KSOCKET_H)
 
哈哈,真的没有想到,一个帖子,一个完成端口,把一群所谓的高手们,一群从delphibbs创立就很活跃的所谓高手,全都弄得丑态百出,群形毕露。

我不知道这些人是不是某些公司的重要人员,也不知道他们现在究竟在做什么,这么多年来你们关注了什么,学习了什么呢?

我觉得进入这个论坛,这个帖子,让我感觉进入了黑暗时代,中世纪的“暗黑”岁月,搞Delphi网络编程的搞到完成端口算是NB吧,会用几个API,内存池,就不得了了吗?耶稣来到这里传教都会害怕,一个个被拉来的都是什么人啊,这个圈子需要用谎言堆积来维护吗?

公元2006年了,和win32 dll几乎一样的驱动程序,竟然让少数所谓高手专家描述成洪水猛兽,这能维护你在Delphi圈子里面的尊严吗?你的面子那么重要吗,掉到了地上需要拉这么多人帮你来拣面子吗?[:D]
 
以我这个年龄的人是不屑于与小辈叫骂的,不过,看样子中国急需加强汉语教育了,
毕竟在中国还是以汉语为主的,如果连汉语都看不懂,真不知道该如何与人交流、沟通。

任何比较都不能脱离它的具体环境,每一个比较的项目要确定他的内涵和外延,什么叫
作效率高?是1秒钟执行1000条指令高还是1秒钟执行100条指令高?是占用1K内存效率
高还是1M效率高?类似这些都需要明确。何况,在资源有限的情况下,A程序运行时间
多些,B程序就少些,除非你的机器只做一件事,只运行你的程序。

看任何问题都不要绝对化,事事都有例外,Ring0,底层,汇编就代表了高效率吗?
恐怕并非如此吧,同样的工具在不同的人的手里效率是不同的,可能甲写出来的就是高效
率的,乙写出来的就是垃圾。看不懂“未必”这个词可以查词典,否则,丢脸的是自己。
 
单纯脱离环境讲究效率是愚蠢的行为。
看看现在的JAVA,还有上面多位朋友提到的各种大行其道的脚本语言。世界已经变了。。。
 
[:D]楼上的tseug老先生,我声音大一点哦,怕你耳朵不好听不到,中庸先生是当不得的。

到底效率高低是有数字的,是有统计学来方法来证明的,是有全球著名的实验室的数据来说明的,软件评测,硬件评测,CPU评测,这些都有权威的工具来测试出对比数据图的。

如果你偏说这个也不相信,我也只能表示无奈,在你眼里,用了MMX,SSE指令的也不一定比你的效率高,FastCode修改了Delphi的很多基础函数,每个函数都提供MMX,SSE,Pascal的函数对比测试例子,运行100亿次,性能对比图马上就出来。你的论据全是中庸的,在技术上我鄙视这种中庸,我引用的瑞典大学的论文在年会上发表过,你不相信我也真的不敢怎么样你。

Delphi的性能比VB的高,我想大家接受这个,因为是国外那些著名的评测机构用软件测试出来的,传到中国渐渐被接受,当然现在还有VB开发者不认同,精神上我认为可以理解。按照你的中庸观点,遇到SB DElphi开发者,效率不一定比VB的高,这能改变什么吗?
 
张无忌:世界变了你不用害怕,工作换了你也不要害怕,真的,认识到了本质,你就会有饭吃,做上层的总有不安全感,你这么声嘶力竭的喊出来,这语气我能理解,战栗的声音代表了广大Dlephi开发者的心声——明天在何处,我该怎么走?。

所以我鼓励你去钻下去,你的能力应该在内核开发上能够有所体现,嵌入式开发需要你们这种人,真的,有一天你能理解内核的力量,那么就是真的“王者归来”了。
 
硬件的接口有可能变化,内核也是有可能变的。所以驱动开发方式肯定也会变,比如WIN2K和驱动和VISTA的驱动开发未必一样。相反上层应用对于JAVA,各种脚本语言,由于有虚拟机去处理这些细节,上层代码基本上可以不做修改照样运行。你WIN2K的驱动代码未必能在VISTA上跑,而JAVA或者其他脚本确不用做修改照样运行。
 
无忌,你又错了。内核开发的稳健性是有目共睹的,相反上层的开发才能用一日千里来形容,拿你所熟悉的Delphi编译器,你知道核心代码10年来到现在动了多少吗?很少动!所以搞内核开发多舒服啊。

因为如果内核变了,它所承载的金字塔是什么呢?上千万的程序都要改写。因此内核开发非常重视这种修正,XP已经5年了,linux从2.4跳到2.6也5,6年了,WDM驱动框架13年了。熟悉了内核,你写一个win的驱动,很容易移植到liu上,真的不难啊,谁用谁知道!

微软的每个内核框架都是他们的大批团队的心血结晶,涉及到大量的专利和技术,这些内核设计的非常漂亮,也就是Tobject的概念,升级什么东西都是面向对象的,这个底盘是平滑的,温顺的。阿门,感谢发明分层构架的科学家们。

孩子,不用怕,做内核开发有趣有序。win2k的驱动用vista编译器重新编译就能在vista上跑,vista从推出测试到发布,几年了?做内核开发真的好悠闲了,微软早先就给所有的驱动开发者提供新技术的所有细节,就是让你的驱动平滑的升级。做驱动是内核开发的一部分,你真的很适合,不用怕,别被吓着。[:)]
 
to 王府井:
你是一叶障目,你说普通软件不行,驱动重要,恐怕那么那些做硬件,芯片的浮躁人士
要笑了,他们认为各种数字电路更加重要,他们优化一下设计比驱动优化100下能带来
更好的性能,因为你的所谓驱动都是在等他们给饭吃,他们罢工你们就危险了,就如同
你刚才说的高效的网络层碰上一个烂网卡再怎么牛X也用不上力,呵呵。话扯远了。
做硬件的鄙视做驱动的,做驱动鄙视做应用软件的,人家BOSS说这些人都是给他打工
的了,这么相互看不起有什么意义了?
对于软件开发,每人做好自己的工作,在自己的领域内保证高效和可扩展性就够了。
鄙视其他领域的开发是没有任何意义的。
 
正所谓我不入地狱谁入地狱,放下Delphi的杀猪刀,进入修炼内核的佛道来吧。再锤炼你的杀猪刀,你都是屠夫,有天你会累,有一天你会老,有天你的刀举起,再也抡不圆,有一天你的刀插入,流泪的是自己。猪会蔑视屠夫吗,我想会的。

borland是一个商业公司,delphi是一个商业工具,就算你有再多的感情在这里,心早晚都会碎的,没有听过那首歌吗?你最爱的人,却伤你最深。

开发的队伍已经在分化了,有些人沉了下去,有些人浮了上来。我劝那些有慧根的高手,去做你能真正驾驭的事情吧,随波逐流,最终会被机器取代,会被世界遗忘的。
 
to 张无忌:你有这个能力深入下去研究内核,至少我觉得你不浮躁。被人强拉来,我想也是你的失误。

我已经陈述过好多次,做驱动并不是做硬件驱动,驱动被微软划分了很多层,只有最下层的实现类驱动才是和硬件打交道的,这是一个树形结构的图,就像你展开一个注册表的树一样,接触到硬件的是最初一两个节点,更多的叶子在繁茂的开着。

我已经举例很多次了,网络硬盘,杀毒软件,防火墙,这些你日常接触的驱动编程跟你的网卡有关吗?

为什么非要做一个调用别人接口的普通程序员呢?

你跳一下,其实可以够到更多的果子的,因为你有你的思想,有深入思考的能力。
 
以前不知技术中庸如此受鄙视,今天第一次听说。从2000年开始一直在工地上混,眼见
着一群中庸的人用中庸的技术,踏踏实实地修建起一条条高速公路。

忽然间想起以前《神鞭》的一个台词:
祖宗的东西再好,到了该割的时候也得割,辫子剪了,神留着,一变还是绝活
 
[:D]楼上的tseug,本人有听在中国工地上,做钢筋预算都能少几百万的,用竹子插在里面充数是小case,黄河小浪底被人举报用竹子代替钢筋,举报人被追杀跑到中南海门口都被抓了回去。我不知道楼上看到这个是不是睁一只眼,闭一只眼呢?

中庸之道不会让自己有杀身之祸,但是更多的人,在高速上跑得上千万汽车呢?三峡下面的9个省呢?小浪底下面的河南呢?

我相信如果tseug真的是纯洁的,下次我家的厨房装修找你们工程队。
 
你说用竹子代替钢筋,没听说过,在我参与的几个工程中也没见过。建设工程有着严格
的程序,我不否认其中有腐败,但总体上还是好的,绝大多数人不会拿自己的前途去冒
险。至于预算差了几百万,不知道你为何那么惊讶,在我看来,很平常,一般来说每个
工程大约有3%计日工、5%不可预见费(具体各地不同),一个2000万的小项目就是160万
何况一般高速公路都是几十个亿的项目。

话题越扯越远,不知道楼主会怎么想。

顺便说一句,我没有工程队,你们家装修帮不上忙了。
 
[:D],呵呵,扯远了,tseug是值得敬佩的,你不要被人拉来趟浑水嘛,那些人用心险恶啊,这下中庸之道老同志怎么又不会用了呢?是不是觉得我小,好欺负哦,呵呵,拉手和好吧。

引用一句赵丽蓉老太的话,啥群英荟萃,萝卜开会哦。
 
>>为什么非要做一个调用别人接口的普通程序员呢?
你做驱动不调别人接口?不响应硬件的中断?牛皮不是你那么吹的。
即使做硬件也要用那些专业的设计软件来设计。
在一个开发团对里,你不用别人开发的模块?你以为你是神仙啊,
什么都自己做。
 
顶部