How can I kill a Websocket connection?

六眼飞鱼酱① 提交于 2021-02-19 03:16:06

问题


How can I kill a Websocket connection? I'm not talking about closing the connection on either end but interrupting it "in the middle". I need to test some application logic that must happen on a reconnect (which is handled through SocketIO).

And no, unplugging the network cable doesn't count because I can't really automate that in a unit test :-) Besides, I wish to kill only one specific connection and not all of them.


回答1:


It is painful, but it is possible. You can find an explanation here. The code is as follows:

using System;
using System.Collections;
using System.Runtime.InteropServices;
/// <summary>
/// This is a class for disconnecting TCP connections.
/// You can get a list of all connections and close by a connection, localIP, 
///  remoteIP, localPort and remotePort.
/// </summary>
public class Disconnecter {
        //Enumeration of the states
        public enum State{
                All=0,
                Closed=1,
                Listen=2,
                Syn_Sent=3,
                Syn_Rcvd=4,
                Established=5,
                Fin_Wait1=6,
                Fin_Wait2=7,
                Close_Wait=8,
                Closing=9,
                Last_Ack=10,
                Time_Wait=11,
                Delete_TCB=12
        }
        //Connection info
        private struct MIB_TCPROW{
                public int dwState;
                public int dwLocalAddr;
                public int dwLocalPort;
                public int dwRemoteAddr;
                public int dwRemotePort;
        }
        //API to get list of connections
        [DllImport("iphlpapi.dll")]
        private static extern int GetTcpTable(IntPtr pTcpTable,ref int pdwSize,bool bOrder);
        //API to change status of connection
        [DllImport("iphlpapi.dll")]
                //private static extern int SetTcpEntry(MIB_TCPROW tcprow);
        private static extern int SetTcpEntry(IntPtr pTcprow);
        //Convert 16-bit value from network to host byte order
        [DllImport("wsock32.dll")]
        private static extern int ntohs(int netshort);
        //Convert 16-bit value back again
        [DllImport("wsock32.dll")]
        private static extern int htons(int netshort);

        //Close all connection to the remote IP
        public static void CloseRemoteIP(string IP){
                MIB_TCPROW[] rows = getTcpTable();
                for(int i=0; i<rows.Length; i++){
                        if(rows[i].dwRemoteAddr==IPStringToInt(IP)){
                                rows[i].dwState = (int) State.Delete_TCB;
                                IntPtr ptr = GetPtrToNewObject(rows[i]);
                                int ret = SetTcpEntry(ptr);
                        }
                }
        }

        //Close all connections at current local IP
        public static void CloseLocalIP(string IP){
                MIB_TCPROW[] rows = getTcpTable();
                for(int i=0; i<rows.Length; i++){
                        if(rows[i].dwLocalAddr==IPStringToInt(IP)){
                                rows[i].dwState = (int) State.Delete_TCB;
                                IntPtr ptr = GetPtrToNewObject(rows[i]);
                                int ret = SetTcpEntry(ptr);
                        }
                }
        }
        //Closes all connections to the remote port
        public static void CloseRemotePort(int port){
                MIB_TCPROW[] rows = getTcpTable();
                for(int i=0; i<rows.Length; i++){
                        if(port==ntohs(rows[i].dwRemotePort)){
                                rows[i].dwState = (int) State.Delete_TCB;
                                IntPtr ptr = GetPtrToNewObject(rows[i]);
                                int ret = SetTcpEntry(ptr);
                        }
                }
        }
        //Closes all connections to the local port
        public static void CloseLocalPort(int port){
                MIB_TCPROW[] rows = getTcpTable();
                for(int i=0; i<rows.Length; i++){
                        if(port==ntohs(rows[i].dwLocalPort)){
                                rows[i].dwState = (int) State.Delete_TCB;
                                IntPtr ptr = GetPtrToNewObject(rows[i]);
                                int ret = SetTcpEntry(ptr);
                        }
                }
        }
        //Close a connection by returning the connectionstring
        public static void CloseConnection(string connectionstring){
                try{
                        //Split the string to its subparts
                        string[] parts = connectionstring.Split('-');
                        if(parts.Length!=4) throw new Exception("Invalid connectionstring - use the one provided by Connections.");
                        string[] loc = parts[0].Split(':');
                        string[] rem = parts[1].Split(':');
                        string[] locaddr = loc[0].Split('.');
                        string[] remaddr = rem[0].Split('.');
                        //Fill structure with data
                        MIB_TCPROW row = new MIB_TCPROW();
                        row.dwState = 12;
                        byte[] bLocAddr = new byte[]{byte.Parse(locaddr[0]),byte.Parse(locaddr[1]),byte.Parse(locaddr[2]),byte.Parse(locaddr[3])};
                        byte[] bRemAddr = new byte[]{byte.Parse(remaddr[0]),byte.Parse(remaddr[1]),byte.Parse(remaddr[2]),byte.Parse(remaddr[3])};
                        row.dwLocalAddr = BitConverter.ToInt32(bLocAddr,0);
                        row.dwRemoteAddr = BitConverter.ToInt32(bRemAddr,0);
                        row.dwLocalPort = htons(int.Parse(loc[1]));
                        row.dwRemotePort = htons(int.Parse(rem[1]));
                        //Make copy of the structure into memory and use the pointer to call SetTcpEntry
                        IntPtr ptr = GetPtrToNewObject(row);
                        int ret = SetTcpEntry(ptr);
                        if(ret==-1) throw new Exception("Unsuccessful");
                        if(ret==65) throw new Exception("User has no sufficient privilege to execute this API successfully");
                        if(ret==87) throw new Exception("Specified port is not in state to be closed down");
                        if(ret!=0) throw new Exception("Unknown error ("+ret+")");
                }catch(Exception ex){
                        throw new Exception("CloseConnection failed ("+connectionstring+")! ["+ex.GetType().ToString()+","+ex.Message+"]");
                }
        }
        //Gets all connections
        public static string[] Connections(){
                return Connections(State.All);
        }
        //Gets a connection list of connections with a defined state
        public static string[] Connections(State state){
                MIB_TCPROW[] rows = getTcpTable();

                ArrayList arr = new ArrayList();

                foreach(MIB_TCPROW row in rows){
                        if(state == State.All || state == (State)row.dwState){
                                string localaddress = IPIntToString(row.dwLocalAddr) +":"+ ntohs(row.dwLocalPort);
                                string remoteaddress = IPIntToString(row.dwRemoteAddr) + ":" + ntohs(row.dwRemotePort);
                                arr.Add(localaddress + "-" + remoteaddress + "-" + ((State)row.dwState).ToString() + "-" + row.dwState);
                        }
                }

                return (string[])arr.ToArray(typeof(System.String));
        }
        //The function that fills the MIB_TCPROW array with connectioninfos
        private static MIB_TCPROW[] getTcpTable(){
                IntPtr buffer = IntPtr.Zero; bool allocated=false;
                try{
                        int iBytes=0;
                        GetTcpTable(IntPtr.Zero, ref iBytes, false); //Getting size of return data
                        buffer=Marshal.AllocCoTaskMem(iBytes); //allocating the datasize

                        allocated=true;
                        GetTcpTable(buffer, ref iBytes, false); //Run it again to fill the memory with the data
                        int structCount=Marshal.ReadInt32(buffer); // Get the number of structures
                        IntPtr buffSubPointer = buffer; //Making a pointer that will point into the buffer
                        buffSubPointer = (IntPtr)((int)buffer + 4); //Move to the first data (ignoring dwNumEntries from the original MIB_TCPTABLE struct)
                        MIB_TCPROW[] tcpRows = new MIB_TCPROW[structCount]; //Declaring the array
                        //Get the struct size
                        MIB_TCPROW tmp = new MIB_TCPROW();
                        int sizeOfTCPROW = Marshal.SizeOf(tmp);
                        //Fill the array 1 by 1
                        for(int i=0; i<structCount; i++){
                                tcpRows[i] = (MIB_TCPROW)Marshal.PtrToStructure(buffSubPointer, typeof(MIB_TCPROW)); //copy struct data
                                buffSubPointer = (IntPtr)((int)buffSubPointer + sizeOfTCPROW ); //move to next structdata
                        }

                        return tcpRows;
                }catch(Exception ex){
                        throw new Exception("getTcpTable failed! ["+ex.GetType().ToString()+","+ex.Message+"]");
                }finally{
                        if(allocated) Marshal.FreeCoTaskMem(buffer); //Free the allocated memory
                }
        }
        private static IntPtr GetPtrToNewObject(object obj){
                IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(obj));
                Marshal.StructureToPtr(obj,ptr,false);
                return ptr;
        }
        //Convert an IP string to the INT value
        private static int IPStringToInt(string IP){
                if(IP.IndexOf(".")<0) throw new Exception("Invalid IP address");
                string[] addr = IP.Split('.');
                if(addr.Length!=4) throw new Exception("Invalid IP address");
                byte[] bytes = new byte[]{byte.Parse(addr[0]),byte.Parse(addr[1]),byte.Parse(addr[2]),byte.Parse(addr[3])};
                return BitConverter.ToInt32(bytes,0);
        }
        //Convert an IP integer to IP string
        private static string IPIntToString(int IP){
                byte[] addr = System.BitConverter.GetBytes(IP);
                return addr[0] +"."+addr[1] +"."+addr[2] +"."+addr[3];
        }
}



回答2:


Is the WebSocket connection running within a browser? If so, could you get hold of the WebSocket object reference using JavaScript and call websocketInstance.close();? This seems a bit easier than doing it at a lower OS level.

You could then use something like the Selenium .NET driver to control the browser instance and execute the JavaScript that closes the WebSocket connection. Other similar libraries are available to do this sort of thing too.



来源:https://stackoverflow.com/questions/7268419/how-can-i-kill-a-websocket-connection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!