有些同窗电脑总是要出问题,但又不是什么大问题,一般几句cmd就能搞定。以前解决方案有2:一是远程演示,我口述别人操做;一是我写个cmd脚本,但毕竟不在本机很差调试。(吐槽一下经常使用的远程控制实在是难用至极)windows
解决:远程cmd,可以实时的反馈执行结果,带宽占用少缓存
windows10, Microsoft Visual C# 2010 Express, 资料都是百度的!服务器
一、终端应该作成能在全部能联网的设备上跑,而不是内网版网络
二、假设终端只在内网上运行,那么一个终端须要知道另外一个终端的ip和端口(可经过广播,但麻烦了)tcp
三、作成广域网版使用什么技术(主要指消息是经过转发仍是打洞),最后选择转发,由于打洞我还不是很会 -_-''ide
四、终端应该区分控制端和被控制端?不用,软件内部功能区分就好了;若是终端分开那么服务器端还要作识别,就设计麻烦了测试
五、先就这么多吧...优化
一、服务器开启后可接受2个客户端链接,不区分【控制端】或【被控制端】,只作消息转发(提升效率);只有当两端都连上后才能传输消息,当只有一端存在时该端发送消息会收到服务器提示 "另外一端不在线"spa
二、客户端进入时选择是【控制端】仍是【被控制端】,连上后提示另外一端是否链接上服务器线程
三、【控制端】向【被控制端】发送控制命令,【控制端】将收到的消息(期待收到的回显)显示
四、【被控制端】等待命令,收到后执行并将回显显示于该端,最后将回显发送回【控制端】
1 const int PORT = 58888; //Server PORT 2 const string HOST = "127.0.0.1"; //Server IP 3 static TcpClient tcp = new TcpClient(); 4 static bool isAlive = false; //链接标识 5 static bool s=false; //控制端标识,须要传入参数[u999]进入 6 7 //包中第一字节为0x04解析为聊天消息,不然为控制消息;别问为何用0x04,问就是缘分 8 9 static void Main(string[] args) 10 { 11 //控制端判断 12 if(args.Length!=0) 13 if(string.Compare(args[0],"u999")==0) //控制端 14 { 15 Console.Write("Welcome, controller."); 16 s=true; 17 } 18 else 19 Console.WriteLine("Hello loser."); //想爆破密码的? 20 try{ 21 tcp.Connect(HOST, PORT); //链接阻塞 22 isAlive = true; 23 Console.WriteLine("-------已链接=" + tcp.Client.RemoteEndPoint + "------"); 24 }catch(Exception e){ 25 Console.WriteLine(e.Message+"\n任意键退出..."); 26 Console.ReadKey(); 27 return; 28 } 29 30 if(!s) //被控制端 31 { 32 //发送线程 33 ThreadStart ts=new ThreadStart(sendToCtrl); 34 Thread th=new Thread(ts); 35 th.Start(); 36 37 Process p = new Process(); 38 p.StartInfo.FileName = "cmd.exe"; //程序名 39 p.StartInfo.UseShellExecute = false; //不使用程序外壳 40 p.StartInfo.RedirectStandardInput = true; //重定向输入 41 p.StartInfo.RedirectStandardOutput = true; //重定向输出 42 p.StartInfo.RedirectStandardError = true; //错误 43 p.StartInfo.CreateNoWindow = true; //建立窗口 44 p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived); //订阅输出 45 p.ErrorDataReceived += new DataReceivedEventHandler(p_OutputDataReceived); //错误输出 46 p.Start(); 47 p.BeginOutputReadLine(); //程序开始后开始订阅 48 p.BeginErrorReadLine(); 49 50 byte[] recvBuf = new byte[1024]; 51 string command = ""; 52 int recvNum; 53 while(!p.HasExited) //循环执行 54 { 55 recvNum = 0; 56 try{ 57 recvNum = tcp.Client.Receive(recvBuf); //服务等待阻塞 58 }catch(Exception){ //断开链接 59 break; 60 } 61 if(recvNum == 0) //主动断开:空消息 62 break; 63 if(recvBuf[0]!=0x04) //控制消息 64 { 65 command = Encoding.UTF8.GetString(recvBuf, 0, recvNum); //接收远程命令 66 p.StandardInput.WriteLine(command); //执行 67 } 68 else 69 Console.WriteLine(Encoding.UTF8.GetString(recvBuf,1,recvNum-1)); 70 Thread.Sleep(100); //检测exit命令,while循环条件检查 71 } 72 Console.WriteLine("-------End.------\n任意键退出..."); 73 //先关程序,再关链接 74 p.Close(); 75 p = null; 76 tcp.Client.Close(); 77 tcp.Close(); 78 tcp=null; 79 } 80 else //控制端 81 { 82 //接收线程 83 ThreadStart ts = new ThreadStart(recvMsg); 84 Thread th = new Thread(ts); 85 th.Start(); 86 87 string input = ""; 88 while(true) //循环发送 89 { 90 //这里也输入的是什么消息,反正都当控制消息吧(区分要解析输入) 91 input = Console.ReadLine(); 92 if(isAlive) 93 tcp.Client.Send(Encoding.UTF8.GetBytes(input+'\n')); 94 else 95 break; 96 Thread.Sleep(100); 97 } 98 } 99 Console.ReadKey(); //这一句没什么卵用但我不想删 100 } 101 102 //控制端回显消息 103 static void recvMsg() 104 { 105 byte[] recvBuf = new byte[8192]; 106 int recvNum; 107 while(true) //循环接收 108 { 109 recvNum = 0; 110 try{ 111 recvNum = tcp.Client.Receive(recvBuf); 112 }catch(Exception){ 113 break; 114 } 115 if(recvNum == 0) 116 break; 117 //以上为TCP断开判断 118 119 //如下为何要分开写呢?由于合起来麻烦了... 120 if(recvBuf[0]!=0x04) //被控端回显 121 Console.Write(Encoding.UTF8.GetString(recvBuf,0, recvNum)); 122 else //聊天消息 123 Console.WriteLine(Encoding.UTF8.GetString(recvBuf,1, recvNum-1)); 124 } 125 tcp.Client.Close(); 126 tcp.Close(); 127 isAlive = false; 128 Console.WriteLine("-------Server down------"); 129 } 130 131 //被控端消息发送 132 static string output = ""; 133 static void sendToCtrl() 134 { 135 int outputFlag = 0; //被控端超时发送标记 136 string outputNow = ""; 137 byte[] sendBytesT = null, sendBytes=null; 138 while(true) //循环检测缓冲池 139 { 140 Thread.Sleep(50); 141 if(!isAlive || output.Length == 0) //未链接 或 无缓存数据 142 continue; 143 if(output.Length > 4096 || outputFlag > 2) //缓存满4k 或 超时传送150ms 144 { 145 outputNow = output; 146 output = ""; 147 148 //这段可能有点low, 望大佬告知该怎么写 149 sendBytesT = Encoding.UTF8.GetBytes(outputNow); 150 sendBytes = new byte[sendBytesT.Length + 1]; 151 sendBytes[0] = 0x04; 152 sendBytesT.CopyTo(sendBytes, 1); 153 154 try{ 155 tcp.Client.Send(sendBytes); 156 }catch(Exception){ 157 break; 158 } 159 outputFlag = 0; 160 continue; 161 } 162 ++outputFlag; 163 } 164 } 165 166 //被控端输出入池 167 static void p_OutputDataReceived(object sender, DataReceivedEventArgs e) 168 { 169 if(!string.IsNullOrEmpty(e.Data)) 170 { 171 Console.WriteLine(e.Data); 172 output += e.Data + '\n'; 173 }
1 //服务器端不区分控制端被控制端,只做数据转发 2 const int PORT = 58888; //Server PORT 3 static TcpClient[] tcp=new TcpClient[2]; 4 static int alive=0; //二进制位标识该终端是否在线=00|01|10|11 5 static void Main() 6 { 7 //消息线程 8 ParameterizedThreadStart ts=new ParameterizedThreadStart(user); 9 10 TcpListener listen=new TcpListener(IPAddress.Any,PORT); 11 TcpClient tcpT=null; 12 while(true) //循环监听 13 { 14 if(alive==3) //两个终端==11 15 { 16 Thread.Sleep(4000); 17 continue; 18 } 19 listen.Start(1); 20 Console.WriteLine("Listen="+PORT); 21 tcpT=listen.AcceptTcpClient(); //监听阻塞 22 Console.WriteLine("Accept="+tcpT.Client.RemoteEndPoint); 23 if(alive<2) //==00|01 24 { 25 tcp[0]=tcpT; 26 alive|=2; 27 Thread th=new Thread(ts); 28 th.Start(0); 29 } 30 else //==10,不可能==11(当==11时两个线程都在消息循环中) 31 { 32 tcp[1]=tcpT; 33 alive|=1; 34 Thread th=new Thread(ts); 35 th.Start(1); 36 } 37 listen.Stop(); 38 } 39 Console.ReadKey(); 40 } 41 42 //处理一个终端,传入本段代码控制的tcp序号==0|1 43 static void user(object index0) 44 { 45 int index=(int)index0; 46 if(index!=0 && index!=1) //非法验证 47 return; 48 byte[] sendBytesT=Encoding.UTF8.GetBytes(alive==3?"Another is connected.\n":"Only you, wait.\n"); 49 byte[] sendBytes=new byte[sendBytesT.Length+1]; 50 sendBytes[0]=0x04; 51 sendBytesT.CopyTo(sendBytes,1); 52 tcp[index].Client.Send(sendBytes); 53 54 byte[] recvBuf = new byte[8192]; 55 int recvNum; 56 while(true) //接收[转发]消息 57 { 58 recvNum=0; 59 try{ 60 recvNum = tcp[index].Client.Receive(recvBuf); 61 }catch(Exception){ 62 break; 63 } 64 if(recvNum == 0) 65 break; 66 //以上为TCP断开判断 被控制端断开 67 68 //Console.WriteLine(recvNum+","+Encoding.UTF8.GetString(recvBuf,0,recvNum)); 69 if(alive==3) //两端在线 70 { 71 byte[] sendBuf=new byte[recvNum]; 72 Array.Copy(recvBuf,sendBuf,recvNum); 73 tcp[index==0?1:0].Client.Send(sendBuf); 74 } 75 else //一端不在线 76 { 77 sendBytesT=Encoding.UTF8.GetBytes("Another is disconnected.Ctrl+C to EXIT.\n"); 78 sendBytes=new byte[sendBytesT.Length+1]; 79 sendBytes[0]=0x04; 80 sendBytesT.CopyTo(sendBytes,1); 81 tcp[index].Client.Send(sendBytes); 82 } 83 } 84 tcp[index].Client.Close(); 85 tcp[index].Close(); 86 tcp[index]=null; 87 alive&=index==0?1:2; 88 }
一、服务器只容许两个终端链接应该能知足通常使用场景,至少能解决开始叙述的问题
二、客户端开始那个密码区分控制端的东西,其实没多大用,编译出来的exe我用16进制打开都能找到 "密码",但愿会密码学的大神不要喷,我确实不大会
三、【被控制端】那段调用cmd的代码网上很多,略有借鉴...
四、【被控制端】消息回显为何不直接发送回【控制端呢】?由于【被控制端】每输出一行就会产生一个输出重定向,若是每个重定向都直接使用网络传送,那么将致使网络负荷过大(我猜的),因此根据网络原理我优化了发送界定为:150ms的超时传送 或 4k的超限传送
五、服务器端能够作成多终端链接,但消息转发/群发会麻烦,可改进用于一个终端控制多个终端,考虑使用特征编号之类的识别控制群
六、消息前加不可打印字符最开始是因为:测试开启两个【被控制端】时,会形成消息循环发送,当区分控制消息和显示消息后,显示消息就不会执行并循环控制
七、以后测试开启两个【控制端】,【控制端】之间能够互相发送消息,而且都不会当成控制消息(由于该流程里没有执行这个步骤),因此只能分类处理一下显示出来;估计...大概至关于个能聊天的东西了吧
八、最后我以为数据转发应该有更牛逼的办法,好比服务器直接把网络流量重定向之类的;说实话我以为我写的服务器这种接收再转发——实在是low爆了,真的但愿大神能帮我改进下