能力值:
( LV2,RANK:10 )
|
-
-
2 楼
别沉啊? 大家给点思路吧
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
今天早上过来又试了一下,还是没有解决,谁给点思路吧
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
发现一个新的情况,刚在 Win7下面尝试了一下,发现无论读写,速度都很快
XP下面还是很慢,这样就奇怪了,看起来跟操作系统有点关系
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
终于找到原因了,是因为Nagle算法。
TCP在发送数据时,会先把数据存到内部的一个Buffer里面,然后跟下次send的数据进行合并,当大于一个阀值时,数据才真正send的出去。
当然这里有一个超时处理,如果在一定时间内(大约是40ms),没有收集到足够的数据,那么,也会发送出去。
所以,解决方法有两个:
1. 采用”send-recv-send-recv“的模型
也就是说,两个连续的send之间,必须插入一次 recv 请求,这样在recv的时候,TCP返回了对端的ACK确认,这样 send 请求得以继续
2. 在内核中禁用”Nagle“算法
折腾了两天,尝试了很多代码,都没有结果。
#include <tdiinfo.h>
#define IOCTL_TCP_SET_INFORMATION_EX \
CTL_CODE(FILE_DEVICE_NETWORK, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_TCP_QUERY_INFORMATION_EX \
CTL_CODE(FILE_DEVICE_NETWORK, 0, METHOD_NEITHER, FILE_ANY_ACCESS)
#define TL_INSTANCE 0
#define TCP_SOCKET_NODELAY 1
// NoDelay is currently off and the application wants to turn it on.
NTSTATUS TdiSetTcpNoDelay(PFILE_OBJECT connectionFileObject)
{
PDEVICE_OBJECT devObj;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
PIO_STACK_LOCATION StackLocation;
INT optionValue = TRUE;
PTCP_REQUEST_SET_INFORMATION_EX setInfoEx = NULL;
ULONG len = sizeof(TCP_REQUEST_SET_INFORMATION_EX)+sizeof(INT);
KeInitializeEvent(&event, NotificationEvent, FALSE);
devObj = IoGetRelatedDeviceObject(connectionFileObject);
setInfoEx = ExAllocatePoolWithTag(NonPagedPool, len, VDISK_TAG);
//
// Initialize the TDI information buffers.
//
setInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
setInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
setInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
setInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
setInfoEx->ID.toi_id = TCP_SOCKET_NODELAY;
memcpy( setInfoEx->Buffer, &optionValue, sizeof(INT) );
setInfoEx->BufferSize = sizeof(INT);
irp = IoBuildDeviceIoControlRequest (
IOCTL_TCP_SET_INFORMATION_EX,
devObj,
setInfoEx,
len,
NULL,
0,
FALSE,
&event,
&iosb);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
StackLocation = IoGetNextIrpStackLocation( irp );
StackLocation->FileObject = connectionFileObject;
status = IoCallDriver(devObj, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = iosb.Status;
}
KdPrint(("TdiSetInformation status = 0x%x\n", status));
return NT_SUCCESS(status) ? (ULONG) iosb.Information : status;
}
虽然IoCallDriver的返回值是成功的,但是却没有任何效果,
如果有人知道,如何在内核禁用Nagle算法,还请赐教!先谢谢了
|
|
|