Program.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.ComponentModel;
  9. using System.Data;
  10. using System.Drawing;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.ComponentModel;
  17. using System.Data;
  18. using System.Drawing;
  19. using System.Linq;
  20. using System.Text;
  21. using System.Net.Sockets;
  22. using System.Net; // IP,IPAddress, IPEndPoint,端口等;
  23. using System.Threading;
  24. using System.IO;
  25. namespace ConsoleApp1
  26. {
  27. class Program
  28. {
  29. string ip_val = "";
  30. static string tcp_port = "1520";
  31. static Thread threadWatch = null; // 负责监听客户端连接请求的 线程;
  32. static Socket socketWatch = null;
  33. private bool Client_connect = false;
  34. static Dictionary<string, Socket> dict = new Dictionary<string, Socket>();////例如使用socket,创建字典代码<br>  Dictionary<string,Socket> dic = new Dictionary<string,Socket>();<br>
  35. static Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();
  36. static void start_init()
  37. {
  38. // 创建负责监听的套接字,注意其中的参数;
  39. socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  40. // 获得文本框中的IP对象;
  41. IPAddress address = IPAddress.Parse(GetLocalIPv4Address().ToString());//127.0.0.1
  42. Console.WriteLine("服务器IP:"+GetLocalIPv4Address().ToString()+" 端口:"+tcp_port);
  43. // 创建包含ip和端口号的网络节点对象;
  44. IPEndPoint endPoint = new IPEndPoint(address, int.Parse(tcp_port)); //8098
  45. //IPEndPoint endPoint = new IPEndPoint(address, 8098); //8098
  46. try
  47. {
  48. // 将负责监听的套接字绑定到唯一的ip和端口上;
  49. socketWatch.Bind(endPoint);
  50. }
  51. catch (SocketException se)
  52. {
  53. Console.WriteLine("异常:" + se.Message);
  54. return;
  55. }
  56. // 设置监听队列的长度;
  57. socketWatch.Listen(20);
  58. // 创建负责监听的线程;
  59. threadWatch = new Thread(WatchConnecting);
  60. threadWatch.IsBackground = true;
  61. threadWatch.Start();
  62. Console.WriteLine("TCP透传服务器启动成功!");
  63. }
  64. /// <字节数组转16进制字符串>
  65. /// <param name="bytes"></param>
  66. /// <returns> String 16进制显示形式</returns>
  67. public static string byteToHexStr(byte[] bytes)
  68. {
  69. string returnStr = "";
  70. try
  71. {
  72. if (bytes != null)
  73. {
  74. for (int i = 0; i < bytes.Length; i++)
  75. {
  76. returnStr += bytes[i].ToString("X2");
  77. returnStr += " ";//两个16进制用空格隔开,方便看数据
  78. }
  79. }
  80. return returnStr;
  81. }
  82. catch (Exception)
  83. {
  84. return returnStr;
  85. }
  86. }
  87. /// <字符串转16进制格式,不够自动前面补零>
  88. ///
  89. /// </summary>
  90. /// <param name="hexString"></param>
  91. /// <returns></returns>
  92. private static byte[] strToToHexByte(String hexString)
  93. {
  94. int i;
  95. // hexString = hexString.Replace(" ", "");//清除空格
  96. if ((hexString.Length % 2) != 0)//奇数个
  97. {
  98. byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
  99. try
  100. {
  101. for (i = 0; i < (hexString.Length - 1) / 2; i++)
  102. {
  103. returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
  104. }
  105. returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
  106. }
  107. catch
  108. {
  109. return null;
  110. }
  111. return returnBytes;
  112. }
  113. else
  114. {
  115. byte[] returnBytes = new byte[(hexString.Length) / 2];
  116. try
  117. {
  118. for (i = 0; i < returnBytes.Length; i++)
  119. {
  120. returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
  121. }
  122. }
  123. catch
  124. {
  125. return null;
  126. }
  127. return returnBytes;
  128. }
  129. }
  130. /// <summary>
  131. /// 监听客户端请求的方法;
  132. /// </summary>
  133. static void WatchConnecting()
  134. {
  135. Socket sokConnection = null;
  136. while (true) // 持续不断的监听客户端的连接请求;
  137. {
  138. // 开始监听客户端连接请求,Accept方法会阻断当前的线程;
  139. try
  140. {
  141. sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
  142. // Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
  143. }
  144. catch (Exception ex)
  145. {
  146. //提示套接字监听异常
  147. Console.WriteLine(ex.Message);
  148. ShowMsg("客户端异常" + ex.Message);
  149. break;
  150. }
  151. // 想列表控件中添加客户端的IP信息;
  152. // lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
  153. // 将与客户端连接的 套接字 对象添加到集合中;
  154. dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);//// 字典集合添加元素
  155. ShowMsg("客户端连接成功!");
  156. Thread thr = new Thread(RecMsg);
  157. thr.IsBackground = true;
  158. thr.Start(sokConnection);
  159. dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr); // 将新建的线程 添加 到线程的集合中去。
  160. }
  161. }
  162. static bool IsSocketConnected(Socket s)
  163. {
  164. return !((s.Poll(10, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
  165. }
  166. static void RecMsg(object sokConnectionparn)
  167. {
  168. Socket sokClient = sokConnectionparn as Socket;
  169. while (true)
  170. {
  171. // 定义一个5M的缓存区;
  172. byte[] arrMsgRec = new byte[1024 * 1024 * 5];
  173. // 将接受到的数据存入到输入 arrMsgRec中;
  174. int length = -1;
  175. if (sokClient.Poll(-1, SelectMode.SelectRead))//第一个参数为等待时间 us -1 为一直等待 阻塞在这里等待 当有数据
  176. /*SelectRead: 如果已调用 Listen(Int32) 并且有挂起的连接,则为 true。
  177. - 或 - 如果有数据可供读取,则为 true。
  178. - 或 - 如果连接已关闭 重置或终止则返回 true;
  179. - 否则,返回 false。*/
  180. {
  181. try
  182. {
  183. length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
  184. // 当客户端断开时 会发送一个长度为0 的空数据 此处一定要加判断 等于0 说明断开了 要做出处理 否则线程死循环一直接收0字节数据bug
  185. if (length == 0) //长度等于0 客户端断开连接了 会发送个0字节数据上来的
  186. {
  187. dict.Remove(sokClient.RemoteEndPoint.ToString());
  188. // 从通信线程集合中删除被中断连接的通信线程对象;
  189. dictThread.Remove(sokClient.RemoteEndPoint.ToString());
  190. // 从列表中移除被中断的连接IP
  191. //lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
  192. Console.WriteLine("客户端:"+ sokClient.RemoteEndPoint.ToString()+"断开连接");
  193. break; //客户端断开了 终止当前的通讯线程 不然会一直触发接收 有bug
  194. }
  195. else //接收正常数据了
  196. {
  197. string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);// 将接受到的字节数据转化成字符串; 接收文件另外处理 看下面 这里不能接收文件
  198. byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;
  199. string ShowstrMsg = "客户端:" + sokClient.RemoteEndPoint + " 时间:" + GetCurrentTime() + "\r\n源数据 String:" + strMsg + " hex:"+ byteToHexStr(arrMsg) +"\r\n";
  200. ShowMsg(ShowstrMsg);
  201. // SendMsgdata(strMsg);//源数据下发 给所有客户端
  202. foreach (Socket s in dict.Values) //开始群发信息 遍历字典里面的连接好的socket客户端
  203. {
  204. if (s != sokClient)//判断是否是当前发送数据上来的客户端 是的话就不发送
  205. {
  206. s.Send(arrMsg);
  207. }
  208. // s.Send(arrMsg);
  209. }
  210. //ShowMsg("发送消息为:" + strMsg);
  211. }
  212. }
  213. catch (SocketException se)
  214. {
  215. ShowMsg("异常了:" + se.Message);
  216. // 从 通信套接字 集合中删除被中断连接的通信套接字;
  217. dict.Remove(sokClient.RemoteEndPoint.ToString());
  218. // 从通信线程集合中删除被中断连接的通信线程对象;
  219. dictThread.Remove(sokClient.RemoteEndPoint.ToString());
  220. Console.WriteLine("客户端:" + sokClient.RemoteEndPoint.ToString() + "断开连接");
  221. // 从列表中移除被中断的连接IP
  222. // lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
  223. break;
  224. }
  225. catch (Exception e)
  226. {
  227. ShowMsg("异常了:" + e.Message);
  228. // 从 通信套接字 集合中删除被中断连接的通信套接字;
  229. dict.Remove(sokClient.RemoteEndPoint.ToString());
  230. // 从通信线程集合中删除被中断连接的通信线程对象;
  231. dictThread.Remove(sokClient.RemoteEndPoint.ToString());
  232. Console.WriteLine("客户端:" + sokClient.RemoteEndPoint.ToString() + "断开连接");
  233. // sokClient.Close();
  234. // 从列表中移除被中断的连接IP
  235. // lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
  236. break;
  237. }
  238. }
  239. }
  240. }
  241. static void SendMsgdata(string dataStr)
  242. {
  243. // string strMsg = "服务器" + "\r\n" + " -->" + dataStr + "\r\n";
  244. string strMsg = dataStr;
  245. byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(dataStr); // 将要发送的字符串转换成Utf-8字节数组;
  246. byte[] arrSendMsg = new byte[arrMsg.Length];
  247. // byte[] arrSendMsg = new byte[arrMsg.Length + 1];
  248. // 用来标识发送是数据而不是文件,如果没有这一段的客户端就接收不到消息了~~~
  249. // arrSendMsg[0] = 0; // 表示发送的是消息数据
  250. //  Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
  251. foreach (Socket s in dict.Values)
  252. {
  253. s.Send(arrMsg);
  254. }
  255. ShowMsg("发送消息为:" + strMsg);
  256. }
  257. static int cnt_info = 0;
  258. static void ShowMsg(string str)
  259. {
  260. Console.WriteLine(str);
  261. Write_SaveTxtFile(str + "\r\n");
  262. if(++cnt_info>5000)
  263. {
  264. cnt_info = 0;
  265. Console.Clear();
  266. }
  267. // txtMsg.Items.Add(str + "\r\n");
  268. }
  269. static public void Write_SaveTxtFile(string txtStr) //保存文本文件 到软件运行目录下
  270. {
  271. string str = Environment.CurrentDirectory;//获取软件的运行目录 取得或设置当前工作目录的完整限定路径
  272. File.AppendAllText(@str + "\\" + "Log.txt", txtStr); //在软件运行目录下保存log信息
  273. }
  274. ///
  275. /// 获取当前系统时间的方法
  276. /// 当前时间
  277. static DateTime GetCurrentTime()
  278. {
  279. DateTime currentTime = new DateTime();
  280. currentTime = DateTime.Now;
  281. return currentTime;
  282. } /// <summary>
  283. /// 获取本地IPv4地址
  284. /// </summary>
  285. /// <returns></returns>
  286. static public IPAddress GetLocalIPv4Address()
  287. {
  288. IPAddress localIpv4 = null;
  289. //获取本机所有的IP地址列表
  290. IPAddress[] IpList = Dns.GetHostAddresses(Dns.GetHostName());
  291. //循环遍历所有IP地址
  292. foreach (IPAddress IP in IpList)
  293. {
  294. //判断是否是IPv4地址
  295. if (IP.AddressFamily == AddressFamily.InterNetwork)
  296. {
  297. localIpv4 = IP;
  298. }
  299. else
  300. {
  301. continue;
  302. }
  303. }
  304. return localIpv4;
  305. }
  306. static string acceptmultiLine()
  307. {
  308. ConsoleKeyInfo cki;
  309. // Console.TreatControlCAsInput = true;//防止Ctrl+C复制
  310. Console.WriteLine("Press the F10 key to quit app \n");
  311. string result = string.Empty;
  312. do
  313. {
  314. cki = Console.ReadKey();
  315. result += cki.KeyChar;
  316. if (cki.Key == ConsoleKey.Enter)
  317. {
  318. if(result!="")
  319. {
  320. result += System.Environment.NewLine;//如果输入回车,则加入换行标志
  321. SendMsgdata(result);
  322. }
  323. result = string.Empty;
  324. }
  325. } while (cki.Key != ConsoleKey.F10);//按F10退出
  326. Environment.Exit(0);
  327. return result;
  328. }
  329. static void Main(string[] args)
  330. {
  331. // Console.WriteLine("hello");
  332. start_init();
  333. string s = acceptmultiLine();
  334. Console.WriteLine(s);
  335. while (true) ;
  336. }
  337. }
  338. }