|
@@ -0,0 +1,356 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
+using System.Data;
|
|
|
+using System.Drawing;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
+using System.Data;
|
|
|
+using System.Drawing;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Net.Sockets;
|
|
|
+using System.Net; // IP,IPAddress, IPEndPoint,端口等;
|
|
|
+using System.Threading;
|
|
|
+using System.IO;
|
|
|
+
|
|
|
+namespace ConsoleApp1
|
|
|
+{
|
|
|
+ class Program
|
|
|
+ {
|
|
|
+ string ip_val = "";
|
|
|
+ static string tcp_port = "1520";
|
|
|
+
|
|
|
+ static Thread threadWatch = null; // 负责监听客户端连接请求的 线程;
|
|
|
+ static Socket socketWatch = null;
|
|
|
+ private bool Client_connect = false;
|
|
|
+
|
|
|
+ static Dictionary<string, Socket> dict = new Dictionary<string, Socket>();////例如使用socket,创建字典代码<br> Dictionary<string,Socket> dic = new Dictionary<string,Socket>();<br>
|
|
|
+ static Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();
|
|
|
+ static void start_init()
|
|
|
+ {
|
|
|
+ // 创建负责监听的套接字,注意其中的参数;
|
|
|
+ socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
|
+ // 获得文本框中的IP对象;
|
|
|
+ IPAddress address = IPAddress.Parse(GetLocalIPv4Address().ToString());//127.0.0.1
|
|
|
+ Console.WriteLine("服务器IP:"+GetLocalIPv4Address().ToString()+" 端口:"+tcp_port);
|
|
|
+ // 创建包含ip和端口号的网络节点对象;
|
|
|
+ IPEndPoint endPoint = new IPEndPoint(address, int.Parse(tcp_port)); //8098
|
|
|
+ //IPEndPoint endPoint = new IPEndPoint(address, 8098); //8098
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 将负责监听的套接字绑定到唯一的ip和端口上;
|
|
|
+ socketWatch.Bind(endPoint);
|
|
|
+ }
|
|
|
+ catch (SocketException se)
|
|
|
+ {
|
|
|
+ Console.WriteLine("异常:" + se.Message);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 设置监听队列的长度;
|
|
|
+ socketWatch.Listen(20);
|
|
|
+ // 创建负责监听的线程;
|
|
|
+ threadWatch = new Thread(WatchConnecting);
|
|
|
+ threadWatch.IsBackground = true;
|
|
|
+ threadWatch.Start();
|
|
|
+ Console.WriteLine("TCP透传服务器启动成功!");
|
|
|
+ }
|
|
|
+ /// <字节数组转16进制字符串>
|
|
|
+ /// <param name="bytes"></param>
|
|
|
+ /// <returns> String 16进制显示形式</returns>
|
|
|
+ public static string byteToHexStr(byte[] bytes)
|
|
|
+ {
|
|
|
+ string returnStr = "";
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (bytes != null)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < bytes.Length; i++)
|
|
|
+ {
|
|
|
+ returnStr += bytes[i].ToString("X2");
|
|
|
+ returnStr += " ";//两个16进制用空格隔开,方便看数据
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return returnStr;
|
|
|
+ }
|
|
|
+ catch (Exception)
|
|
|
+ {
|
|
|
+ return returnStr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// <字符串转16进制格式,不够自动前面补零>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hexString"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private static byte[] strToToHexByte(String hexString)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ // hexString = hexString.Replace(" ", "");//清除空格
|
|
|
+ if ((hexString.Length % 2) != 0)//奇数个
|
|
|
+ {
|
|
|
+ byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
|
|
|
+ try
|
|
|
+ {
|
|
|
+ for (i = 0; i < (hexString.Length - 1) / 2; i++)
|
|
|
+ {
|
|
|
+ returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
|
|
|
+ }
|
|
|
+ returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return returnBytes;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ byte[] returnBytes = new byte[(hexString.Length) / 2];
|
|
|
+ try
|
|
|
+ {
|
|
|
+ for (i = 0; i < returnBytes.Length; i++)
|
|
|
+ {
|
|
|
+ returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return returnBytes;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// 监听客户端请求的方法;
|
|
|
+/// </summary>
|
|
|
+ static void WatchConnecting()
|
|
|
+ {
|
|
|
+ Socket sokConnection = null;
|
|
|
+ while (true) // 持续不断的监听客户端的连接请求;
|
|
|
+ {
|
|
|
+ // 开始监听客户端连接请求,Accept方法会阻断当前的线程;
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
|
|
|
+ // Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ //提示套接字监听异常
|
|
|
+ Console.WriteLine(ex.Message);
|
|
|
+ ShowMsg("客户端异常" + ex.Message);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 想列表控件中添加客户端的IP信息;
|
|
|
+ // lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
|
|
|
+ // 将与客户端连接的 套接字 对象添加到集合中;
|
|
|
+ dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);//// 字典集合添加元素
|
|
|
+ ShowMsg("客户端连接成功!");
|
|
|
+ Thread thr = new Thread(RecMsg);
|
|
|
+ thr.IsBackground = true;
|
|
|
+ thr.Start(sokConnection);
|
|
|
+ dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr); // 将新建的线程 添加 到线程的集合中去。
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static bool IsSocketConnected(Socket s)
|
|
|
+ {
|
|
|
+ return !((s.Poll(10, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
|
|
|
+ }
|
|
|
+ static void RecMsg(object sokConnectionparn)
|
|
|
+ {
|
|
|
+ Socket sokClient = sokConnectionparn as Socket;
|
|
|
+ while (true)
|
|
|
+ {
|
|
|
+ // 定义一个5M的缓存区;
|
|
|
+ byte[] arrMsgRec = new byte[1024 * 1024 * 5];
|
|
|
+ // 将接受到的数据存入到输入 arrMsgRec中;
|
|
|
+ int length = -1;
|
|
|
+ if (sokClient.Poll(-1, SelectMode.SelectRead))//第一个参数为等待时间 us -1 为一直等待 阻塞在这里等待 当有数据
|
|
|
+ /*SelectRead: 如果已调用 Listen(Int32) 并且有挂起的连接,则为 true。
|
|
|
+ - 或 - 如果有数据可供读取,则为 true。
|
|
|
+ - 或 - 如果连接已关闭 重置或终止则返回 true;
|
|
|
+ - 否则,返回 false。*/
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
|
|
|
+ // 当客户端断开时 会发送一个长度为0 的空数据 此处一定要加判断 等于0 说明断开了 要做出处理 否则线程死循环一直接收0字节数据bug
|
|
|
+ if (length == 0) //长度等于0 客户端断开连接了 会发送个0字节数据上来的
|
|
|
+ {
|
|
|
+
|
|
|
+ dict.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ // 从通信线程集合中删除被中断连接的通信线程对象;
|
|
|
+ dictThread.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ // 从列表中移除被中断的连接IP
|
|
|
+ //lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ Console.WriteLine("客户端:"+ sokClient.RemoteEndPoint.ToString()+"断开连接");
|
|
|
+ break; //客户端断开了 终止当前的通讯线程 不然会一直触发接收 有bug
|
|
|
+ }
|
|
|
+ else //接收正常数据了
|
|
|
+ {
|
|
|
+ string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);// 将接受到的字节数据转化成字符串; 接收文件另外处理 看下面 这里不能接收文件
|
|
|
+ byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 将要发送的字符串转换成Utf-8字节数组;
|
|
|
+ string ShowstrMsg = "客户端:" + sokClient.RemoteEndPoint + " 时间:" + GetCurrentTime() + "\r\n源数据 String:" + strMsg + " hex:"+ byteToHexStr(arrMsg) +"\r\n";
|
|
|
+ ShowMsg(ShowstrMsg);
|
|
|
+ // SendMsgdata(strMsg);//源数据下发 给所有客户端
|
|
|
+ foreach (Socket s in dict.Values) //开始群发信息 遍历字典里面的连接好的socket客户端
|
|
|
+ {
|
|
|
+ if (s != sokClient)//判断是否是当前发送数据上来的客户端 是的话就不发送
|
|
|
+ {
|
|
|
+ s.Send(arrMsg);
|
|
|
+
|
|
|
+ }
|
|
|
+ // s.Send(arrMsg);
|
|
|
+ }
|
|
|
+ //ShowMsg("发送消息为:" + strMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (SocketException se)
|
|
|
+ {
|
|
|
+ ShowMsg("异常了:" + se.Message);
|
|
|
+ // 从 通信套接字 集合中删除被中断连接的通信套接字;
|
|
|
+ dict.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ // 从通信线程集合中删除被中断连接的通信线程对象;
|
|
|
+ dictThread.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ Console.WriteLine("客户端:" + sokClient.RemoteEndPoint.ToString() + "断开连接");
|
|
|
+ // 从列表中移除被中断的连接IP
|
|
|
+ // lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ ShowMsg("异常了:" + e.Message);
|
|
|
+ // 从 通信套接字 集合中删除被中断连接的通信套接字;
|
|
|
+ dict.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ // 从通信线程集合中删除被中断连接的通信线程对象;
|
|
|
+ dictThread.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ Console.WriteLine("客户端:" + sokClient.RemoteEndPoint.ToString() + "断开连接");
|
|
|
+ // sokClient.Close();
|
|
|
+ // 从列表中移除被中断的连接IP
|
|
|
+ // lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void SendMsgdata(string dataStr)
|
|
|
+ {
|
|
|
+ // string strMsg = "服务器" + "\r\n" + " -->" + dataStr + "\r\n";
|
|
|
+ string strMsg = dataStr;
|
|
|
+ byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(dataStr); // 将要发送的字符串转换成Utf-8字节数组;
|
|
|
+ byte[] arrSendMsg = new byte[arrMsg.Length];
|
|
|
+ // byte[] arrSendMsg = new byte[arrMsg.Length + 1];
|
|
|
+ // 用来标识发送是数据而不是文件,如果没有这一段的客户端就接收不到消息了~~~
|
|
|
+ // arrSendMsg[0] = 0; // 表示发送的是消息数据
|
|
|
+ // Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
|
|
|
+
|
|
|
+ foreach (Socket s in dict.Values)
|
|
|
+ {
|
|
|
+ s.Send(arrMsg);
|
|
|
+
|
|
|
+ }
|
|
|
+ ShowMsg("发送消息为:" + strMsg);
|
|
|
+ }
|
|
|
+ static int cnt_info = 0;
|
|
|
+
|
|
|
+ static void ShowMsg(string str)
|
|
|
+ {
|
|
|
+ Console.WriteLine(str);
|
|
|
+ Write_SaveTxtFile(str + "\r\n");
|
|
|
+ if(++cnt_info>5000)
|
|
|
+ {
|
|
|
+ cnt_info = 0;
|
|
|
+ Console.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ // txtMsg.Items.Add(str + "\r\n");
|
|
|
+ }
|
|
|
+ static public void Write_SaveTxtFile(string txtStr) //保存文本文件 到软件运行目录下
|
|
|
+ {
|
|
|
+ string str = Environment.CurrentDirectory;//获取软件的运行目录 取得或设置当前工作目录的完整限定路径
|
|
|
+ File.AppendAllText(@str + "\\" + "Log.txt", txtStr); //在软件运行目录下保存log信息
|
|
|
+ }
|
|
|
+ ///
|
|
|
+ /// 获取当前系统时间的方法
|
|
|
+ /// 当前时间
|
|
|
+ static DateTime GetCurrentTime()
|
|
|
+ {
|
|
|
+ DateTime currentTime = new DateTime();
|
|
|
+ currentTime = DateTime.Now;
|
|
|
+ return currentTime;
|
|
|
+ } /// <summary>
|
|
|
+ /// 获取本地IPv4地址
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ static public IPAddress GetLocalIPv4Address()
|
|
|
+ {
|
|
|
+ IPAddress localIpv4 = null;
|
|
|
+ //获取本机所有的IP地址列表
|
|
|
+ IPAddress[] IpList = Dns.GetHostAddresses(Dns.GetHostName());
|
|
|
+ //循环遍历所有IP地址
|
|
|
+ foreach (IPAddress IP in IpList)
|
|
|
+ {
|
|
|
+ //判断是否是IPv4地址
|
|
|
+ if (IP.AddressFamily == AddressFamily.InterNetwork)
|
|
|
+ {
|
|
|
+ localIpv4 = IP;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return localIpv4;
|
|
|
+ }
|
|
|
+
|
|
|
+ static string acceptmultiLine()
|
|
|
+ {
|
|
|
+ ConsoleKeyInfo cki;
|
|
|
+ // Console.TreatControlCAsInput = true;//防止Ctrl+C复制
|
|
|
+ Console.WriteLine("Press the F10 key to quit app \n");
|
|
|
+ string result = string.Empty;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ cki = Console.ReadKey();
|
|
|
+ result += cki.KeyChar;
|
|
|
+ if (cki.Key == ConsoleKey.Enter)
|
|
|
+ {
|
|
|
+ if(result!="")
|
|
|
+ {
|
|
|
+ result += System.Environment.NewLine;//如果输入回车,则加入换行标志
|
|
|
+ SendMsgdata(result);
|
|
|
+ }
|
|
|
+ result = string.Empty;
|
|
|
+ }
|
|
|
+ } while (cki.Key != ConsoleKey.F10);//按F10退出
|
|
|
+ Environment.Exit(0);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void Main(string[] args)
|
|
|
+ {
|
|
|
+ // Console.WriteLine("hello");
|
|
|
+ start_init();
|
|
|
+ string s = acceptmultiLine();
|
|
|
+ Console.WriteLine(s);
|
|
|
+ while (true) ;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|