如何关闭一个TCP连接 请问我想在上边的图中右击,关闭当前选择的连接该如何写 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 建議使用SetTcpEntry試試看因為使用idhttp,idftp都是这样的. 程序掉用disconnect后,再在dos下netstat -an 发现还有连接 状态是 Timer_wait,要过一会儿才会消失. 不知道这是不是indy的 "温和关闭 "有关系? 用nmhttp没有问题.基本上不写disconnect,只要free一下,netstat -an都不会看到连接了.一般约一分钟左右这个SOCKET句柄状态会由TIME_WAIT变为CLOSE 所以:在TCP协议里面,有所谓的半关闭.就是要关闭连接时候,SOCKET两端底层是互发 FIN---ACK包(IP包) 一问一答. 为了确保最后的传输用户数据不会被丢掉..SOCKET在发出FIN之后,停止自己这端发出数据,继续收数据, 在接收对端最终ACK应答后才会最终进入CLOSE状态. 在WINDOWS下面..调用SOCKET API的时候,这些有可能实现得不够完美..但一般不容易出大问题. 获取它的句柄,然后CloseHandle 如果你用的INDY控件,用Connection.Disconnect就可以不过如一楼所说,断开连接有一定的延时。 我没用任何INDY的控件 我想要立刻结束我想要结束的TCP连接代码 列出当前进程和端口的对应再谈进程与端口的映射 发布者: ILSY(at: er263.net) · 发布日期: 2002-02-05 · 来源: whitecell.org Author : ilsy Email : [email protected] HomePage: http://www.whitecell.org 日 期:2002-02-06类 别:安全 关键字:进程 PDE PTE 分页 内核对象 线性地址 物理地址 关于进程与端口映射的文章已经有很多了,我把我对fport的分析也写出来,让大家知道fport是如何工作的.fport.exe是由foundstone team出品的免费软件,可以列出系统中所有开放的端口都是由那些进程打开的.而下面所描述的方法是基于fport v1.33的,如果和你机器上的fport有出入,请检查fport版本. 首先,它检测当前用户是否拥有管理员权限(通过读取当前进程的令牌可知当前用户是否具有管理权限,请参考相关历程),如果没有,打印一句提示后退出,然后设置当前进程的令牌,接着,用ZwOpenSection函数打开内核对象\Device\PhysicalMemory,这个对象用于对系统物理内存的访问.ZwOpenSection函数的原型如下: NTSYSAPINTSTSTUSNTAPIZwOpenSection( Out PHANDLE sectionHandle; IN ACCESS_MASK DesiredAccess; IN POBJECT_ATTRIBUTES ObjectAttributes };(见ntddk.h) 第一个参数得到函数执行成功后的句柄第二个参数DesiredAccess为一个常数,可以是下列值: #define SECTION_QUERY 0x0001 #define SECTION_MAP_WRITE 0x0002 #define SECTION_MAP_READ 0x0004 #define SECTION_MAP_EXECUTE 0x0008 #define SECTION_EXTEND_SIZE 0x0010 #define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|\ SECTION_MAP_WRITE | \ SECTION_MAP_READ | \ SECTION_MAP_EXECUTE | \ SECTION_EXTEND_SIZE) (见ntddk.h)第三个参数是一个结构,包含要打开的对象类型等信息,结构定义如下: typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE } OBJECT_ATTRIBUTES; typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; (见ntdef.h)对于这个结构的初始化用一个宏完成: #define InitializeObjectAttributes( p, n, a, r, s ) { \ (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ (p)->RootDirectory = r; \ (p)->Attributes = a; \ (p)->ObjectName = n; \ (p)->SecurityDescriptor = s; \ (p)->SecurityQualityOfService = NULL; \ } (见ntdef.h)那么,打开内核对象\Device\PhysicalMemory的语句如下:WCHAR PhysmemName[] = L"\\Device\\PhysicalMemory";void * pMapPhysicalMemory;HANDLE pHandle; bool OpenPhysicalMemory(){ NTSTATUS status; UNICODE_STRING physmemString; OBJECT_ATTRIBUTES attributes; RtlInitUnicodeString( &physmemString, PhysmemName ); //初始化Unicode字符串,函数原型见ntddk.h InitializeObjectAttributes( &attributes, &physmemString, OBJ_CASE_INSENSITIVE, NULL, NULL ); //初始化OBJECT_ATTRIBUTES结构 status = ZwOpenSection(pHandle, SECTION_MAP_READ, &attributes ); //打开内核对象\Device\PhysicalMemory,获得句柄 if( !NT_SUCCESS( status )) return false; pMapPhysicalMemory=MapViewOfFile(pHandle,FILE_MAP_READ, 0,0x30000,0x1000); //从内存地址0x30000开始映射0x1000个字节 if( GetLastError()!=0) return false; return true;} 为什么要从0x30000开始映射呢,是这样,我们知道,在Windows NT/2000下,系统分为内核模式和用户模式,也就是我们所说的Ring0和Ring3,在Windows NT/2000下,我们所能够看到的进程都运行在Ring3下,一般情况下,系统进程(也就是System进程)的页目录(PDE)所在物理地址地址为0x30000,或者说,系统中最小的页目录所在的物理地址为0x30000.而页目录(PDE)由1024项组成,每项均指向一页表(PTE),每一页表也由1024个页组成,而每页的大小为4K,1024*4=4096(0x1000),所以,上面从物理地址0x30000开始映射了0x1000个字节.(具体描述见WebCrazy的文章<<小议Windows NT/2000的分页机制>>) 程序打开打开内核对象\Device\PhysicalMemory后,继续用函数ZwOpenFile打开内核对象\Device\Tcp和Device\Udp,ZwOpenFile函数的原型如下:NTSYSAPINTSTATUSNTAPIZwOpenFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions );(见ntddk.h) 第一个参数返回打开对象的句柄第二个参数DesiredAccess为一个常数,可以是下列值: #define FILE_READ_DATA ( 0x0001 ) // file & pipe #define FILE_LIST_DIRECTORY ( 0x0001 ) // directory #define FILE_WRITE_DATA ( 0x0002 ) // file & pipe #define FILE_ADD_FILE ( 0x0002 ) // directory #define FILE_APPEND_DATA ( 0x0004 ) // file #define FILE_ADD_SUBDIRECTORY ( 0x0004 ) // directory #define FILE_CREATE_PIPE_INSTANCE ( 0x0004 ) // named pipe #define FILE_READ_EA ( 0x0008 ) // file & directory #define FILE_WRITE_EA ( 0x0010 ) // file & directory #define FILE_EXECUTE ( 0x0020 ) // file #define FILE_TRAVERSE ( 0x0020 ) // directory #define FILE_DELETE_CHILD ( 0x0040 ) // directory #define FILE_READ_ATTRIBUTES ( 0x0080 ) // all #define FILE_WRITE_ATTRIBUTES ( 0x0100 ) // all #define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) #define FILE_GENERIC_READ (STANDARD_RIGHTS_READ |\ FILE_READ_DATA |\ FILE_READ_ATTRIBUTES |\ FILE_READ_EA |\ SYNCHRONIZE) #define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\ FILE_WRITE_DATA |\ FILE_WRITE_ATTRIBUTES |\ FILE_WRITE_EA |\ FILE_APPEND_DATA |\ SYNCHRONIZE) #define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE |\ FILE_READ_ATTRIBUTES |\ FILE_EXECUTE |\ SYNCHRONIZE) (见ntdef.h)第三个参数是一个结构,包含要打开的对象类型等信息,结构定义见上面所述第四个参数返回打开对象的属性,是一个结构,定义如下: typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; #if defined(_WIN64) typedef struct _IO_STATUS_BLOCK32 { NTSTATUS Status; ULONG Information; } IO_STATUS_BLOCK32, *PIO_STATUS_BLOCK32; #endif (见ntddk.h)第五个参数ShareAccess是一个常数,可以是下列值: #define FILE_SHARE_READ 0x00000001 // winnt #define FILE_SHARE_WRITE 0x00000002 // winnt #define FILE_SHARE_DELETE 0x00000004 // winnt (见ntddk.h)第六个参数OpenOptions也是一个常数,可以是下列的值: #define FILE_DIRECTORY_FILE 0x00000001 #define FILE_WRITE_THROUGH 0x00000002 #define FILE_SEQUENTIAL_ONLY 0x00000004 #define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 #define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 #define FILE_NON_DIRECTORY_FILE 0x00000040 #define FILE_CREATE_TREE_CONNECTION 0x00000080 #define FILE_COMPLETE_IF_OPLOCKED 0x00000100 #define FILE_NO_EA_KNOWLEDGE 0x00000200 #define FILE_OPEN_FOR_RECOVERY 0x00000400 #define FILE_RANDOM_ACCESS 0x00000800 #define FILE_DELETE_ON_CLOSE 0x00001000 #define FILE_OPEN_BY_FILE_ID 0x00002000 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 #define FILE_NO_COMPRESSION 0x00008000 #define FILE_RESERVE_OPFILTER 0x00100000 #define FILE_OPEN_REPARSE_POINT 0x00200000 #define FILE_OPEN_NO_RECALL 0x00400000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 #define FILE_COPY_STRUCTURED_STORAGE 0x00000041 #define FILE_STRUCTURED_STORAGE 0x00000441 #define FILE_VALID_OPTION_FLAGS 0x00ffffff #define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 #define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 #define FILE_VALID_SET_FLAGS 0x00000036 (见ntddk.h) 那么,打开内核对象\Device\Tcp和\Device\Udp的语句如下: WCHAR physmemNameTcp[]=L"\\Device\\TCP";WCHAR physmemNameUdp[]=L"\\Device\\UDP";HANDLE pTcpHandle;HANDLE pUdpHandle; HANDLE OpenDeviceTcpUdp(WCHAR * deviceName){ NTSTATUS status; UNICODE_STRING physmemString; OBJECT_ATTRIBUTES attributes; IO_STATUS_BLOCK iosb; HANDLE pDeviceHandle; RtlInitUnicodeString(&physmemString, deviceName); if(GetLastError()!=0) return NULL; InitializeObjectAttributes( &attributes,&physmemString, OBJ_CASE_INSENSITIVE,0, NULL ); status = ZwOpenFile ( &pDeviceHandle,0x100000, &attributes, &iosb, 3,0); if( !NT_SUCCESS( status )) return NULL;} 接着,程序用ZwQuerySystemInformation函数获得系统当前所以进程的所建立的句柄及其相关信息,函数的原型如下:NTSYSAPINTSTATUSNTAPI ZwQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL };(这个函数结构Microsoft没有公开,参见Gary Nebbett<<Windows NT/2000 Native API Reference>>) 第一个参数是一个枚举常数,设置要查询的系统信息类型,ZwQuerySystemInformation支持54个系统信息的查询,我们要用到的是它的第16号功能,进行SystemHandleInformation查询.SYSTEM_HANDLE_INFORMATION结构定义如下: typedef struct _SYSTEM_HANDLE_INFORMATION{ ULONG ProcessID; //进程的标识ID UCHAR ObjectTypeNumber; //对象类型 UCHAR Flags; //0x01 = PROTECT_FROM_CLOSE,0x02 = INHERIT USHORT Handle; //对象句柄的数值 PVOID Object; //对象句柄所指的内核对象地址 ACCESS_MASK GrantedAccess; //创建句柄时所准许的对象的访问权 }SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; (这个函数结构Microsoft没有公开,参见Gary Nebbett<<Windows NT/2000 Native API Reference>>)第二个参数输出查询的结果第三个参数设置缓冲区的长度第四个参数返回函数正确执行需要的缓冲区的大小代码如下:#define SystemHandleInformation 16PULONG GetHandleList(){ ULONG cbBuffer = 0x1000; //先设定一个较小的缓冲空间 PULONG pBuffer = new ULONG[cbBuffer]; //分配内存 NTSTATUS Status; do { Status = ZwQuerySystemInformation( SystemHandleInformation, pBuffer, cbBuffer * sizeof * pBuffer, NULL); if (Status == STATUS_INFO_LENGTH_MISMATCH) { //如果返回的错误信息为缓冲区长度不够,那么重新分配内存 delete [] pBuffer; pBuffer = new ULONG[cbBuffer *= 2]; } else if (!NT_SUCCESS(Status)) { //如果是其他错误信息,返回 delete [] pBuffer; return false; } } while (Status == STATUS_INFO_LENGTH_MISMATCH); return pBuffer;} 因为如果一个进程打开了端口,那么它肯定会建立类型为\Device\Tcp和\Device\Udp的内核对象,所以,我们在当前进程中打开上述的两个内核对象,在打开的同时保存了打开的句柄,这样,我们可以在上面获得的句柄列表中的当前进程中查找对象句柄的数值和我们保存的两个打开的内核对象的句柄数值相同的句柄,并得到其句柄所指向的内核对象的地址.代码如下:DWORD TcpHandle;DWORD UdpHandle;DWORD GetTcpUdpObject(PULONG pBuffer,HANDLE pHandle,DWORD ProcessId){ DWORD objTYPE1,objTYPE2,HandleObject; PSYSTEM_HANDLE_INFORMATION pProcesses = (PSYSTEM_HANDLE_INFORMATION)(pBuffer+1); for (i=0;i< * pBuffer;i++) { if ((pProcesses[i].ProcessID) == ProcessId) { objTYPE1 = (DWORD)hDeviceTcpUdp; objTYPE2 = (DWORD)pProcesses[i].Handle; if(objTYPE1==objTYPE2) { HandleObject = (DWORD)pProcesses.Object; return HandleObject; } } return 0;} 这个内核对象地址是一个线性地址,我们需要把这个地址转换为物理地址,并得到一些相关的数据.在fport中,换算是这样进行的:(具体描述见WebCrazy的文章<<小议Windows NT/2000的分页机制>>)void * NewmapPhy; void GetPTE(DWORD objAddress){ DWORD physmemBuff; DWORD newAddress1,newAddress2,newAddress3,newAddress4; DWORD * newAddress; physmemBuff = (DWORD)pMapPhysicalMemory; newAddress1 = physmemBuff+(objAddress>>0x16)*4; newAddress = (DWORD *)newAddress1; newAddress1 = * newAddress; newAddress2 = objAddress & 0x3FF000; newAddress3 = newAddress1 & 0x0FFFFF000; newAddress4 = newAddress2 + newAddress3; NewmapPhy = MapViewOfFile(ghPhysicalMemory,FILE_MAP_READ,0,newAddress4,0x1000); //重新映射物理内存,得到当前线性地址所指向的PTE的物理地址内容} 然后在根据内核对象的线性地址得到这个地址所指向的物理页,得到体现当前内核对象内容的页,其结构如下:typedef struct { ULONG Present; ULONG WriteTable; ULONG User; ULONG WriteThru; ULONG NoCache; ULONG Accessed; ULONG Dirty; ULONG PageSize; ULONG Global; ULONG Available; ULONG Pfn;} PTE, *PPTE;(注:我不能保证这个结构的正确性,但我们只会用到其中的两个值,对程序来说,这个结构是可以工作的,^_^)代码如下:ULONG CurrWriteTable;ULONG NoCache; void GetMustPar(DWORD objAddress){ DWORD CurrAddress; CurrAddress = objAddress & 0xFFF; PPTE pte = (PPTE)(VOID *)((DWORD)NewmapPhy+CurrAddress); CurrWriteTable = pte->WriteTable; CurrNoCache = Pte->NoCache;} 好了,我们现在想要得到的都已经得到了,下面需要做的是遍历进程,用每一个进程中的每一个句柄(呵呵,不是每一个句柄,在Windows NT下,\Device\Tcp和\Device\Udp的句柄类型值为0x16,在Windows 2000下这个值为0x1A)的核心地址用上面所描述的办法得到其PTE内容,得到其WriteTable值,如果与内核对象\Device\Tcp和\Device\Udp相等,那么这个句柄就有可能打开了一个端口,再对这个句柄进行确认,就可以了.确认的代码如下:typedef struct _TDI_CONNECTION_INFO { ULONG State; ULONG Event; ULONG TransmittedTsdus; ULONG ReceivedTsdus; ULONG TransmissionErrors; ULONG ReceiveErrors; LARGE_INTEGER Throughput; LARGE_INTEGER Delay; ULONG SendBufferSize; ULONG ReceiveBufferSize; BOOLEAN Unreliable; } TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO; typedef struct _TDI_CONNECTION_INFORMATION { LONG UserDataLength; PVOID UserData; LONG OptionsLength; PVOID Options; LONG RemoteAddressLength; PVOID RemoteAddress; } TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION; (以上结构见tdi.h) void GetOpenPort(DWORD dwProcessesID,USHORT Handle,int NoCache)//dwProcessesID为进程标识ID//Handle为进程打开的句柄,并且经过比较为\Device\Tcp或\Device\Udp类型//NoCache为PTE结构中的一个值 { HANDLE hProc,DupHandle=NULL; HANDLE hEven=NULL; OVERLAPPED overlap; u_short openport; int i=0; char procName[256]={0}; int portflag=0; overlap.Internal = 0; overlap.InternalHigh = 0; overlap.Offset = 0; overlap.OffsetHigh = 0; hEven=CreateEvent(0,1,0,0); overlap.hEvent = hEven; hProc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwProcessesID); if(hProc) { DuplicateHandle(hProc, (HANDLE)Handle, GetCurrentProcess(), &DupHandle, 0, FALSE, 2); CloseHandle( hProc ); if(DupHandle) { TDI_CONNECTION_INFO TdiConnInfo={0}; TDI_CONNECTION_INFORMATION TdiConnInformation={0}; DWORD dwRetu=0; if(NoCache==0x2) { TdiConnInformation.RemoteAddressLength= 4; if(DeviceIoControl(DupHandle,0x210012, &TdiConnInformation,sizeof(TdiConnInformation), &TdiConnInfo,sizeof(TdiConnInfo), 0,&overlap)) //进行TDI查询,得到连接的相关信息 { openport = ntohs((u_short)TdiConnInfo.ReceivedTsdus); procname = GetProcName(dwProcessesID); //得到进程标识ID的进程名称 printf("PID = %4d ProcessName = %15s PORT = %4d\n",dwProcessesID,procName,openport); } } if(NoCache==0x1) { TdiConnInformation.RemoteAddressLength= 3; if(DeviceIoControl(DupHandle,0x210012, &TdiConnInformation,sizeof(TdiConnInformation), &TdiConnInfo,sizeof(TdiConnInfo), 0,&overlap)) //进行TDI查询,得到连接的相关信息 { openport = ntohs((u_short)TdiConnInfo.ReceivedTsdus); procname = GetProcName(dwProcessesID); //得到进程标识ID的进程名称 printf("PID = %4d ProcessName = %15s PORT = %4d\n",dwProcessesID,procName,openport); } } } } CloseHandle(hEven); CloseHandle(DupHandle);} 以上是我对fport.exe的分析及其实现代码,演示程序可以从whitecell.org下载,如果你发现有问题,请通知我,^_^ 参考: fport.exeGary Nebbett<<Windows NT/2000 Native API Reference>>WebCrazy<<小议Windows NT/2000分页机制>>NTDDK 抱歉 一直看下来都看不懂.C的我完全看不懂进程的名和ID、TCP连接我都写好了 就是不知该如何结束某个进程的某个TCP连接 关于最小化到拖盘的问题 在excel里面怎样进行下述(类4舍5入)转化? 别人给了个示例函数结果调用的时候总出错,请帮忙指点一下如何调用它,见内。高分相谢! 如果用DELPHI在SQL内存入jpb图片 怪怪怪,在XP/2000下正常执行,但在win98下竟然不正常!!! 高手请进,串口通信问题! 帮忙修改一下此函数中的错误,不甚感激 delphi中的16进制数怎么表示!? 为什么 请教一个问题啊. 调试时,提示 Undeclared identifier: 'String' 我有一个心愿,就是请资深版主aiirii回来坐坐
程序掉用disconnect后,再在dos下netstat -an
发现还有连接 状态是 Timer_wait,要过一会儿才会消失.
不知道这是不是indy的 "温和关闭 "有关系?
用nmhttp没有问题.基本上不写disconnect,只要free一下,netstat -an都不会看到连接了.
一般约一分钟左右这个SOCKET句柄状态会由TIME_WAIT变为CLOSE
所以:
在TCP协议里面,有所谓的半关闭.就是要关闭连接时候,SOCKET两端底层是互发
FIN---ACK包(IP包) 一问一答.
为了确保最后的传输用户数据不会被丢掉..SOCKET在发出FIN之后,停止自己这端发出数据,继续收数据,
在接收对端最终ACK应答后才会最终进入CLOSE状态. 在WINDOWS下面..调用SOCKET API的时候,这些有可能实现得不够完美..但一般不容易出大问题.
不过如一楼所说,断开连接有一定的延时。