后端开发 网络 基于C#的TcpSmtpSqlServer的不可名状之物 L X Y 2024-11-04 2025-12-11
通过Tcp进行远程连接,SQL server进行数据存储,QQ邮箱发送注册验证码 引言 本文项目可以,在远程主机上通过客户端与服务端的Tcp连接进行通信,然后利用邮箱发送验证码在服务端完成验证并且注册,当验证在服务端通过后, ,服务端将会把用户信息保存在SQL server的数据库中。注意使用QQ在服务端发送消息,需要先在QQ邮箱开启SMTP服务,然后保存授权码。
步骤一:在VisualStudio中创建一个“控制台应用(.net framework)”的新项目FWDBx02。 项目命名为:FWDBx02 。包含四个部分:Program.cs(主体);MailSendControls.cs(邮件控制);SQLcontrols.cs(数据库控制); ProtocolControls.cs(验证处理控制)。
Program.cs代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; namespace FWDBx02 { internal class Program { private static List<string> DataList = new List<string>(); private static string asd; private static string userReturn; public static string asduserID; private static string userID; public static string asduserkeyword; private static string userkeyword; private static string CAPTCHAstr; public static string asdsendMAIL; private static string sendMAIL; public static byte[] receiveBuffer = new byte[1024]; public static string receiveSTR; public static IPAddress ipAddress; public static int portINT; public static IPEndPoint iPEndPoint; public static Socket socket; static void Main(string[] args) { Console.WriteLine("这里是服务端:"); try { Console.WriteLine("输入服务器IP:"); ipAddress = IPAddress.Parse(Console.ReadLine()); Console.WriteLine("输入开放端口:"); portINT = int.Parse(Console.ReadLine()); iPEndPoint = new IPEndPoint(ipAddress, portINT); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(iPEndPoint); socket.Listen(10); socket.BeginAccept(AcceptCallback,socket); } catch (SocketException se) { Console.WriteLine("MAINse:"+se.Message); } catch (Exception ex) { Console.WriteLine("MAINex:"+ex.Message); } Console.ReadKey(); } private static void AcceptCallback(IAsyncResult ar) { try { Socket socket = (Socket)ar.AsyncState; Socket clientSocket = socket.EndAccept(ar); clientSocket.BeginReceive(receiveBuffer,0,1024,0,ReceiveCallback,clientSocket); socket.BeginAccept(AcceptCallback, socket); } catch (SocketException se) { Console.WriteLine("ACBse:"+se.Message);} catch (Exception ex) { Console.WriteLine("ACBex:"+ex.Message); } } private static void ReceiveCallback(IAsyncResult ar) { //try //{ Socket clientSocket = (Socket)ar.AsyncState; int con = clientSocket.EndReceive(ar); receiveSTR = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, con); Console.WriteLine(receiveSTR);//* ProcessingUSER(receiveSTR); /// clientSocket.BeginReceive(receiveBuffer, 0, 1024, 0, ReceiveCallback, clientSocket); //} //catch (SocketException se) { Console.WriteLine("RCBse:"+se.Message);} //catch (Exception ex) { Console.WriteLine("RCBex:"+ex.Message);} } private static void ProcessingUSER(string receiveSTR) { ProtocolControls protocolControls = new ProtocolControls(receiveSTR); CAPTCHAstr = protocolControls.captchaSTR;//用户发送信息第一波产生的验证码 asd = CAPTCHAstr; sendMAIL = protocolControls.SENDMAIL; asdsendMAIL = sendMAIL; userID = protocolControls.USRID; asduserID = userID; userkeyword = protocolControls.USRKEYWORD; asduserkeyword = userkeyword; DataList.Add(asduserID); DataList.Add(asduserkeyword); DataList.Add(asdsendMAIL); //DataList.Add(CAPTCHAstr); Console.WriteLine($"{asduserID} {asduserkeyword} {asdsendMAIL}"); //222222/1234565/[email protected] if (CAPTCHAstr != null) { userReturn = protocolControls.USRRETURN; MailSendControls mailSendControls = new MailSendControls(sendMAIL, CAPTCHAstr); }else if(userReturn == asd ) { Console.WriteLine($"{DataList[0]} {DataList[1]} {DataList[2]}"); SQLcontrols sQLcontrols = new SQLcontrols(DataList[0], DataList[1], DataList[2]); } } } }
MailSendControls.cs代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 using System.Net; using System.Net.Mail; namespace FWDBx02 { internal class MailSendControls//注册邮件发送 { private static string mailLocalAdd = "你的邮箱"; private static string keyword = "SMTP授权码"; private static string SendToMailAdd ; private static string CAPTCHAstr; public MailSendControls(string sendToMailAdd,string captchaSTR) { SendToMailAdd = sendToMailAdd; CAPTCHAstr = captchaSTR; MailSend(SendToMailAdd, CAPTCHAstr); } private void MailSend(string SendToMailAdd, string captchaSTR) { MailMessage mailMessage = new MailMessage(); mailMessage.From = new MailAddress(mailLocalAdd, "通信ID注册", System.Text.Encoding.UTF8); mailMessage.To.Add(new MailAddress(SendToMailAdd)); mailMessage.Bcc.Add(new MailAddress(SendToMailAdd)); mailMessage.Subject = "这是邮件的主题"; mailMessage.SubjectEncoding = System.Text.Encoding.UTF8; mailMessage.IsBodyHtml = false; mailMessage.Body = $"注册验证码:{captchaSTR}"; mailMessage.BodyEncoding = System.Text.Encoding.UTF8; SmtpClient smtpClient = new SmtpClient("smtp.qq.com", 587); smtpClient.EnableSsl = true; smtpClient.Credentials = new NetworkCredential(mailLocalAdd, keyword); smtpClient.Send(mailMessage); } } }
SQLcontrols.cs代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using System.Data.SqlClient; namespace FWDBx02 { internal class SQLcontrols//注册信息存入数据库 { //连接字符串 private static string serverToDateBase = "Server = localhost;DataBase = TestA02x01;Trusted_Connection = true;"; //sql语句 private static string sqlSTR; private static string userid; private static string userkeyword; private static string usermail; public SQLcontrols(string Userid,string Userkeyword,string Usermail) { sqlSTR = $"insert into userREGTable_1(userid,userkeyword,usermail) values('{Userid}','{Userkeyword}','{Usermail}')"; InsertSQLDB(sqlSTR); } private static void InsertSQLDB (string SqlSTR) { SqlConnection sqlConnection = new SqlConnection (); sqlConnection.ConnectionString = serverToDateBase;//先连接,再打开 sqlConnection.Open (); SqlCommand cmd = sqlConnection.CreateCommand (); cmd.CommandText = sqlSTR; cmd.Connection = sqlConnection; int resultSQL = cmd.ExecuteNonQuery (); sqlConnection.Close (); } } }
ProtocolControls.cs代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 using System; namespace FWDBx02 { internal class ProtocolControls //协议处理,将账号的注册并入协议处理 { class ProtocolTexts { public ProtocolTexts() { } public string reg = "REG"; public string communication = "COMM"; } public string captchaSTR; public string SENDMAIL; public string USRID; public string USRKEYWORD; public string USRRETURN; private static string receiveSTR; char splitSTR = '/'; //通过“/”分割信息 private static string[] parts; private static int partsLength; public ProtocolControls(string ReceiveSTR) { receiveSTR = ReceiveSTR; ///// //扫描接收信息字节是否有恶意(没写) ///// ProtocolProcessing(receiveSTR); } private void ProtocolProcessing( string receiveSTR) { ProtocolTexts protocolTexts = new ProtocolTexts(); parts = receiveSTR.Split(splitSTR); partsLength = parts.Length; if (parts[0] == protocolTexts.reg) { switch (parts[0]) { case "REG": goto ZCZH; ; ; case "COMM": goto ZHTX; ; ; } } ZCZH: if (parts[1].Length == 4) { //SENDMAIL = parts[3]; USRRETURN = parts[1]; captchaSTR = null;////???????????????????????????? goto PT; } else { //USRRETURN = null; USRID = parts[1]; USRKEYWORD = parts[2]; SENDMAIL = parts[3]; Random random = new Random(); int[] num = new int[4]; string[] captcha = new string[4]; for (int i = 0; i<4;i++) { num[i] = random.Next(0,10); //随机生成数字 captcha[i] = num[i].ToString(); } captchaSTR = captcha[0]+captcha[1]+captcha[2]+captcha[3];//这是验证码 goto PT; ; } ZHTX: goto PT; ; PT:// ZCZH 或者 ZHTX 执行完成 后统一 跳转 到 "PT标签" return ; } } }
步骤二:创建一个“控制台应用(.net framework)”的新项目CHDAx02 项目命名为CHDAx02。该项目只有一个Program.cs文件,唯一需要注意的是socket的使用,它的Beginsend方法及其回调SendCallback与发送方法send。
由于这个代码是以前写的,不是用来做这个的,只是稍稍改了一下,所以有多余部分没有修改删除,不过重点注意上一句话的内容就行了。
Program.cs代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 using System; using System.Net.Sockets; using System.Net; namespace CHDAx02 { internal class Program //客户端 { //REGISTRATION:REG(注册请求) //COMMUNICATION:COMM(通信请求) public enum Protocol { REG = 1110, COMM = 1111, } static IPAddress iPAddress; public static int portINT ; static IPEndPoint iPEndPoint ; public static string receiveSTR; public static byte[] sendBuffer; public static byte[] receiveBuffer; static Socket socket ; static void Main(string[] args) { Console.WriteLine("这里是客户端"); try { Console.WriteLine("注意输入用户信息时,格式为 用户id/用户密码/用户邮箱 然后回车,只回车一下,然后等待邮箱接受验证码"); Console.WriteLine("当邮箱接收到验证码后,就可以直接在客户端输入验证码然后回车,若验证码正确,注册完成"); Console.WriteLine("输入服务端IP地址:"); iPAddress = IPAddress.Parse(Console.ReadLine()); Console.WriteLine("输入服务端端口:"); portINT = int.Parse(Console.ReadLine()); Console.WriteLine("输入用户信息:"); iPEndPoint = new IPEndPoint(iPAddress, portINT); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.BeginConnect(iPEndPoint, ConnectCallback, socket); while (true) { string asd = Console.ReadLine(); Send(Protocol.REG, asd); } //*发送信息方法 } catch (SocketException se) { Console.WriteLine("MainSE:"+se.Message); } catch (Exception ex) { Console.WriteLine("MainEX:"+ex.Message); } Console.WriteLine("按任意键关闭"); Console.ReadKey(); } private static void ConnectCallback(IAsyncResult ar) { try { Socket clientSocket = (Socket)ar.AsyncState; clientSocket.EndConnect(ar); //注释接收 //clientSocket.BeginReceive(receiveBuffer,0,receiveBuffer.Length,0,ReceiveCallback,clientSocket); } catch (SocketException se) { Console.WriteLine("CCBse:"+se.Message); } catch (Exception ex) { Console.WriteLine("CCBex:"+ex.Message); } } private static void ReceiveCallback(IAsyncResult ar) { try { Socket clientSocket = (Socket)ar.AsyncState; int cont = clientSocket.EndReceive(ar); receiveSTR = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, cont); Console.WriteLine(receiveSTR);//* clientSocket.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, ReceiveCallback, clientSocket); } catch (SocketException se) { Console.WriteLine("RCBse:" + se.Message); } catch (Exception ex) { Console.WriteLine("RCBex:"+ex.Message); } } public static void Send(Protocol protocol,string UserSendSTR) //手动调用//约定协议,协议全部大写 { try { string sendData = protocol + "/" + UserSendSTR; sendBuffer = System.Text.Encoding.UTF8.GetBytes(sendData); socket.BeginSend(sendBuffer, 0, sendBuffer.Length, 0, SendCallback, socket); } catch (SocketException se) { Console.WriteLine("SendSE:" + se.Message); } catch (Exception ex) { Console.WriteLine("SendSE:"+ex.Message); } } private static void SendCallback(IAsyncResult ar) { try { Socket socket = (Socket)ar.AsyncState; int cont = socket.EndSend(ar); } catch (SocketException se) { Console.WriteLine("SCBse:" + se.Message); } catch (Exception ex) { Console.WriteLine("SCBex:"+ex.Message); } } } }
步骤三:如果就只是在本机的端口上使用,那么已经完成。如果想两台电脑远程访问,需要结合路由器的端口映射和cpolar创建隧道,进行进行内网穿透。 当你完成端口映射和隧道创建后: 拥有FWDBx02 项目的作服务端,在输入ip是,应该是你的内网ip,即在cmd中ipconfig看到的ip地址。
而CHDAx02项目则是需要发送给客户端,这里输入的ip应该是路由器的公网ip,需要注意端口要统一。
原理:当客户端访问 路由器公网ip:端口 时,因为有端口映射,所以路由器会把该端口的访问转发到映射的内网ip上的端口上,就完成了通信。
代码很粗糙,我知道,这只是我的一个学习记录而已。